commit 3dbff843ac8df3aa167ddf0a52f5869086daa45a Author: Olesya Smirnova Date: Fri Nov 5 20:15:51 2004 +0300 import diff --git a/plugins/InspectionGadgets/Announcement b/plugins/InspectionGadgets/Announcement new file mode 100644 index 000000000000..10630a570127 --- /dev/null +++ b/plugins/InspectionGadgets/Announcement @@ -0,0 +1,371 @@ + +Announcing version 1.0 of the InspectionGadgets plugin, available via the PluginManager +or at http://www.intellij.org/twiki/bin/view/Main/InspectionGadgets. + +Changes in version 1.0 + +New inspections: + +* Use of '$' in identifier +* Infinite Recursion +* Auto-Boxing +* Auto-Unboxing +* Unnecessary boxing +* Unnecessary unboxing +* Class without no-arg constructor +* Unnecessary 'final' for method parameter +* Unnecessarily qualified static method call +* Unqualified static method call +* setUp() with incorrect signature +* tearDown() with incorrect signature +* setUp() doesn't call super.setUp() +* tearDown() doesn't call super.tearDown() +* Test method with incorrect signature +* 'assert' statement +* Use of 'enum' as identifier + +plus huge numbers of bugfixes. + +Special thanks go to Bas Lejsdekkers and Keith Lea for their help and ideas on this release. + +With the 1.0 release, development on InspectionGadgets will be going into "bugfixes-only" +mode for the next several months. Thanks to everyone for your ideas, code, and +criticism as I developed InspectionGadgets. It's thanks to your interest and support +that InspectionGadgets has become the most full-featured and powerful Java static analysis +tool available today, and the most-downloaded IDEA plugin. I hope I've helped you kill a +lot of bugs. + + + + + * Abstraction issues + * Cast to a concrete class + * Class references one of its subclasses + * Collection declared by class, not interface + * Concrete class for instance variable + * Concrete class for local variable + * Concrete class for method parameter + * Concrete class for method return + * Concrete class for static variable + * 'instanceof' a concrete class + * "Magic number" + * 'switch' statement + + * Class metrics + * Class too deep in inheritance tree + * Class with too many constructors + * Class with too many fields + * Class with too many methods + * Inner class too deeply nested + * Overly complex class + * Overly coupled class + + * Class structure + * Abstract class extends concrete class + * Abstract class without abstract methods + * Abstract method overrides abstract method + * Abstract method overrides concrete method + * Class may be interface + * Class without constructor + * Class without no-arg constructor + * Class without package statement + * Constant declared in abstract class + * Constant declared in interface + * constructor not 'protected' in 'abstract' class(*) + * 'final' method in 'final' class(*) + * Inner class of interface + * No-op method in abstract class + * 'private' method declared 'final'(*) + * 'protected' member in 'final' class(*) + * 'public' constructor in non-'public' class(*) + * Static inheritance + * 'static' method declared 'final'(*) + * 'static', non-'final' field + * Utility class + * Utility class with public constructor + * Utility class without private constructor + + * Cloning issues + * clone() doesn't call super.clone() + * clone() doesn't declare CloneNotSupportedException + * clone() instantiates objects with constructor + * Cloneable class without 'clone()' + + * Code maturity issues + * Call to printStackTrace() + * Call to Thread.dumpStack() + * Class without toString() + * Use of obsolete collection type + * Use of System.out or System.err + + * Code style issues + * C-style array declaration(*) + * Constant on left side of comparison(*) + * Constant on right side of comparison(*) + * expression.equals("literal") rather than "literal".equals(expression)(*) + * Missorted modifers(*) + * Multiple variables in one declaration(*) + * Return of 'this' + * Unnecessarily qualified static method call(*) + * Unqualified static method call(*) + * Variables of different types in one declaration(*) + + * Encapsulation issues + * Assignment to Collection or array field from parameter + * Package-visible field + * Package-visible inner class + * Protected field + * Protected inner class + * Public field + * Public inner class + * Return of Collection or array field + + * Error handling + * 'catch' generic class + * Checked exception class + * Empty 'catch' block + * Empty 'finally' block + * Empty 'try' block + * Error not rethrown + * 'instanceof' on 'catch' parameter + * Nested 'try' statement + * Overly broad 'catch' block + * 'return' inside 'finally' block + * ThreadDeath not rethrown + * 'throw' generic class + * 'throw' inside 'catch' block which ignores the caught exception + * 'throw' inside 'finally' block + * Unchecked exception class + + * Finalization issues + * finalize() called explicitly + * finalize() doesn't call super.finalize() + * finalize() not declared 'protected'(*) + * Use of finalize() + + * Imports + * * import + * Import from same package + * java.lang import + * Redundant import + * Single class import + * Unused import + + * Initialization issues + * Abstract method call in constructor + * Instance variable may not be initialized + * Overridable method call in constructor + * Static variable may not be initialized + + * Internationalization issues + * Call to Date.toString() + * Call to Numeric .toString() + * Call to String.compareTo() + * Call to String.equals() + * Call to String.equalsIgnoreCase() + * Call to Time.toString() + * Character comparison + * Hardcoded string literal + * "Magic character" + * String concatenation + * Use of StringTokenizer + + * JUnit issues + * JUnit TestCase with non-trivial constructors + * Missing message on JUnit assertion + * setUp() doesn't call super.setUp() + * setUp() with incorrect signature + * 'setup()' instead of 'setUp()'(*) + * 'suite()' method not declared 'static' + * tearDown() doesn't call super.tearDown() + * tearDown() with incorrect signature + * 'teardown()' instead of 'tearDown()'(*) + * Test method with incorrect signature + + * Method metrics + * Method with more than three negations + * Method with multiple loops + * Method with multiple return points. + * Method with too many parameters + * Overly complex method + * Overly coupled method + * Overly long method + * Overly nested method + + * Naming conventions + * Class name prefixed with package name(*) + * Class naming convention(*) + * Confusing 'main()' method(*) + * Constant naming convention(*) + * Exception class name doesn't end with Exception(*) + * Instance method naming convention(*) + * Instance variable naming convention(*) + * Interface naming convention(*) + * Local Variable naming convention(*) + * Method name same as class name(*) + * Method name same as parent class name(*) + * Method parameter naming convention(*) + * Non-exception class name ends with 'Exception'(*) + * Standard variable names(*) + * Static method naming convention(*) + * Static variable naming convention(*) + * Use of '$' in identifier(*) + + * Performance issues + * Boolean constructor call(*) + * Calls to System.gc() or Runtime.gc() + * Collection without initial capacity + * Field may be 'static'(*) + * Field repeatedly accessed in method + * Manual array copy(*) + * Multiply or divide by power of two(*) + * Object allocation in loop + * Redundant String constructor call(*) + * Redundant String.toString()(*) + * Single character .startsWith() or .endsWith() + * Single character string concatenation(*) + * Static collection + * String concatenation in loop + * StringBuffer without initial capacity + * StringBuffer.toString() in concatenation(*) + * Tail recursion + * Unnecessary temporary object in conversion from String(*) + * Unnecessary temporary object in conversion to String(*) + * Use of java.lang.reflect + * Zero-length array allocation + + * Portability issues + * 'assert' statement + * Auto-boxing(*) + * Auto-unboxing(*) + * Call to Runtime.exec() + * Call to System.exit() + * Call to System.getenv() + * Hardcoded file separator + * Hardcoded line separator + * Native method + * Use of 'assert' as identifier(*) + * Use of 'enum' as identifier(*) + + * Potentially confusing code constructs + * Assignment to for-loop parameter + * Assignment to method parameter + * 'break' statement + * 'break' statement with label + * Chained equality comparisons + * Chained method calls + * Conditional expression (?:) + * Confusing else branch + * Confusing floating-point literal(*) + * 'continue' statement + * 'continue' statement with label + * If statement with negated condition + * Implicit call to super()(*) + * Implicit numeric conversions(*) + * Local variable used and declared in different 'switch' branches + * Long literal ending with 'l' instead of 'L'(*) + * Method names differing only by case + * Nested 'switch' statement + * Nested assignment + * Nested conditional expression + * Nested method calls + * Numeric cast that loses precision + * Overloaded methods with same number of parameters + * Overly complex arithmetic expression + * Overly complex boolean expression + * Switch statement with too few branches + * Switch statement with too many branches + * Value of ++ or -- used + + * Probable bugs + * Assignment to 'null' + * Assignment used as condition + * 'compareto()' instead of 'compareTo()'(*) + * Comparison of short and char values + * Covariant compareTo() + * Covariant equals() + * 'default' not last case in 'switch' + * equals() between objects of inconvertible types + * Fallthrough in 'switch' statement + * Floating point equality comparison + * For loop where update or condition doesn't use loop variable + * For loop with missing components + * 'hashcode()' instead of 'hashCode()'(*) + * Infinite loop statement + * Infinite recursion + * Loop statement that doesn't loop + * Non-final field referenced in 'compareTo()' + * Non-final field referenced in 'equals()' + * Non-final field referenced in 'hashCode()' + * Object comparison using ==, instead of '.equals()'(*) + * Octal and decimal integers in same array + * Result of InputStream.read() ignored + * Return of 'null' + * Statement with empty body + * String comparison using ==, instead of '.equals()'(*) + * Subtraction in compareTo() + * 'switch' statement without 'default' branch + * Text label in 'switch' statement + + * Security issues + * Cloneable class in secure context + * Deserializable class in secure context + * Non-static inner class in secure context + * Serializable class in secure context + + * Serialization issues + * Instance variable may not be initialized by readObject + * Non-serializable class with 'readObject()' or 'writeObject()' + * Non-serializable class with serialVersionUID + * 'readObject()' or 'writeObject()' not declared 'private'(*) + * 'readResolve()' or 'writeReplace()' not declared 'protected'(*) + * Serializable class with unconstructable ancestor + * Serializable class without 'readObject()' and 'writeObject()' + * Serializable class without serialVersionUID + * 'serialVersionUID' field not declared 'static final'(*) + * Transient field in non-serializable class(*) + + * Threading issues + * Busy wait + * Call to notify() instead of notifyAll()(*) + * Call to Thread.run()(*) + * Double-checked locking + * Empty 'synchronized' statement + * Field accessed in both synchronized and unsynchronized contexts + * Nested 'synchronized' statement + * Non-private field accessed in synchronized context + * Non-synchronized method overrides synchronized method + * Synchronization on 'this' + * Synchronization on a non-final field + * 'synchronized' method + * 'wait()' not in loop + + * Verbose or redundant code constructs + * Assignment replacable with operator assignment(*) + * Class explicitly extends java.lang.Object + * 'for' loop may be replaced by 'while' loop(*) + * Pointless arithmetic expression(*) + * Redundant boolean comparison(*) + * Redundant field initialization(*) + * Unnecessary 'final' for method parameter(*) + * Unnecessary 'if' statement(*) + * Unnecessary 'return' statement(*) + * Unnecessary 'super()' statement(*) + * Unnecessary 'this' qualifier(*) + * Unnecessary boxing(*) + * Unnecessary code block(*) + * Unnecessary fully qualified name(*) + * Unnecessary interface modifier(*) + * Unnecessary parentheses(*) + * Unnecessary semicolon(*) + * Unnecessary unboxing(*) + * Unused label(*) + + * Visibility issues + * Field name hides field in superclass(*) + * Inner class field hides outer class field(*) + * Local variable hides member variable(*) + * Method overloads method of superclass(*) + * Method overrides private method of superclass(*) + * Method overrides static method of superclass(*) + * Parameter hides member variable(*) \ No newline at end of file diff --git a/plugins/InspectionGadgets/InspectionGadgets.iml b/plugins/InspectionGadgets/InspectionGadgets.iml new file mode 100644 index 000000000000..42c4b537feb0 --- /dev/null +++ b/plugins/InspectionGadgets/InspectionGadgets.iml @@ -0,0 +1,52 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/InspectionGadgets/InspectionGadgets.ipr b/plugins/InspectionGadgets/InspectionGadgets.ipr new file mode 100644 index 000000000000..082f546d68d6 --- /dev/null +++ b/plugins/InspectionGadgets/InspectionGadgets.ipr @@ -0,0 +1,221 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/InspectionGadgets/InspectionGadgets.iws b/plugins/InspectionGadgets/InspectionGadgets.iws new file mode 100644 index 000000000000..f0d19d1d7ef6 --- /dev/null +++ b/plugins/InspectionGadgets/InspectionGadgets.iws @@ -0,0 +1,717 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/InspectionGadgets/InspectionGadgetsPlugin.iml b/plugins/InspectionGadgets/InspectionGadgetsPlugin.iml new file mode 100644 index 000000000000..2f25e7bf5cfc --- /dev/null +++ b/plugins/InspectionGadgets/InspectionGadgetsPlugin.iml @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/InspectionGadgets/META-INF/plugin.xml b/plugins/InspectionGadgets/META-INF/plugin.xml new file mode 100644 index 000000000000..d17c3cde9026 --- /dev/null +++ b/plugins/InspectionGadgets/META-INF/plugin.xml @@ -0,0 +1,26 @@ + + Inspection Gadgets + inspection + Over 320 new automated code inspections for IDEA + InspectionGadgets Software + 1.0 + + + + + com.siyeh.ig.InspectionGadgetsPlugin + + + + + + + + + + + + + \ No newline at end of file diff --git a/plugins/InspectionGadgets/build.xml b/plugins/InspectionGadgets/build.xml new file mode 100644 index 000000000000..96349a2c5a0f --- /dev/null +++ b/plugins/InspectionGadgets/build.xml @@ -0,0 +1,76 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/BaseInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/BaseInspection.java new file mode 100644 index 000000000000..b6d8808f1fb1 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/BaseInspection.java @@ -0,0 +1,55 @@ +package com.siyeh.ig; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.codeInspection.LocalInspectionTool; +import com.intellij.psi.PsiElement; + +import java.lang.reflect.Method; + +public abstract class BaseInspection extends LocalInspectionTool { + private final String m_shortName = null; + + public String getShortName() { + if (m_shortName == null) { + final Class aClass = getClass(); + final String name = aClass.getName(); + return name.substring(name.lastIndexOf((int) '.') + 1, name.length() - "Inspection".length()); + } + return m_shortName; + } + + protected abstract BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly); + + protected String buildErrorString(PsiElement location) { + return null; + } + + protected String buildErrorString(Object arg) { + return null; + } + + + protected boolean buildQuickFixesOnlyForOnTheFlyErrors() { + return false; + } + + protected boolean buildQuickFixesOnlyForBatchErrors() { + return false; + } + + protected InspectionGadgetsFix buildFix(PsiElement location) { + return null; + } + + public boolean hasQuickFix() { + final Method[] methods = getClass().getDeclaredMethods(); + for (int i = 0; i < methods.length; i++) { + final Method method = methods[i]; + final String methodName = method.getName(); + if ("buildFix".equals(methodName)) { + return true; + } + } + return false; + } +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/BaseInspectionVisitor.java b/plugins/InspectionGadgets/src/com/siyeh/ig/BaseInspectionVisitor.java new file mode 100644 index 000000000000..2168c89b867e --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/BaseInspectionVisitor.java @@ -0,0 +1,140 @@ +package com.siyeh.ig; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.codeInspection.LocalQuickFix; +import com.intellij.codeInspection.ProblemDescriptor; +import com.intellij.codeInspection.ProblemHighlightType; +import com.intellij.psi.*; + +import java.util.ArrayList; +import java.util.List; + +public abstract class BaseInspectionVisitor extends PsiRecursiveElementVisitor { + private final BaseInspection m_inspection; + private final InspectionManager m_inspectionManager; + private final boolean m_onTheFly; + private List m_errors = null; + + protected BaseInspectionVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean onTheFly) { + super(); + m_inspection = inspection; + m_inspectionManager = inspectionManager; + m_onTheFly = onTheFly; + } + + public void visitReferenceExpression(PsiReferenceExpression expression) { + final PsiExpression qualifier = expression.getQualifierExpression(); + if (qualifier != null) { + qualifier.accept(this); + } + final PsiReferenceParameterList typeParameters = expression.getParameterList(); + if (typeParameters != null) { + typeParameters.accept(this); + } + } + + protected void registerMethodCallError(PsiMethodCallExpression expression) { + final PsiReferenceExpression methodExpression = expression.getMethodExpression(); + final PsiElement nameToken = methodExpression.getReferenceNameElement(); + registerError(nameToken); + } + + protected void registerStatementError(PsiStatement statement) { + final PsiElement statementToken = statement.getFirstChild(); + registerError(statementToken); + } + + protected void registerClassError(PsiClass aClass) { + final PsiElement nameIdentifier = aClass.getNameIdentifier(); + registerError(nameIdentifier); + } + + protected void registerMethodError(PsiMethod method) { + final PsiElement nameIdentifier = method.getNameIdentifier(); + registerError(nameIdentifier); + } + + protected void registerVariableError(PsiVariable variable) { + final PsiElement nameIdentifier = variable.getNameIdentifier(); + registerError(nameIdentifier); + } + + protected void registerTypeParameterError(PsiTypeParameter param) { + final PsiElement nameIdentifier = param.getNameIdentifier(); + registerError(nameIdentifier); + } + + protected void registerFieldError(PsiField field) { + final PsiElement nameIdentifier = field.getNameIdentifier(); + registerError(nameIdentifier); + } + + protected void registerModifierError(String modifier, PsiModifierListOwner parameter) { + final PsiModifierList modifiers = parameter.getModifierList(); + if (modifiers == null) { + return; + } + final PsiElement[] children = modifiers.getChildren(); + for (int i = 0; i < children.length; i++) { + final PsiElement child = children[i]; + final String text = child.getText(); + if (modifier.equals(text)) { + registerError(child); + } + } + } + + protected void registerError(PsiElement location) { + if (location == null) { + return; + } + final LocalQuickFix fix; + if (!m_onTheFly && m_inspection.buildQuickFixesOnlyForOnTheFlyErrors()) { + fix = null; + } else if (m_onTheFly && m_inspection.buildQuickFixesOnlyForBatchErrors()) { + fix = null; + } else { + fix = m_inspection.buildFix(location); + } + final String description = m_inspection.buildErrorString(location); + final ProblemDescriptor problem + = m_inspectionManager.createProblemDescriptor(location, description, fix, + ProblemHighlightType.GENERIC_ERROR_OR_WARNING); + addError(problem); + } + + private void addError(ProblemDescriptor problem) { + if (m_errors == null) { + m_errors = new ArrayList(5); + } + m_errors.add(problem); + } + + protected void registerError(PsiElement location, Object arg) { + final LocalQuickFix fix; + if (!m_onTheFly && m_inspection.buildQuickFixesOnlyForOnTheFlyErrors()) { + fix = null; + } else if (m_onTheFly && m_inspection.buildQuickFixesOnlyForBatchErrors()) { + fix = null; + } else { + fix = m_inspection.buildFix(location); + } + final String description = m_inspection.buildErrorString(arg); + final ProblemDescriptor problem + = m_inspectionManager.createProblemDescriptor(location, description, fix, + ProblemHighlightType.GENERIC_ERROR_OR_WARNING); + addError(problem); + } + + + public ProblemDescriptor[] getErrors() { + final List errors = m_errors; + if (errors == null) { + return null; + } else { + final int numErrors = errors.size(); + return (ProblemDescriptor[]) errors.toArray(new ProblemDescriptor[numErrors]); + } + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/InspectionComparator.java b/plugins/InspectionGadgets/src/com/siyeh/ig/InspectionComparator.java new file mode 100644 index 000000000000..fa0569a1dd32 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/InspectionComparator.java @@ -0,0 +1,49 @@ +package com.siyeh.ig; + +import com.intellij.codeInspection.LocalInspectionTool; + +import java.util.Comparator; + +class InspectionComparator implements Comparator { + InspectionComparator() { + super(); + } + + public int compare(Object o1, Object o2) { + final Class class1 = (Class) o1; + final Class class2 = (Class) o2; + final LocalInspectionTool inspection1; + final LocalInspectionTool inspection2; + try { + inspection1 = (LocalInspectionTool) class1.newInstance(); + inspection2 = (LocalInspectionTool) class2.newInstance(); + } catch (InstantiationException e) { + return -1; + } catch (IllegalAccessException e) { + return -1; + } + final String groupName1 = inspection1.getGroupDisplayName(); + final String groupName2 = inspection2.getGroupDisplayName(); + final int groupNameComparison = groupName1.compareTo(groupName2); + if (groupNameComparison != 0) { + return groupNameComparison; + } + String displayName1 = inspection1.getDisplayName(); + String displayName2 = inspection2.getDisplayName(); + displayName1 = displayName1.toUpperCase(); + displayName2 = displayName2.toUpperCase(); + displayName1 = stripLeadingNonCharacters(displayName1); + displayName2 = stripLeadingNonCharacters(displayName2); + return displayName1.compareTo(displayName2); + } + + private static String stripLeadingNonCharacters(String str) { + for (int i = 0; i < str.length(); i++) { + final char ch = str.charAt(i); + if (Character.isLetter(ch)) { + return str.substring(i); + } + } + return str; + } +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/InspectionGadgetsFix.java b/plugins/InspectionGadgets/src/com/siyeh/ig/InspectionGadgetsFix.java new file mode 100644 index 000000000000..f49a8f59fd9c --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/InspectionGadgetsFix.java @@ -0,0 +1,53 @@ +package com.siyeh.ig; + +import com.intellij.codeInspection.LocalQuickFix; +import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.project.Project; +import com.intellij.psi.*; +import com.intellij.psi.codeStyle.CodeStyleManager; +import com.intellij.util.IncorrectOperationException; + +public abstract class InspectionGadgetsFix implements LocalQuickFix { + protected void deleteElement(PsiElement element) { + try { + element.delete(); + } catch (IncorrectOperationException e) { + final Class aClass = getClass(); + final String className = aClass.getName(); + final Logger logger = Logger.getInstance(className); + logger.error(e); + } + } + + protected void replaceExpression(Project project, PsiExpression expression, String newExpression) { + try { + final PsiManager psiManager = PsiManager.getInstance(project); + final PsiElementFactory factory = psiManager.getElementFactory(); + final PsiExpression newExp = factory.createExpressionFromText(newExpression, null); + final PsiElement replacementExp = expression.replace(newExp); + final CodeStyleManager styleManager = psiManager.getCodeStyleManager(); + styleManager.reformat(replacementExp); + } catch (IncorrectOperationException e) { + final Class aClass = getClass(); + final String className = aClass.getName(); + final Logger logger = Logger.getInstance(className); + logger.error(e); + } + } + + protected void replaceStatement(Project project, PsiStatement statement, String newStatement) { + try { + final PsiManager psiManager = PsiManager.getInstance(project); + final PsiElementFactory factory = psiManager.getElementFactory(); + final PsiStatement newExp = factory.createStatementFromText(newStatement, null); + final PsiElement replacementExp = statement.replace(newExp); + final CodeStyleManager styleManager = psiManager.getCodeStyleManager(); + styleManager.reformat(replacementExp); + } catch (IncorrectOperationException e) { + final Class aClass = getClass(); + final String className = aClass.getName(); + final Logger logger = Logger.getInstance(className); + logger.error(e); + } + } +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/InspectionGadgetsPlugin.java b/plugins/InspectionGadgets/src/com/siyeh/ig/InspectionGadgetsPlugin.java new file mode 100644 index 000000000000..844e4f933836 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/InspectionGadgetsPlugin.java @@ -0,0 +1,699 @@ +package com.siyeh.ig; + +import com.intellij.codeInspection.InspectionToolProvider; +import com.intellij.codeInspection.LocalInspectionTool; +import com.intellij.openapi.application.Application; +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.components.ApplicationComponent; +import com.intellij.openapi.util.InvalidDataException; +import com.intellij.openapi.util.JDOMExternalizable; +import com.intellij.openapi.util.WriteExternalException; +import com.siyeh.ig.abstraction.*; +import com.siyeh.ig.bugs.*; +import com.siyeh.ig.classlayout.*; +import com.siyeh.ig.classmetrics.*; +import com.siyeh.ig.cloneable.CloneCallsConstructorsInspection; +import com.siyeh.ig.cloneable.CloneCallsSuperCloneInspection; +import com.siyeh.ig.cloneable.CloneDeclaresCloneNotSupportedInspection; +import com.siyeh.ig.cloneable.CloneableImplementsCloneInspection; +import com.siyeh.ig.confusing.*; +import com.siyeh.ig.encapsulation.*; +import com.siyeh.ig.errorhandling.*; +import com.siyeh.ig.finalization.FinalizeCallsSuperFinalizeInspection; +import com.siyeh.ig.finalization.FinalizeInspection; +import com.siyeh.ig.finalization.FinalizeNotProtectedInspection; +import com.siyeh.ig.finalization.NoExplicitFinalizeCallsInspection; +import com.siyeh.ig.imports.*; +import com.siyeh.ig.initialization.*; +import com.siyeh.ig.internationalization.*; +import com.siyeh.ig.junit.*; +import com.siyeh.ig.logging.ClassWithoutLoggerInspection; +import com.siyeh.ig.logging.ClassWithMultipleLoggersInspection; +import com.siyeh.ig.logging.NonStaticFinalLoggerInspection; +import com.siyeh.ig.maturity.*; +import com.siyeh.ig.methodmetrics.*; +import com.siyeh.ig.naming.*; +import com.siyeh.ig.performance.*; +import com.siyeh.ig.portability.*; +import com.siyeh.ig.security.CloneableClassInSecureContextInspection; +import com.siyeh.ig.security.DeserializableClassInSecureContextInspection; +import com.siyeh.ig.security.NonStaticInnerClassInSecureContextInspection; +import com.siyeh.ig.security.SerializableClassInSecureContextInspection; +import com.siyeh.ig.serialization.*; +import com.siyeh.ig.style.*; +import com.siyeh.ig.threading.*; +import com.siyeh.ig.verbose.*; +import com.siyeh.ig.visibility.*; +import org.jdom.Element; + +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.OutputStream; +import java.io.PrintStream; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +public class InspectionGadgetsPlugin implements ApplicationComponent, + InspectionToolProvider, JDOMExternalizable { + private static final int NUM_INSPECTIONS = 360; + private final List m_inspectionClasses = new ArrayList(NUM_INSPECTIONS); + + private final InspectionGadgetsConfig m_config = new InspectionGadgetsConfig(); + + public static void main(String[] args) { + final InspectionGadgetsPlugin plugin = new InspectionGadgetsPlugin(); + final PrintStream out; + if (args.length == 0) { + out = System.out; + } else { + final OutputStream stream; + try { + stream = new FileOutputStream(args[0]); + } catch (final FileNotFoundException e) { + return; + } + out = new PrintStream(stream); + } + plugin.createDocumentation(out); + } + + private void createDocumentation(PrintStream out) { + initComponent(); + final Class[] classes = getInspectionClasses(); + String currentGroupName = ""; + + final int numQuickFixes = countQuickFixes(classes, out); + out.println(classes.length + " Inspections"); + out.println(numQuickFixes + " Quick Fixes"); + + for (int i = 0; i < classes.length; i++) { + final Class aClass = classes[i]; + final String className = aClass.getName(); + try { + final LocalInspectionTool inspection = (LocalInspectionTool) aClass.newInstance(); + final String groupDisplayName = inspection.getGroupDisplayName(); + if (!groupDisplayName.equals(currentGroupName)) { + currentGroupName = groupDisplayName; + out.println(); + out.print(" * "); + out.println(currentGroupName); + } + printInspectionDescription(inspection, out); + + } catch (InstantiationException e) { + out.print("Couldn't instantiate "); + out.println(className); + } catch (IllegalAccessException e) { + out.print("Couldn't access "); + out.println(className); + } catch (ClassCastException e) { + out.print("Couldn't cast "); + out.println(className); + } + } + } + + private static void printInspectionDescription(LocalInspectionTool inspection, PrintStream out) { + final boolean hasQuickFix = ((BaseInspection) inspection).hasQuickFix(); + + final String displayName = inspection.getDisplayName(); + if (hasQuickFix) { + out.print(" * "); + out.print(displayName); + out.println("(*)"); + } else { + out.print(" * "); + out.println(displayName); + } + } + + private static int countQuickFixes(Class[] classes, PrintStream out) { + int numQuickFixes = 0; + for (int i = 0; i < classes.length; i++) { + final Class aClass = classes[i]; + final String className = aClass.getName(); + try { + final LocalInspectionTool inspection = (LocalInspectionTool) aClass.newInstance(); + if (inspection instanceof BaseInspection) { + if (((BaseInspection) inspection).hasQuickFix()) { + numQuickFixes++; + } + } + + } catch (InstantiationException e) { + out.print("Couldn't instantiate "); + out.println(className); + } catch (IllegalAccessException e) { + out.print("Couldn't access "); + out.println(className); + } catch (ClassCastException e) { + out.print("Couldn't cast "); + out.println(className); + } + } + return numQuickFixes; + } + + public static InspectionGadgetsPlugin getInstance() { + final Application application = ApplicationManager.getApplication(); + return (InspectionGadgetsPlugin) application.getComponent(InspectionGadgetsPlugin.class); + } + + public String getComponentName() { + return "InspectionGadgets"; + } + + public Class[] getInspectionClasses() { + final int numInspections = m_inspectionClasses.size(); + return (Class[]) m_inspectionClasses.toArray(new Class[numInspections]); + } + + public void initComponent() { + registerNamingInspections(); + registerBugInspections(); + registerCloneInspection(); + registerConfusingInspections(); + registerAbstractionInspections(); + registerClassLayoutInspections(); + registerImportInspections(); + registerEncapsulationInspections(); + registerVisibilityInspections(); + registerInitializerInspections(); + registerFinalizationInspections(); + registerExceptionInspections(); + registerVerboseInspections(); + registerStyleInspections(); + registerSerializationInspections(); + registerThreadingInspections(); + registerMethodMetricsInspections(); + registerClassMetricsInspections(); + registerPortabilityInspections(); + registerInternationalInspections(); + registerPerformanceInspections(); + registerMaturityInspections(); + registerJUnitInspections(); + registerLoggingInspections(); + registerSecurityInspections(); + Collections.sort(m_inspectionClasses, new InspectionComparator()); + } + + private void registerLoggingInspections() { + final List inspectionClasses = m_inspectionClasses; + inspectionClasses.add(ClassWithoutLoggerInspection.class); + inspectionClasses.add(ClassWithMultipleLoggersInspection.class); + inspectionClasses.add(NonStaticFinalLoggerInspection.class); + } + + private void registerSecurityInspections() { + final List inspectionClasses = m_inspectionClasses; + inspectionClasses.add(DeserializableClassInSecureContextInspection.class); + inspectionClasses.add(SerializableClassInSecureContextInspection.class); + inspectionClasses.add(CloneableClassInSecureContextInspection.class); + inspectionClasses.add(NonStaticInnerClassInSecureContextInspection.class); + } + + private void registerImportInspections() { + final List inspectionClasses = m_inspectionClasses; + inspectionClasses.add(UnusedImportInspection.class); + inspectionClasses.add(RedundantImportInspection.class); + inspectionClasses.add(OnDemandImportInspection.class); + inspectionClasses.add(SingleClassImportInspection.class); + inspectionClasses.add(JavaLangImportInspection.class); + inspectionClasses.add(SamePackageImportInspection.class); + inspectionClasses.add(StaticImportInspection.class); + } + + private void registerNamingInspections() { + final List inspectionClasses = m_inspectionClasses; + inspectionClasses.add(ClassNamingConventionInspection.class); + inspectionClasses.add(InterfaceNamingConventionInspection.class); + inspectionClasses.add(InstanceVariableNamingConventionInspection.class); + inspectionClasses.add(StaticVariableNamingConventionInspection.class); + inspectionClasses.add(ConstantNamingConventionInspection.class); + inspectionClasses.add(InstanceMethodNamingConventionInspection.class); + inspectionClasses.add(StaticMethodNamingConventionInspection.class); + inspectionClasses.add(LocalVariableNamingConventionInspection.class); + inspectionClasses.add(ParameterNamingConventionInspection.class); + inspectionClasses.add(ExceptionNameDoesntEndWithExceptionInspection.class); + inspectionClasses.add(NonExceptionNameEndsWithExceptionInspection.class); + inspectionClasses.add(ClassNamePrefixedWithPackageNameInspection.class); + inspectionClasses.add(ClassNameSameAsAncestorNameInspection.class); + inspectionClasses.add(MethodNameSameAsClassNameInspection.class); + inspectionClasses.add(MethodNameSameAsParentNameInspection.class); + inspectionClasses.add(StandardVariableNamesInspection.class); + inspectionClasses.add(ConfusingMainMethodInspection.class); + inspectionClasses.add(UpperCaseFieldNameNotConstantInspection.class); + inspectionClasses.add(DollarSignInNameInspection.class); + } + + private void registerBugInspections() { + final List inspectionClasses = m_inspectionClasses; + //inspectionClasses.add(StreamOpenCloseInspection.class); + inspectionClasses.add(IntegerDivisionInFloatingPointContextInspection.class); + inspectionClasses.add(NonShortCircuitBooleanInspection.class); + inspectionClasses.add(ComparisonOfShortAndCharInspection.class); + inspectionClasses.add(AssignmentUsedAsConditionInspection.class); + inspectionClasses.add(EmptyStatementBodyInspection.class); + inspectionClasses.add(EmptyInitializerInspection.class); + inspectionClasses.add(EqualsBetweenInconvertibleTypesInspection.class); + inspectionClasses.add(BigDecimalEqualsInspection.class); + inspectionClasses.add(CovariantCompareToInspection.class); + inspectionClasses.add(CovariantEqualsInspection.class); + inspectionClasses.add(FloatingPointEqualityInspection.class); + inspectionClasses.add(MisspelledCompareToInspection.class); + inspectionClasses.add(MisspelledHashcodeInspection.class); + inspectionClasses.add(MisspelledEqualsInspection.class); + inspectionClasses.add(MisspelledToStringInspection.class); + inspectionClasses.add(FallthruInSwitchStatementInspection.class); + inspectionClasses.add(SwitchStatementsWithoutDefaultInspection.class); + inspectionClasses.add(DefaultNotLastCaseInSwitchInspection.class); + inspectionClasses.add(ObjectEqualityInspection.class); + inspectionClasses.add(ObjectEqualsNullInspection.class); + inspectionClasses.add(StringEqualityInspection.class); + inspectionClasses.add(IgnoreResultOfCallInspection.class); + inspectionClasses.add(ResultOfObjectAllocationIgnoredInspection.class); + inspectionClasses.add(ResultSetIndexZeroInspection.class); + inspectionClasses.add(LoopStatementsThatDontLoopInspection.class); + inspectionClasses.add(MismatchedArrayReadWriteInspection.class); + inspectionClasses.add(MismatchedCollectionQueryUpdateInspection.class); + inspectionClasses.add(TextLabelInSwitchStatementInspection.class); + inspectionClasses.add(AssignmentToNullInspection.class); + inspectionClasses.add(ReturnNullInspection.class); + inspectionClasses.add(OctalAndDecimalIntegersMixedInspection.class); + inspectionClasses.add(IncompatibleMaskInspection.class); + inspectionClasses.add(ForLoopWithMissingComponentInspection.class); + inspectionClasses.add(ForLoopThatDoesntUseLoopVariableInspection.class); + inspectionClasses.add(InfiniteLoopStatementInspection.class); + inspectionClasses.add(InfiniteRecursionInspection.class); + inspectionClasses.add(SubtractionInCompareToInspection.class); + inspectionClasses.add(EqualsUsesNonFinalVariableInspection.class); + inspectionClasses.add(HashCodeUsesNonFinalVariableInspection.class); + inspectionClasses.add(CompareToUsesNonFinalVariableInspection.class); + } + + private void registerAbstractionInspections() { + final List inspectionClasses = m_inspectionClasses; + inspectionClasses.add(DuplicateStringLiteralInspection.class); + inspectionClasses.add(FeatureEnvyInspection.class); + inspectionClasses.add(LocalVariableOfConcreteClassInspection.class); + inspectionClasses.add(RawUseOfParameterizedTypeInspection.class); + inspectionClasses.add(InstanceVariableOfConcreteClassInspection.class); + inspectionClasses.add(StaticVariableOfConcreteClassInspection.class); + inspectionClasses.add(ParameterOfConcreteClassInspection.class); + inspectionClasses.add(MethodReturnOfConcreteClassInspection.class); + inspectionClasses.add(InstanceofInterfacesInspection.class); + inspectionClasses.add(CastToConcreteClassInspection.class); + inspectionClasses.add(OverlyStrongTypeCastInspection.class); + inspectionClasses.add(DeclareCollectionAsInterfaceInspection.class); + inspectionClasses.add(MagicNumberInspection.class); + inspectionClasses.add(ClassReferencesSubclassInspection.class); + inspectionClasses.add(SwitchStatementInspection.class); + inspectionClasses.add(PublicMethodNotExposedInInterfaceInspection.class); + inspectionClasses.add(InstanceofThisInspection.class); + } + + private void registerClassLayoutInspections() { + final List inspectionClasses = m_inspectionClasses; + inspectionClasses.add(FinalClassInspection.class); + inspectionClasses.add(EmptyClassInspection.class); + inspectionClasses.add(AnonymousInnerClassInspection.class); + inspectionClasses.add(LimitedScopeInnerClassInspection.class); + inspectionClasses.add(FinalMethodInspection.class); + inspectionClasses.add(ClassInitializerInspection.class); + inspectionClasses.add(ClassMayBeInterfaceInspection.class); + inspectionClasses.add(NonProtectedConstructorInAbstractClassInspection.class); + inspectionClasses.add(ClassWithoutConstructorInspection.class); + inspectionClasses.add(AbstractClassWithoutAbstractMethodsInspection.class); + inspectionClasses.add(FinalMethodInFinalClassInspection.class); + inspectionClasses.add(ProtectedMemberInFinalClassInspection.class); + inspectionClasses.add(PublicConstructorInNonPublicClassInspection.class); + inspectionClasses.add(UtilityClassWithPublicConstructorInspection.class); + inspectionClasses.add(UtilityClassWithoutPrivateConstructorInspection.class); + inspectionClasses.add(AbstractMethodOverridesConcreteMethodInspection.class); + inspectionClasses.add(AbstractMethodOverridesAbstractMethodInspection.class); + inspectionClasses.add(AbstractClassExtendsConcreteClassInspection.class); + inspectionClasses.add(StaticNonFinalFieldInspection.class); + inspectionClasses.add(ConstantDeclaredInAbstractClassInspection.class); + inspectionClasses.add(ConstantDeclaredInInterfaceInspection.class); + inspectionClasses.add(StaticInheritanceInspection.class); + inspectionClasses.add(ClassInTopLevelPackageInspection.class); + inspectionClasses.add(UtilityClassInspection.class); + inspectionClasses.add(SingletonInspection.class); + inspectionClasses.add(InnerClassOnInterfaceInspection.class); + inspectionClasses.add(FinalPrivateMethodInspection.class); + inspectionClasses.add(NoopMethodInAbstractClassInspection.class); + inspectionClasses.add(FinalStaticMethodInspection.class); + inspectionClasses.add(ClassWithoutNoArgConstructorInspection.class); + inspectionClasses.add(MultipleTopLevelClassesInFileInspection.class); + inspectionClasses.add(ClassNameDiffersFromFileNameInspection.class); + inspectionClasses.add(MarkerInterfaceInspection.class); + } + + private void registerCloneInspection() { + m_inspectionClasses.add(CloneableImplementsCloneInspection.class); + m_inspectionClasses.add(CloneCallsConstructorsInspection.class); + m_inspectionClasses.add(CloneCallsSuperCloneInspection.class); + m_inspectionClasses.add(CloneDeclaresCloneNotSupportedInspection.class); + + } + + private void registerVisibilityInspections() { + final List inspectionClasses = m_inspectionClasses; + inspectionClasses.add(FieldHidesSuperclassFieldInspection.class); + inspectionClasses.add(InnerClassVariableHidesOuterClassVariableInspection.class); + inspectionClasses.add(ParameterHidingMemberVariableInspection.class); + inspectionClasses.add(LocalVariableHidingMemberVariableInspection.class); + inspectionClasses.add(MethodOverridesPrivateMethodInspection.class); + inspectionClasses.add(MethodOverridesStaticMethodInspection.class); + inspectionClasses.add(MethodOverloadsParentMethodInspection.class); + } + + private void registerEncapsulationInspections() { + final List inspectionClasses = m_inspectionClasses; + inspectionClasses.add(PublicFieldInspection.class); + inspectionClasses.add(PackageVisibleFieldInspection.class); + inspectionClasses.add(ProtectedFieldInspection.class); + inspectionClasses.add(PublicInnerClassInspection.class); + inspectionClasses.add(PackageVisibleInnerClassInspection.class); + inspectionClasses.add(ProtectedInnerClassInspection.class); + inspectionClasses.add(ReturnOfCollectionFieldInspection.class); + inspectionClasses.add(ReturnOfDateFieldInspection.class); + inspectionClasses.add(AssignmentToCollectionFieldFromParameterInspection.class); + inspectionClasses.add(AssignmentToDateFieldFromParameterInspection.class); + } + + private void registerInitializerInspections() { + final List inspectionClasses = m_inspectionClasses; + inspectionClasses.add(StaticVariableInitializationInspection.class); + inspectionClasses.add(InstanceVariableInitializationInspection.class); + inspectionClasses.add(AbstractMethodCallInConstructorInspection.class); + inspectionClasses.add(OverridableMethodCallInConstructorInspection.class); + inspectionClasses.add(ThisEscapedInConstructorInspection.class); + inspectionClasses.add(StaticVariableUninitializedUseInspection.class); + inspectionClasses.add(InstanceVariableUninitializedUseInspection.class); + } + + private void registerConfusingInspections() { + final List inspectionClasses = m_inspectionClasses; + inspectionClasses.add(ClassEscapesItsScopeInspection.class); + inspectionClasses.add(ConfusingFloatingPointLiteralInspection.class); + inspectionClasses.add(OverlyComplexArithmeticExpressionInspection.class); + inspectionClasses.add(OverlyComplexBooleanExpressionInspection.class); + inspectionClasses.add(AssignmentToMethodParameterInspection.class); + inspectionClasses.add(AssignmentToCatchBlockParameterInspection.class); + inspectionClasses.add(AssignmentToForLoopParameterInspection.class); + inspectionClasses.add(NestedAssignmentInspection.class); + inspectionClasses.add(BreakStatementInspection.class); + inspectionClasses.add(BreakStatementWithLabelInspection.class); + inspectionClasses.add(ContinueStatementInspection.class); + inspectionClasses.add(ContinueStatementWithLabelInspection.class); + inspectionClasses.add(ConditionalExpressionInspection.class); + inspectionClasses.add(NestedConditionalExpressionInspection.class); + inspectionClasses.add(LongLiteralsEndingWithLowercaseLInspection.class); + inspectionClasses.add(IncrementDecrementUsedAsExpressionInspection.class); + inspectionClasses.add(IfStatementWithTooManyBranchesInspection.class); + inspectionClasses.add(SwitchStatementWithTooManyBranchesInspection.class); + inspectionClasses.add(SwitchStatementWithTooFewBranchesInspection.class); + inspectionClasses.add(SwitchStatementDensityInspection.class); + inspectionClasses.add(NestedSwitchStatementInspection.class); + inspectionClasses.add(ChainedMethodCallInspection.class); + inspectionClasses.add(NestedMethodCallInspection.class); + inspectionClasses.add(OctalLiteralInspection.class); + inspectionClasses.add(ChainedEqualityInspection.class); + inspectionClasses.add(ConfusingOctalEscapeInspection.class); + inspectionClasses.add(MethodNamesDifferOnlyByCaseInspection.class); + inspectionClasses.add(OverloadedMethodsWithSameNumberOfParametersInspection.class); + inspectionClasses.add(ImplicitNumericConversionInspection.class); + inspectionClasses.add(ImplicitCallToSuperInspection.class); + inspectionClasses.add(RefusedBequestInspection.class); + inspectionClasses.add(CastThatLosesPrecisionInspection.class); + inspectionClasses.add(NegatedIfElseInspection.class); + inspectionClasses.add(NegatedConditionalInspection.class); + inspectionClasses.add(ConfusingElseInspection.class); + inspectionClasses.add(SwitchStatementWithConfusingDeclarationInspection.class); + } + + private void registerVerboseInspections() { + final List inspectionClasses = m_inspectionClasses; + inspectionClasses.add(UnnecessaryLabelOnBreakStatementInspection.class); + inspectionClasses.add(UnnecessaryLabelOnContinueStatementInspection.class); + inspectionClasses.add(PointlessBooleanExpressionInspection.class); + inspectionClasses.add(ReplaceAssignmentWithOperatorAssignmentInspection.class); + inspectionClasses.add(TrivialIfInspection.class); + inspectionClasses.add(UnnecessaryConditionalExpressionInspection.class); + inspectionClasses.add(UnnecessaryParenthesesInspection.class); + inspectionClasses.add(UnnecessaryThisInspection.class); + inspectionClasses.add(UnnecessaryBlockStatementInspection.class); + inspectionClasses.add(UnnecessaryInterfaceModifierInspection.class); + inspectionClasses.add(UnnecessaryReturnInspection.class); + inspectionClasses.add(UnnecessaryContinueInspection.class); + inspectionClasses.add(UnnecessarySemicolonInspection.class); + inspectionClasses.add(UnnecessaryFullyQualifiedNameInspection.class); + inspectionClasses.add(UnnecessaryQualifierForThisInspection.class); + inspectionClasses.add(UnusedLabelInspection.class); + inspectionClasses.add(RedundantFieldInitializationInspection.class); + inspectionClasses.add(RedundantImplementsInspection.class); + inspectionClasses.add(ExtendsObjectInspection.class); + inspectionClasses.add(TypeParameterExtendsObjectInspection.class); + inspectionClasses.add(PointlessArithmeticExpressionInspection.class); + inspectionClasses.add(PointlessBitwiseExpressionInspection.class); + inspectionClasses.add(UnnecessarySuperConstructorInspection.class); + inspectionClasses.add(ForLoopReplaceableByWhileInspection.class); + inspectionClasses.add(UnnecessaryDefaultInspection.class); + inspectionClasses.add(UnnecessaryBoxingInspection.class); + inspectionClasses.add(UnnecessaryUnboxingInspection.class); + inspectionClasses.add(UnnecessaryFinalOnParameterInspection.class); + inspectionClasses.add(UnnecessaryFinalOnLocalVariableInspection.class); + inspectionClasses.add(ForCanBeForeachInspection.class); + } + + private void registerStyleInspections() { + final List inspectionClasses = m_inspectionClasses; + inspectionClasses.add(ReturnThisInspection.class); + inspectionClasses.add(ConstantOnLHSOfComparisonInspection.class); + inspectionClasses.add(ConstantOnRHSOfComparisonInspection.class); + inspectionClasses.add(LiteralAsArgToStringEqualsInspection.class); + inspectionClasses.add(MissortedModifiersInspection.class); + inspectionClasses.add(CStyleArrayDeclarationInspection.class); + inspectionClasses.add(MultipleDeclarationInspection.class); + inspectionClasses.add(MultipleTypedDeclarationInspection.class); + inspectionClasses.add(UnqualifiedStaticUsageInspection.class); + inspectionClasses.add(UnnecessarilyQualifiedStaticUsageInspection.class); + } + + private void registerExceptionInspections() { + final List inspectionClasses = m_inspectionClasses; + inspectionClasses.add(CatchGenericClassInspection.class); + inspectionClasses.add(EmptyCatchBlockInspection.class); + inspectionClasses.add(UnusedCatchParameterInspection.class); + inspectionClasses.add(EmptyFinallyBlockInspection.class); + inspectionClasses.add(EmptyTryBlockInspection.class); + inspectionClasses.add(ThrowFromFinallyBlockInspection.class); + inspectionClasses.add(ThrowCaughtLocallyInspection.class); + inspectionClasses.add(ReturnFromFinallyBlockInspection.class); + inspectionClasses.add(ContinueOrBreakFromFinallyBlockInspection.class); + inspectionClasses.add(ThrowGenericClassInspection.class); + inspectionClasses.add(TooBroadCatchInspection.class); + inspectionClasses.add(CheckedExceptionClassInspection.class); + inspectionClasses.add(UncheckedExceptionClassInspection.class); + inspectionClasses.add(ThreadDeathRethrownInspection.class); + inspectionClasses.add(ErrorRethrownInspection.class); + inspectionClasses.add(NestedTryStatementInspection.class); + inspectionClasses.add(ExceptionFromCatchWhichDoesntWrapInspection.class); + inspectionClasses.add(InstanceofCatchParameterInspection.class); + } + + private void registerFinalizationInspections() { + final List inspectionClasses = m_inspectionClasses; + inspectionClasses.add(FinalizeInspection.class); + inspectionClasses.add(FinalizeNotProtectedInspection.class); + inspectionClasses.add(FinalizeCallsSuperFinalizeInspection.class); + inspectionClasses.add(NoExplicitFinalizeCallsInspection.class); + } + + private void registerSerializationInspections() { + final List inspectionClasses = m_inspectionClasses; + inspectionClasses.add(SerializableHasSerializationMethodsInspection.class); + inspectionClasses.add(SerializableHasSerialVersionUIDFieldInspection.class); + inspectionClasses.add(ReadObjectInitializationInspection.class); + inspectionClasses.add(ReadObjectAndWriteObjectPrivateInspection.class); + inspectionClasses.add(SerialVersionUIDNotStaticFinalInspection.class); + inspectionClasses.add(ReadResolveAndWriteReplaceProtectedInspection.class); + inspectionClasses.add(TransientFieldInNonSerializableClassInspection.class); + inspectionClasses.add(SerializableWithUnconstructableAncestorInspection.class); + inspectionClasses.add(NonSerializableWithSerializationMethodsInspection.class); + inspectionClasses.add(ExternalizableWithSerializationMethodsInspection.class); + inspectionClasses.add(NonSerializableWithSerialVersionUIDFieldInspection.class); + inspectionClasses.add(SerializableInnerClassHasSerialVersionUIDFieldInspection.class); + inspectionClasses.add(SerializableInnerClassWithNonSerializableOuterClassInspection.class); + } + + private void registerThreadingInspections() { + final List inspectionClasses = m_inspectionClasses; + inspectionClasses.add(DoubleCheckedLockingInspection.class); + inspectionClasses.add(BusyWaitInspection.class); + inspectionClasses.add(ObjectNotifyInspection.class); + inspectionClasses.add(NakedNotifyInspection.class); + inspectionClasses.add(UnconditionalWaitInspection.class); + inspectionClasses.add(WhileLoopSpinsOnFieldInspection.class); + inspectionClasses.add(WaitNotInLoopInspection.class); + inspectionClasses.add(VolatileLongOrDoubleFieldInspection.class); + inspectionClasses.add(WaitNotInSynchronizedContextInspection.class); + inspectionClasses.add(WaitWhileHoldingTwoLocksInspection.class); + inspectionClasses.add(NotifyNotInSynchronizedContextInspection.class); + inspectionClasses.add(ThreadRunInspection.class); + inspectionClasses.add(ThreadStartInConstructionInspection.class); + inspectionClasses.add(SynchronizedMethodInspection.class); + inspectionClasses.add(SynchronizeOnLockInspection.class); + inspectionClasses.add(SynchronizeOnNonFinalFieldInspection.class); + inspectionClasses.add(SynchronizeOnThisInspection.class); + inspectionClasses.add(NestedSynchronizedStatementInspection.class); + inspectionClasses.add(EmptySynchronizedStatementInspection.class); + inspectionClasses.add(NonSynchronizedMethodOverridesSynchronizedMethodInspection.class); + inspectionClasses.add(PublicFieldAccessedInSynchronizedContextInspection.class); + inspectionClasses.add(FieldAccessedSynchronizedAndUnsynchronizedInspection.class); + } + + private void registerMethodMetricsInspections() { + final List inspectionClasses = m_inspectionClasses; + inspectionClasses.add(ThreeNegationsPerMethodInspection.class); + inspectionClasses.add(MethodWithMultipleLoopsInspection.class); + inspectionClasses.add(MultipleReturnPointsPerMethodInspection.class); + inspectionClasses.add(ParametersPerMethodInspection.class); + inspectionClasses.add(CyclomaticComplexityInspection.class); + inspectionClasses.add(NestingDepthInspection.class); + inspectionClasses.add(NonCommentSourceStatementsInspection.class); + inspectionClasses.add(MethodCouplingInspection.class); + } + + private void registerClassMetricsInspections() { + final List inspectionClasses = m_inspectionClasses; + inspectionClasses.add(AnonymousClassComplexityInspection.class); + inspectionClasses.add(AnonymousClassMethodCountInspection.class); + inspectionClasses.add(ClassComplexityInspection.class); + inspectionClasses.add(ClassInheritanceDepthInspection.class); + inspectionClasses.add(ClassNestingDepthInspection.class); + inspectionClasses.add(ClassCouplingInspection.class); + inspectionClasses.add(ConstructorCountInspection.class); + inspectionClasses.add(MethodCountInspection.class); + inspectionClasses.add(FieldCountInspection.class); + } + + private void registerPortabilityInspections() { + final List inspectionClasses = m_inspectionClasses; + inspectionClasses.add(RuntimeExecInspection.class); + inspectionClasses.add(SystemExitInspection.class); + inspectionClasses.add(SystemGetenvInspection.class); + inspectionClasses.add(HardcodedLineSeparatorsInspection.class); + inspectionClasses.add(HardcodedFileSeparatorsInspection.class); + inspectionClasses.add(NativeMethodsInspection.class); + inspectionClasses.add(AssertAsNameInspection.class); + inspectionClasses.add(EnumAsNameInspection.class); + inspectionClasses.add(AssertStatementInspection.class); + inspectionClasses.add(AutoBoxingInspection.class); + inspectionClasses.add(AutoUnboxingInspection.class); + inspectionClasses.add(VarargParameterInspection.class); + inspectionClasses.add(ForeachStatementInspection.class); + inspectionClasses.add(EnumClassInspection.class); + inspectionClasses.add(AnnotationClassInspection.class); + inspectionClasses.add(AnnotationInspection.class); + inspectionClasses.add(UseOfSunClassesInspection.class); + } + + private void registerInternationalInspections() { + final List inspectionClasses = m_inspectionClasses; + inspectionClasses.add(StringLiteralInspection.class); + inspectionClasses.add(CharacterComparisonInspection.class); + inspectionClasses.add(MagicCharacterInspection.class); + inspectionClasses.add(NumericToStringInspection.class); + inspectionClasses.add(DateToStringInspection.class); + inspectionClasses.add(TimeToStringInspection.class); + inspectionClasses.add(StringCompareToInspection.class); + inspectionClasses.add(StringEqualsIgnoreCaseInspection.class); + inspectionClasses.add(StringEqualsInspection.class); + inspectionClasses.add(StringConcatenationInspection.class); + inspectionClasses.add(StringTokenizerInspection.class); + inspectionClasses.add(StringToUpperWithoutLocaleInspection.class); + } + + private void registerPerformanceInspections() { + final List inspectionClasses = m_inspectionClasses; + inspectionClasses.add(ObjectAllocationInLoopInspection.class); + inspectionClasses.add(UnnecessaryTemporaryOnConversionToStringInspection.class); + inspectionClasses.add(UnnecessaryTemporaryOnConversionFromStringInspection.class); + inspectionClasses.add(FieldMayBeStaticInspection.class); + inspectionClasses.add(MethodMayBeStaticInspection.class); + inspectionClasses.add(InnerClassMayBeStaticInspection.class); + inspectionClasses.add(StringBufferMustHaveInitialCapacityInspection.class); + inspectionClasses.add(StringBufferReplaceableByStringBuilderInspection.class); + inspectionClasses.add(StringBufferReplaceableByStringInspection.class); + inspectionClasses.add(StringReplaceableByStringBufferInspection.class); + inspectionClasses.add(CollectionsMustHaveInitialCapacityInspection.class); + inspectionClasses.add(StringConcatenationInLoopsInspection.class); + inspectionClasses.add(MultiplyOrDivideByPowerOfTwoInspection.class); + inspectionClasses.add(LengthOneStringsInConcatenationInspection.class); + inspectionClasses.add(BooleanConstructorInspection.class); + inspectionClasses.add(StringToStringInspection.class); + inspectionClasses.add(StringConstructorInspection.class); + inspectionClasses.add(StringBufferToStringInConcatenationInspection.class); + inspectionClasses.add(TailRecursionInspection.class); + inspectionClasses.add(TrivialStringConcatenationInspection.class); + inspectionClasses.add(SystemGCInspection.class); + inspectionClasses.add(SingleCharacterStartsWithInspection.class); + inspectionClasses.add(StringEqualsEmptyStringInspection.class); + inspectionClasses.add(FieldRepeatedlyAccessedInspection.class); + inspectionClasses.add(ManualArrayCopyInspection.class); + inspectionClasses.add(JavaLangReflectInspection.class); + inspectionClasses.add(StaticCollectionInspection.class); + inspectionClasses.add(ZeroLengthArrayInitializationInspection.class); + } + + private void registerMaturityInspections() { + final List inspectionClasses = m_inspectionClasses; + inspectionClasses.add(SystemOutErrInspection.class); + inspectionClasses.add(ThrowablePrintStackTraceInspection.class); + inspectionClasses.add(ThreadDumpStackInspection.class); + inspectionClasses.add(ClassWithoutToStringInspection.class); + inspectionClasses.add(ObsoleteCollectionInspection.class); + } + + private void registerJUnitInspections() { + final List inspectionClasses = m_inspectionClasses; + inspectionClasses.add(AssertsWithoutMessagesInspection.class); + inspectionClasses.add(TestCaseWithConstructorInspection.class); + inspectionClasses.add(MisspelledSetUpInspection.class); + inspectionClasses.add(MisspelledTearDownInspection.class); + inspectionClasses.add(StaticSuiteInspection.class); + inspectionClasses.add(SetupCallsSuperSetupInspection.class); + inspectionClasses.add(TeardownCallsSuperTeardownInspection.class); + inspectionClasses.add(SetupIsPublicVoidNoArgInspection.class); + inspectionClasses.add(TeardownIsPublicVoidNoArgInspection.class); + inspectionClasses.add(TestMethodIsPublicVoidNoArgInspection.class); + inspectionClasses.add(TestMethodWithoutAssertionInspection.class); + inspectionClasses.add(TestCaseWithNoTestMethodsInspection.class); + } + + public void disposeComponent() { + + } + + public InspectionGadgetsConfig getConfig() { + return m_config; + } + + public void readExternal(Element element) throws InvalidDataException { + m_config.readExternal(element); + } + + public void writeExternal(Element element) throws WriteExternalException { + m_config.writeExternal(element); + } + + public static boolean isEnabled() { + final InspectionGadgetsPlugin instance = getInstance(); + final InspectionGadgetsConfig config = instance.getConfig(); + return config.isEnabled(); + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/RegExFormatter.java b/plugins/InspectionGadgets/src/com/siyeh/ig/RegExFormatter.java new file mode 100644 index 000000000000..2f1defcb0646 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/RegExFormatter.java @@ -0,0 +1,36 @@ +/** + * (c) 2004 Carp Technologies BV + * Hengelosestraat 705, 7521PA Enschede + * Created: Feb 3, 2004, 5:44:43 PM + */ +package com.siyeh.ig; + +import javax.swing.text.DefaultFormatter; +import java.text.ParseException; +import java.util.regex.Pattern; +import java.util.regex.PatternSyntaxException; + +/** + * @author Bas Leijdekkers + */ +public class RegExFormatter extends DefaultFormatter { + public RegExFormatter() { + super(); + setOverwriteMode(false); + } + + public Object stringToValue(String text) throws ParseException { + try { + return Pattern.compile(text); + } catch (final PatternSyntaxException e) { + throw new ParseException(e.getMessage(), e.getIndex()); + } + } + + public String valueToString(Object value) throws ParseException { + if (value == null) { + return ""; + } + return ((Pattern) value).pattern(); + } +} \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/RegExInputVerifier.java b/plugins/InspectionGadgets/src/com/siyeh/ig/RegExInputVerifier.java new file mode 100644 index 000000000000..0d8266298d12 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/RegExInputVerifier.java @@ -0,0 +1,39 @@ +package com.siyeh.ig; + +import com.intellij.openapi.ui.Messages; + +import javax.swing.InputVerifier; +import javax.swing.JComponent; +import javax.swing.JFormattedTextField; +import javax.swing.SwingUtilities; +import java.text.ParseException; + +/** + * @author Bas Leijdekkers + */ +public class RegExInputVerifier extends InputVerifier { + public boolean verify(JComponent input) { + return true; + } + + + public boolean shouldYieldFocus(JComponent input) { + if (input instanceof JFormattedTextField) { + final JFormattedTextField ftf = (JFormattedTextField) input; + final JFormattedTextField.AbstractFormatter formatter = ftf.getFormatter(); + if (formatter != null) { + try { + formatter.stringToValue(ftf.getText()); + } catch (final ParseException e) { + SwingUtilities.invokeLater(new Runnable() { + public void run() { + Messages.showErrorDialog(e.getMessage(), "Malformed Naming Pattern"); + } + }); + } + } + + } + return true; + } +} \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/abstraction/CastToConcreteClassInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/abstraction/CastToConcreteClassInspection.java new file mode 100644 index 000000000000..da6915df7a06 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/abstraction/CastToConcreteClassInspection.java @@ -0,0 +1,46 @@ +package com.siyeh.ig.abstraction; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiTypeCastExpression; +import com.intellij.psi.PsiTypeElement; +import com.siyeh.ig.BaseInspection; +import com.siyeh.ig.BaseInspectionVisitor; +import com.siyeh.ig.ExpressionInspection; +import com.siyeh.ig.GroupNames; + +public class CastToConcreteClassInspection extends ExpressionInspection { + + public String getDisplayName() { + return "Cast to a concrete class"; + } + + public String getGroupDisplayName() { + return GroupNames.ABSTRACTION_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "Cast to concrete class #ref #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new CastToConcreteClassVisitor(this, inspectionManager, onTheFly); + } + + private static class CastToConcreteClassVisitor extends BaseInspectionVisitor { + + private CastToConcreteClassVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitTypeCastExpression(PsiTypeCastExpression expression) { + super.visitTypeCastExpression(expression); + final PsiTypeElement typeElement = expression.getCastType(); + + if (!ConcreteClassUtil.typeIsConcreteClass(typeElement)) { + return; + } + registerError(typeElement); + } + } +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/abstraction/ClassAccessVisitor.java b/plugins/InspectionGadgets/src/com/siyeh/ig/abstraction/ClassAccessVisitor.java new file mode 100644 index 000000000000..489ec231e2e5 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/abstraction/ClassAccessVisitor.java @@ -0,0 +1,72 @@ +package com.siyeh.ig.abstraction; + +import com.intellij.psi.*; +import com.intellij.psi.util.PsiTreeUtil; +import com.siyeh.ig.psiutils.LibraryUtil; + +import java.util.*; + +class ClassAccessVisitor extends PsiRecursiveElementVisitor { + private final Map m_accessCounts = new HashMap(2); + private final Set m_overAccessedClasses = new HashSet(2); + private static final Integer ONE = new Integer(1); + private static final Integer TWO = new Integer(2); + private PsiClass currentClass; + + ClassAccessVisitor(PsiClass currentClass) { + super(); + this.currentClass = currentClass; + } + + 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 expression) { + super.visitMethodCallExpression(expression); + final PsiMethod method = expression.resolveMethod(); + if (method == null) { + return; + } + final PsiClass calledClass = method.getContainingClass(); + if (currentClass.equals(calledClass)) { + return; + } + if (currentClass.isInheritor(calledClass, true)) { + return; + } + if (PsiTreeUtil.isAncestor(currentClass, calledClass, true)) { + return; + } + if (PsiTreeUtil.isAncestor(calledClass, currentClass, true)) { + return; + } + if (LibraryUtil.classIsInLibrary(calledClass)) { + return; + } + final Set overAccessedClasses = m_overAccessedClasses; + if (overAccessedClasses.contains(calledClass)) { + return; + } + final Map accessCounts = m_accessCounts; + final Integer count = (Integer) accessCounts.get(calledClass); + if (count == null) { + accessCounts.put(calledClass, ONE); + } else if (count.equals(ONE)) { + accessCounts.put(calledClass, TWO); + } else { + overAccessedClasses.add(calledClass); + } + } + + public Set getOveraccessedClasses() { + return Collections.unmodifiableSet(m_overAccessedClasses); + } +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/abstraction/ClassReferencesSubclassInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/abstraction/ClassReferencesSubclassInspection.java new file mode 100644 index 000000000000..9e6a490f0a32 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/abstraction/ClassReferencesSubclassInspection.java @@ -0,0 +1,171 @@ +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.ClassInspection; +import com.siyeh.ig.GroupNames; +import com.siyeh.ig.psiutils.ClassUtils; +import com.siyeh.ig.psiutils.CollectionUtils; + +public class ClassReferencesSubclassInspection extends ClassInspection { + + public String getDisplayName() { + return "Class references one of its subclasses"; + } + + public String getGroupDisplayName() { + return GroupNames.ABSTRACTION_GROUP_NAME; + } + + public String buildErrorString(PsiElement classRef) { + final PsiClass containingClass = + ClassUtils.getContainingClass(classRef); + final String containingClassName = containingClass.getName(); + return "Class " + containingClassName + " references subclass #ref #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new ClassReferencesSubclassVisitor(this, inspectionManager, onTheFly); + } + + private static class ClassReferencesSubclassVisitor extends BaseInspectionVisitor { + private boolean m_inClass = false; + + private ClassReferencesSubclassVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitClass(PsiClass aClass) { + final boolean wasInClass = m_inClass; + if (!m_inClass) { + + m_inClass = true; + super.visitClass(aClass); + } + m_inClass = wasInClass; + } + + public void visitVariable(PsiVariable variable) { + final PsiType type = variable.getType(); + if (type == null) { + return; + } + final PsiType componentType = type.getDeepComponentType(); + if (!(componentType instanceof PsiClassType)) { + return; + } + + final PsiClassType classType = (PsiClassType) componentType; + + final PsiClass containingClass = + ClassUtils.getContainingClass(variable); + if (!isSubclass(classType, containingClass)) { + return; + } + final PsiElement typeElement = variable.getTypeElement(); + registerError(typeElement); + } + + public void visitMethod(PsiMethod method) { + super.visitMethod(method); + final PsiType type = method.getReturnType(); + if (type == null) { + return; + } + final PsiType componentType = type.getDeepComponentType(); + if (!(componentType instanceof PsiClassType)) { + return; + } + final PsiClassType classType = (PsiClassType) componentType; + final PsiClass containingClass = method.getContainingClass(); + if (!isSubclass(classType, containingClass)) { + return; + } + if (!CollectionUtils.isCollectionClass(type)) { + return; + } + final PsiTypeElement typeElement = method.getReturnTypeElement(); + registerError(typeElement); + } + + public void visitInstanceOfExpression(PsiInstanceOfExpression exp) { + super.visitInstanceOfExpression(exp); + final PsiTypeElement typeElement = exp.getCheckType(); + if (typeElement == null) { + return; + } + final PsiType type = typeElement.getType(); + if (type == null) { + return; + } + final PsiType componentType = type.getDeepComponentType(); + if (!(componentType instanceof PsiClassType)) { + return; + } + final PsiClassType classType = (PsiClassType) componentType; + final PsiClass containingClass = + ClassUtils.getContainingClass(exp); + if (!isSubclass(classType, containingClass)) { + return; + } + registerError(typeElement); + } + + public void visitTypeCastExpression(PsiTypeCastExpression exp) { + super.visitTypeCastExpression(exp); + final PsiTypeElement typeElement = exp.getCastType(); + if (typeElement == null) { + return; + } + final PsiType type = typeElement.getType(); + if (type == null) { + return; + } + final PsiType componentType = type.getDeepComponentType(); + if (!(componentType instanceof PsiClassType)) { + return; + } + final PsiClassType classType = (PsiClassType) componentType; + final PsiClass containingClass = + ClassUtils.getContainingClass(exp); + if (!isSubclass(classType, containingClass)) { + return; + } + registerError(typeElement); + } + + public void visitClassObjectAccessExpression(PsiClassObjectAccessExpression exp) { + super.visitClassObjectAccessExpression(exp); + final PsiTypeElement typeElement = exp.getOperand(); + if (typeElement == null) { + return; + } + final PsiType type = typeElement.getType(); + if (type == null) { + return; + } + final PsiType componentType = type.getDeepComponentType(); + if (!(componentType instanceof PsiClassType)) { + return; + } + final PsiClassType classType = (PsiClassType) componentType; + final PsiClass containingClass = + ClassUtils.getContainingClass(exp); + if (!isSubclass(classType, containingClass)) { + return; + } + registerError(typeElement); + } + + private static boolean isSubclass(PsiClassType childClass, PsiClass parent) { + final PsiClass child = childClass.resolve(); + if (child == null) { + return false; + } + return child.isInheritor(parent, true); + } + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/abstraction/ConcreteClassUtil.java b/plugins/InspectionGadgets/src/com/siyeh/ig/abstraction/ConcreteClassUtil.java new file mode 100644 index 000000000000..8849a2af9358 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/abstraction/ConcreteClassUtil.java @@ -0,0 +1,41 @@ +package com.siyeh.ig.abstraction; + +import com.intellij.psi.PsiType; +import com.intellij.psi.PsiClassType; +import com.intellij.psi.PsiClass; +import com.intellij.psi.PsiTypeElement; +import com.siyeh.ig.psiutils.LibraryUtil; + +public class ConcreteClassUtil { + private ConcreteClassUtil() { + super(); + } + + public static boolean typeIsConcreteClass(PsiTypeElement typeElement) { + if (typeElement == null) { + return false; + } + final PsiType type = typeElement.getType(); + if (type == null) { + return false; + } + final PsiType baseType = type.getDeepComponentType(); + if (baseType == null) { + return false; + } + if (!(baseType instanceof PsiClassType)) { + return false; + } + final PsiClass aClass = ((PsiClassType) baseType).resolve(); + if (aClass == null) { + return false; + } + if (aClass.isInterface() || aClass.isEnum()|| aClass.isAnnotationType()) { + return false; + } + if (LibraryUtil.classIsInLibrary(aClass)) { + return false; + } + return true; + } +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/abstraction/DeclareCollectionAsInterfaceInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/abstraction/DeclareCollectionAsInterfaceInspection.java new file mode 100644 index 000000000000..99905e5b286a --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/abstraction/DeclareCollectionAsInterfaceInspection.java @@ -0,0 +1,63 @@ +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.VariableInspection; +import com.siyeh.ig.psiutils.CollectionUtils; + +public class DeclareCollectionAsInterfaceInspection extends VariableInspection { + + public String getDisplayName() { + return "Collection declared by class, not interface"; + } + + public String getGroupDisplayName() { + return GroupNames.ABSTRACTION_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + final String type = location.getText(); + final String interfaceName = CollectionUtils.getInterfaceForClass(type); + return "Declaration of #ref should probably be weakened to " + interfaceName + " #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new DeclareCollectionAsInterfaceVisitor(this, inspectionManager, onTheFly); + } + + private static class DeclareCollectionAsInterfaceVisitor extends BaseInspectionVisitor { + private DeclareCollectionAsInterfaceVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitVariable(PsiVariable variable) { + final PsiType type = variable.getType(); + if (type == null) { + return; + } + if (!CollectionUtils.isCollectionClass(type)) { + return; + } + final PsiTypeElement typeElement = variable.getTypeElement(); + registerError(typeElement); + } + + public void visitMethod(PsiMethod method) { + super.visitMethod(method); + final PsiType type = method.getReturnType(); + if (type == null) { + return; + } + if (!CollectionUtils.isCollectionClass(type)) { + return; + } + final PsiTypeElement typeElement = method.getReturnTypeElement(); + registerError(typeElement); + } + + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/abstraction/FeatureEnvyInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/abstraction/FeatureEnvyInspection.java new file mode 100644 index 000000000000..8756ebc51a06 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/abstraction/FeatureEnvyInspection.java @@ -0,0 +1,59 @@ +package com.siyeh.ig.abstraction; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.psi.PsiClass; +import com.intellij.psi.PsiIdentifier; +import com.intellij.psi.PsiMethod; +import com.intellij.psi.PsiNamedElement; +import com.siyeh.ig.BaseInspection; +import com.siyeh.ig.BaseInspectionVisitor; +import com.siyeh.ig.GroupNames; +import com.siyeh.ig.MethodInspection; + +import java.util.Iterator; +import java.util.Set; + +public class FeatureEnvyInspection extends MethodInspection { + + public String getDisplayName() { + return "Feature Envy"; + } + + public String getGroupDisplayName() { + return GroupNames.ABSTRACTION_GROUP_NAME; + } + + public String buildErrorString(Object arg) { + final String className = ((PsiNamedElement) arg).getName(); + return "Class " + className + " accessed repeatedly in method #ref #loc"; + } + + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new InstanceVariableRepeatedlyAccessedVisitor(this, inspectionManager, onTheFly); + } + + private static class InstanceVariableRepeatedlyAccessedVisitor extends BaseInspectionVisitor { + private InstanceVariableRepeatedlyAccessedVisitor(BaseInspection inspection, + InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitMethod(PsiMethod method) { + final PsiIdentifier nameIdentifier = method.getNameIdentifier(); + if (nameIdentifier == null) { + return; + } + final PsiClass containingClass = method.getContainingClass(); + final ClassAccessVisitor visitor = new ClassAccessVisitor(containingClass); + method.accept(visitor); + final Set overaccessedClasses = visitor.getOveraccessedClasses(); + for (Iterator iterator = overaccessedClasses.iterator(); iterator.hasNext();) { + final PsiClass aClass = (PsiClass) iterator.next(); + registerError(nameIdentifier, aClass); + } + } + + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/abstraction/InstanceVariableOfConcreteClassInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/abstraction/InstanceVariableOfConcreteClassInspection.java new file mode 100644 index 000000000000..b970677ec418 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/abstraction/InstanceVariableOfConcreteClassInspection.java @@ -0,0 +1,49 @@ +package com.siyeh.ig.abstraction; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.psi.PsiField; +import com.intellij.psi.PsiModifier; +import com.intellij.psi.PsiTypeElement; +import com.siyeh.ig.BaseInspection; +import com.siyeh.ig.BaseInspectionVisitor; +import com.siyeh.ig.FieldInspection; +import com.siyeh.ig.GroupNames; + +public class InstanceVariableOfConcreteClassInspection extends FieldInspection { + + public String getDisplayName() { + return "Concrete class for instance variable"; + } + + public String getGroupDisplayName() { + return GroupNames.ABSTRACTION_GROUP_NAME; + } + + public String buildErrorString(Object arg) { + return "Instance variable " + arg + " of concrete class #ref #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new InstanceVariableOfConcreteClassVisitor(this, inspectionManager, onTheFly); + } + + private static class InstanceVariableOfConcreteClassVisitor extends BaseInspectionVisitor { + private InstanceVariableOfConcreteClassVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitField(PsiField field) { + super.visitField(field); + if (field.hasModifierProperty(PsiModifier.STATIC)) { + return; + } + final PsiTypeElement typeElement = field.getTypeElement(); + if (!ConcreteClassUtil.typeIsConcreteClass(typeElement)) { + return; + } + final String variableName = field.getName(); + registerError(typeElement, variableName); + } + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/abstraction/InstanceofInterfacesInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/abstraction/InstanceofInterfacesInspection.java new file mode 100644 index 000000000000..23ac102d280e --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/abstraction/InstanceofInterfacesInspection.java @@ -0,0 +1,45 @@ +package com.siyeh.ig.abstraction; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiInstanceOfExpression; +import com.intellij.psi.PsiTypeElement; +import com.siyeh.ig.BaseInspection; +import com.siyeh.ig.BaseInspectionVisitor; +import com.siyeh.ig.ExpressionInspection; +import com.siyeh.ig.GroupNames; + +public class InstanceofInterfacesInspection extends ExpressionInspection { + + public String getDisplayName() { + return "'instanceof' a concrete class"; + } + + public String getGroupDisplayName() { + return GroupNames.ABSTRACTION_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "'instanceof' concrete class #ref #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new InstanceofInterfacesVisitor(this, inspectionManager, onTheFly); + } + + private static class InstanceofInterfacesVisitor extends BaseInspectionVisitor { + private InstanceofInterfacesVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitInstanceOfExpression(PsiInstanceOfExpression expression) { + super.visitInstanceOfExpression(expression); + final PsiTypeElement typeElement = expression.getCheckType(); + if (!ConcreteClassUtil.typeIsConcreteClass(typeElement)) { + return; + } + registerError(typeElement); + } + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/abstraction/InstanceofThisInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/abstraction/InstanceofThisInspection.java new file mode 100644 index 000000000000..fb299c39796f --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/abstraction/InstanceofThisInspection.java @@ -0,0 +1,52 @@ +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.ExpressionInspection; +import com.siyeh.ig.GroupNames; + +public class InstanceofThisInspection extends ExpressionInspection { + + public String getDisplayName() { + return "'instanceof' check for 'this'"; + } + + public String getGroupDisplayName() { + return GroupNames.ABSTRACTION_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "'instanceof' check for #ref #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new InstanceofThisVisitor(this, inspectionManager, onTheFly); + } + + private static class InstanceofThisVisitor extends BaseInspectionVisitor { + private InstanceofThisVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitThisExpression(PsiThisExpression thisValue) { + super.visitThisExpression(thisValue); + if (thisValue.getQualifier() != null) { + return; + } + PsiElement parent = thisValue.getParent(); + while (parent != null && + (parent instanceof PsiParenthesizedExpression || + parent instanceof PsiConditionalExpression || + parent instanceof PsiTypeCastExpression)) { + parent = parent.getParent(); + } + if (parent == null || !(parent instanceof PsiInstanceOfExpression)) { + return; + } + registerError(thisValue); + } + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/abstraction/LocalVariableOfConcreteClassInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/abstraction/LocalVariableOfConcreteClassInspection.java new file mode 100644 index 000000000000..cacc3d98c075 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/abstraction/LocalVariableOfConcreteClassInspection.java @@ -0,0 +1,45 @@ +package com.siyeh.ig.abstraction; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.psi.PsiLocalVariable; +import com.intellij.psi.PsiTypeElement; +import com.siyeh.ig.BaseInspection; +import com.siyeh.ig.BaseInspectionVisitor; +import com.siyeh.ig.ExpressionInspection; +import com.siyeh.ig.GroupNames; + +public class LocalVariableOfConcreteClassInspection extends ExpressionInspection { + + public String getDisplayName() { + return "Concrete class for local variable"; + } + + public String getGroupDisplayName() { + return GroupNames.ABSTRACTION_GROUP_NAME; + } + + public String buildErrorString(Object arg) { + return "Local variable " + arg + " of concrete class #ref #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new LocalVariableOfConcreteClassVisitor(this, inspectionManager, onTheFly); + } + + private static class LocalVariableOfConcreteClassVisitor extends BaseInspectionVisitor { + private LocalVariableOfConcreteClassVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitLocalVariable(PsiLocalVariable variable) { + super.visitLocalVariable(variable); + final PsiTypeElement typeElement = variable.getTypeElement(); + if (!ConcreteClassUtil.typeIsConcreteClass(typeElement)) { + return; + } + final String variableName = variable.getName(); + registerError(typeElement, variableName); + } + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/abstraction/MagicNumberInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/abstraction/MagicNumberInspection.java new file mode 100644 index 000000000000..6f09903e2503 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/abstraction/MagicNumberInspection.java @@ -0,0 +1,107 @@ +package com.siyeh.ig.abstraction; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.psi.*; +import com.intellij.psi.util.PsiTreeUtil; +import com.siyeh.ig.*; +import com.siyeh.ig.fixes.IntroduceConstantFix; +import com.siyeh.ig.psiutils.ClassUtils; + +import java.util.HashSet; +import java.util.Set; + +public class MagicNumberInspection extends ExpressionInspection { + + private static final int NUM_SPECIAL_CASE_LITERALS = 22; + private static final String[] s_specialCaseLiteralArray = + new String[]{ + "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "0L", + "1L", "2L", "0l", "1l", "2l", "0.0", "1.0", "0.0F", "1.0F", "0.0f", "1.0f" + }; + private static final Set s_specialCaseLiterals = new HashSet(NUM_SPECIAL_CASE_LITERALS); + private final IntroduceConstantFix fix = new IntroduceConstantFix(); + + static { + for (int i = 0; i < s_specialCaseLiteralArray.length; i++) { + s_specialCaseLiterals.add(s_specialCaseLiteralArray[i]); + } + } + + public String getDisplayName() { + return "\"Magic number\""; + } + + public String getGroupDisplayName() { + return GroupNames.ABSTRACTION_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "Magic number '#ref' #loc"; + } + + protected boolean buildQuickFixesOnlyForOnTheFlyErrors() { + return true; + } + + protected InspectionGadgetsFix buildFix(PsiElement location) { + return fix; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new MagicNumberVisitor(this, inspectionManager, onTheFly); + } + + private static class MagicNumberVisitor extends BaseInspectionVisitor { + private MagicNumberVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitLiteralExpression(PsiLiteralExpression expression) { + super.visitLiteralExpression(expression); + final PsiType type = expression.getType(); + if (type == null) { + return; + } + if (!ClassUtils.isPrimitiveNumericType(type)) { + return; + } + if (type.equals(PsiType.CHAR)) { + return; + } + final String text = expression.getText(); + if (text == null) { + return; + } + if (isSpecialCase(text)) { + return; + } + if (isDeclaredConstant(expression)) { + return; + } + registerError(expression); + } + + private static boolean isSpecialCase(String text) { + return s_specialCaseLiterals.contains(text); + } + + private static boolean isDeclaredConstant(PsiLiteralExpression expression) { + final PsiField field = + (PsiField) PsiTreeUtil.getParentOfType(expression, PsiField.class); + if (field == null) { + return false; + } + if (!field.hasModifierProperty(PsiModifier.STATIC) || + !field.hasModifierProperty(PsiModifier.FINAL)) { + return false; + } + final PsiType type = field.getType(); + if (!ClassUtils.isImmutable(type)) { + return false; + } + return true; + } + + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/abstraction/MethodReturnOfConcreteClassInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/abstraction/MethodReturnOfConcreteClassInspection.java new file mode 100644 index 000000000000..a96ba4eeda1f --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/abstraction/MethodReturnOfConcreteClassInspection.java @@ -0,0 +1,49 @@ +package com.siyeh.ig.abstraction; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiMethod; +import com.intellij.psi.PsiTypeElement; +import com.siyeh.ig.BaseInspection; +import com.siyeh.ig.BaseInspectionVisitor; +import com.siyeh.ig.GroupNames; +import com.siyeh.ig.MethodInspection; + +public class MethodReturnOfConcreteClassInspection extends MethodInspection { + + public String getDisplayName() { + return "Concrete class for method return"; + } + + public String getGroupDisplayName() { + return GroupNames.ABSTRACTION_GROUP_NAME; + } + + protected String buildErrorString(PsiElement location) { + return "Method returns a concrete class #ref #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new MethodReturnOfConcreteClassVisitor(this, inspectionManager, onTheFly); + } + + private static class MethodReturnOfConcreteClassVisitor extends BaseInspectionVisitor { + private MethodReturnOfConcreteClassVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitMethod(PsiMethod method) { + super.visitMethod(method); + if (method.isConstructor()) { + return; + } + final PsiTypeElement typeElement = method.getReturnTypeElement(); + if (!ConcreteClassUtil.typeIsConcreteClass(typeElement)) { + return; + } + registerError(typeElement); + } + + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/abstraction/OverlyStrongTypeCastInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/abstraction/OverlyStrongTypeCastInspection.java new file mode 100644 index 000000000000..1d91fbb33ab7 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/abstraction/OverlyStrongTypeCastInspection.java @@ -0,0 +1,97 @@ +package com.siyeh.ig.abstraction; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.codeInspection.ProblemDescriptor; +import com.intellij.openapi.project.Project; +import com.intellij.psi.*; +import com.intellij.psi.util.TypeConversionUtil; +import com.siyeh.ig.*; +import com.siyeh.ig.psiutils.ClassUtils; +import com.siyeh.ig.psiutils.ExpectedTypeUtils; + +public class OverlyStrongTypeCastInspection extends ExpressionInspection { + private final OverlyStringCastFix fix = new OverlyStringCastFix(); + + public String getDisplayName() { + return "Overly-strong type cast"; + } + + public String getGroupDisplayName() { + return GroupNames.ABSTRACTION_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "Cast to #ref can be weakened #loc"; + } + + public InspectionGadgetsFix buildFix(PsiElement location) { + return fix; + } + + private static class OverlyStringCastFix extends InspectionGadgetsFix { + public String getName() { + return "Weaken overly-strong cast"; + } + + public void applyFix(Project project, ProblemDescriptor descriptor) { + final PsiElement castTypeElement = descriptor.getPsiElement(); + final PsiTypeCastExpression expression = + (PsiTypeCastExpression) castTypeElement.getParent(); + final PsiType expectedType = + ExpectedTypeUtils.findExpectedType(expression); + final String newExpression = '(' + expectedType.getPresentableText() + ')' + expression.getOperand().getText(); + replaceExpression(project, expression, newExpression); + } + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new OverlyStrongTypeCastVisitor(this, inspectionManager, onTheFly); + } + + private static class OverlyStrongTypeCastVisitor extends BaseInspectionVisitor { + private OverlyStrongTypeCastVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitTypeCastExpression(PsiTypeCastExpression expression) { + super.visitTypeCastExpression(expression); + final PsiExpression operand = expression.getOperand(); + if (operand == null) { + return; + } + final PsiType operandType = operand.getType(); + if (operandType == null) { + return; + } + final PsiTypeElement typeElement = expression.getCastType(); + if (typeElement == null) { + return; + } + final PsiType type = typeElement.getType(); + if (type == null) { + return; + } + final PsiType expectedType = + ExpectedTypeUtils.findExpectedType(expression); + if (expectedType == null) { + return; + } + if (expectedType.equals(type)) { + return; + } + if (expectedType.isAssignableFrom(operandType)) { + return; //then it's redundant, and caught by the built-in exception + } + + if (ClassUtils.isPrimitiveNumericType(type) || + ClassUtils.isPrimitiveNumericType(expectedType)) { + return; + } + if (TypeConversionUtil.isPrimitiveWrapper(type.getCanonicalText()) || + TypeConversionUtil.isPrimitiveWrapper(type.getCanonicalText())) { + return; + } + registerError(typeElement); + } + } +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/abstraction/ParameterOfConcreteClassInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/abstraction/ParameterOfConcreteClassInspection.java new file mode 100644 index 000000000000..0ae3215c5f1d --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/abstraction/ParameterOfConcreteClassInspection.java @@ -0,0 +1,50 @@ +package com.siyeh.ig.abstraction; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.psi.PsiParameter; +import com.intellij.psi.PsiTryStatement; +import com.intellij.psi.PsiTypeElement; +import com.siyeh.ig.BaseInspection; +import com.siyeh.ig.BaseInspectionVisitor; +import com.siyeh.ig.GroupNames; +import com.siyeh.ig.MethodInspection; + +public class ParameterOfConcreteClassInspection extends MethodInspection { + + public String getDisplayName() { + return "Concrete class for method parameter"; + } + + public String getGroupDisplayName() { + return GroupNames.ABSTRACTION_GROUP_NAME; + } + + public String buildErrorString(Object arg) { + return "Parameter " + arg + " of concrete class #ref #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new LocalVariableOfConcreteClassVisitor(this, inspectionManager, onTheFly); + } + + private static class LocalVariableOfConcreteClassVisitor extends BaseInspectionVisitor { + private LocalVariableOfConcreteClassVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitParameter(PsiParameter parameter) { + super.visitParameter(parameter); + + if (parameter.getParent() instanceof PsiTryStatement) { + return; + } + final PsiTypeElement typeElement = parameter.getTypeElement(); + if (!ConcreteClassUtil.typeIsConcreteClass(typeElement)) { + return; + } + final String variableName = parameter.getName(); + registerError(typeElement, variableName); + } + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/abstraction/PublicMethodNotExposedInInterfaceInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/abstraction/PublicMethodNotExposedInInterfaceInspection.java new file mode 100644 index 000000000000..cdf793c7ba3e --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/abstraction/PublicMethodNotExposedInInterfaceInspection.java @@ -0,0 +1,82 @@ +package com.siyeh.ig.abstraction; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.psi.*; +import com.intellij.psi.util.PsiSuperMethodUtil; +import com.siyeh.ig.BaseInspection; +import com.siyeh.ig.BaseInspectionVisitor; +import com.siyeh.ig.GroupNames; +import com.siyeh.ig.MethodInspection; + +public class PublicMethodNotExposedInInterfaceInspection extends MethodInspection { + + public String getDisplayName() { + return "Public method not exposed in interface"; + } + + public String getGroupDisplayName() { + return GroupNames.ABSTRACTION_GROUP_NAME; + } + + protected String buildErrorString(PsiElement location) { + return "Public method '#ref' is not exposed via an interface #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new PublicMethodNotExposedInInterface(this, inspectionManager, onTheFly); + } + + private static class PublicMethodNotExposedInInterface extends BaseInspectionVisitor { + private PublicMethodNotExposedInInterface(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitMethod(PsiMethod method) { + super.visitMethod(method); + if (method.isConstructor()) { + return; + } + if (!method.hasModifierProperty(PsiModifier.PUBLIC)) { + return; + } + if (method.hasModifierProperty(PsiModifier.STATIC)) { + return; + } + final PsiClass containingClass = method.getContainingClass(); + if (containingClass == null) { + return; + } + if (containingClass.isInterface()|| containingClass.isAnnotationType()) { + return; + } + if (!containingClass.hasModifierProperty(PsiModifier.PUBLIC)) { + return; + } + if (exposedInInterface(method)) { + return; + } + registerMethodError(method); + } + + private boolean exposedInInterface(PsiMethod method) { + final PsiMethod[] superMethods = PsiSuperMethodUtil.findSuperMethods(method); + for (int i = 0; i < superMethods.length; i++) { + final PsiMethod superMethod = superMethods[i]; + final PsiClass superClass = superMethod.getContainingClass(); + if (superClass.isInterface()) { + return true; + } + final String superclassName = superClass.getQualifiedName(); + if ("java.lang.Object".equals(superclassName)) { + return true; + } + if (exposedInInterface(superMethod)) { + return true; + } + } + return false; + } + + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/abstraction/RawUseOfParameterizedTypeInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/abstraction/RawUseOfParameterizedTypeInspection.java new file mode 100644 index 000000000000..a9b6954f45e4 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/abstraction/RawUseOfParameterizedTypeInspection.java @@ -0,0 +1,102 @@ +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.VariableInspection; + +public class RawUseOfParameterizedTypeInspection extends VariableInspection { + + public String getDisplayName() { + return "Raw use of parameterized class"; + } + + public String getGroupDisplayName() { + return GroupNames.ABSTRACTION_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "Raw use of parameterized class #ref #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new RawUseOfParameterizedTypeVisitor(this, inspectionManager, onTheFly); + } + + private static class RawUseOfParameterizedTypeVisitor extends BaseInspectionVisitor { + private RawUseOfParameterizedTypeVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitVariable(PsiVariable variable) { + super.visitVariable(variable); + final PsiTypeElement typeElement = variable.getTypeElement(); + checkTypeElement(typeElement); + } + + public void visitTypeCastExpression(PsiTypeCastExpression cast) { + super.visitTypeCastExpression(cast); + final PsiTypeElement typeElement = cast.getCastType(); + checkTypeElement(typeElement); + } + + public void visitNewExpression(PsiNewExpression newExpression) { + super.visitNewExpression(newExpression); + final PsiJavaCodeReferenceElement classReference = + newExpression.getClassReference(); + + if (classReference == null) { + return; + } + final PsiElement referent = classReference.resolve(); + if (referent == null) { + return; + } + if (!(referent instanceof PsiClass)) { + return; + } + if (!((PsiClass) referent).hasTypeParameters()) { + return; + } + if (newExpression.getTypeArgumentList() != null) { + return; + } + registerError(classReference); + } + + private void checkTypeElement(PsiTypeElement typeElement) { + if (typeElement == null) { + return; + } + final PsiType type = typeElement.getType(); + if (type == null) { + return; + } + final PsiType componentType = type.getDeepComponentType(); + if (componentType == null) { + return; + } + if (!(componentType instanceof PsiClassType)) { + return; + } + final String typeText = componentType.getCanonicalText(); + if (typeText.indexOf((int) '<') >= 0) { + return; + } + final PsiClass aClass = ((PsiClassType) componentType).resolve(); + + if (aClass == null) { + return; + } + if (!aClass.hasTypeParameters()) { + return; + } + final PsiElement typeNameElement = + typeElement.getInnermostComponentReferenceElement(); + registerError(typeNameElement); + } + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/abstraction/StaticVariableOfConcreteClassInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/abstraction/StaticVariableOfConcreteClassInspection.java new file mode 100644 index 000000000000..7289082c1271 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/abstraction/StaticVariableOfConcreteClassInspection.java @@ -0,0 +1,49 @@ +package com.siyeh.ig.abstraction; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.psi.PsiField; +import com.intellij.psi.PsiModifier; +import com.intellij.psi.PsiTypeElement; +import com.siyeh.ig.BaseInspection; +import com.siyeh.ig.BaseInspectionVisitor; +import com.siyeh.ig.FieldInspection; +import com.siyeh.ig.GroupNames; + +public class StaticVariableOfConcreteClassInspection extends FieldInspection { + + public String getDisplayName() { + return "Concrete class for static variable"; + } + + public String getGroupDisplayName() { + return GroupNames.ABSTRACTION_GROUP_NAME; + } + + public String buildErrorString(Object arg) { + return "Static variable " + arg + " of concrete class #ref #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new StaticVariableOfConcreteClassVisitor(this, inspectionManager, onTheFly); + } + + private static class StaticVariableOfConcreteClassVisitor extends BaseInspectionVisitor { + private StaticVariableOfConcreteClassVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitField(PsiField field) { + super.visitField(field); + if (!field.hasModifierProperty(PsiModifier.STATIC)) { + return; + } + final PsiTypeElement typeElement = field.getTypeElement(); + if (!ConcreteClassUtil.typeIsConcreteClass(typeElement)) { + return; + } + final String variableName = field.getName(); + registerError(typeElement, variableName); + } + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/abstraction/SwitchStatementInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/abstraction/SwitchStatementInspection.java new file mode 100644 index 000000000000..82b8a5487e17 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/abstraction/SwitchStatementInspection.java @@ -0,0 +1,41 @@ +package com.siyeh.ig.abstraction; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiSwitchStatement; +import com.siyeh.ig.BaseInspection; +import com.siyeh.ig.BaseInspectionVisitor; +import com.siyeh.ig.GroupNames; +import com.siyeh.ig.StatementInspection; + +public class SwitchStatementInspection extends StatementInspection { + + public String getDisplayName() { + return "'switch' statement"; + } + + public String getGroupDisplayName() { + return GroupNames.ABSTRACTION_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "'#ref' statement #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new SwitchStatementVisitor(this, inspectionManager, onTheFly); + } + + private static class SwitchStatementVisitor extends BaseInspectionVisitor { + private SwitchStatementVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitSwitchStatement(PsiSwitchStatement statement) { + super.visitSwitchStatement(statement); + registerStatementError(statement); + } + + } + +} \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/bugs/AssignmentToNullInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/bugs/AssignmentToNullInspection.java new file mode 100644 index 000000000000..f71e94e425df --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/bugs/AssignmentToNullInspection.java @@ -0,0 +1,55 @@ +package com.siyeh.ig.bugs; + +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 AssignmentToNullInspection extends ExpressionInspection { + + public String getDisplayName() { + return "Assignment to 'null'"; + } + + public String getGroupDisplayName() { + return GroupNames.BUGS_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "Assignment of variable #ref to null #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new AssignmentToNullVisitor(this, inspectionManager, onTheFly); + } + + private static class AssignmentToNullVisitor extends BaseInspectionVisitor { + private AssignmentToNullVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitLiteralExpression(PsiLiteralExpression value) { + super.visitLiteralExpression(value); + final String text = value.getText(); + if (!"null".equals(text)) { + return; + } + PsiElement parent = value.getParent(); + while (parent != null && + (parent instanceof PsiParenthesizedExpression || + parent instanceof PsiConditionalExpression || + parent instanceof PsiTypeCastExpression)) { + parent = parent.getParent(); + } + if (parent == null || !(parent instanceof PsiAssignmentExpression)) { + return; + } + final PsiExpression lhs = ((PsiAssignmentExpression) parent).getLExpression(); + registerError(lhs); + } + + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/bugs/AssignmentUsedAsConditionInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/bugs/AssignmentUsedAsConditionInspection.java new file mode 100644 index 000000000000..39bea01f0de4 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/bugs/AssignmentUsedAsConditionInspection.java @@ -0,0 +1,105 @@ +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 AssignmentUsedAsConditionInspection extends ExpressionInspection { + private final AssignmentUsedAsConditionFix fix = new AssignmentUsedAsConditionFix(); + + public String getDisplayName() { + return "Assignment used as condition"; + } + + public String getGroupDisplayName() { + return GroupNames.BUGS_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "#ref used as condition #loc"; + } + + public InspectionGadgetsFix buildFix(PsiElement location) { + return fix; + } + + private static class AssignmentUsedAsConditionFix extends InspectionGadgetsFix { + public String getName() { + return "replace '=' with '=='"; + } + + public void applyFix(Project project, ProblemDescriptor problemDescriptor) { + final PsiAssignmentExpression expression = + (PsiAssignmentExpression) problemDescriptor.getPsiElement(); + final PsiExpression leftExpression = expression.getLExpression(); + final PsiExpression rightExpression = expression.getRExpression(); + final String newExpression = leftExpression.getText() + "==" + rightExpression.getText(); + replaceExpression(project, expression, newExpression); + } + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new AssignmentUsedAsConditionVisitor(this, inspectionManager, onTheFly); + } + + private static class AssignmentUsedAsConditionVisitor extends BaseInspectionVisitor { + private AssignmentUsedAsConditionVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitAssignmentExpression(PsiAssignmentExpression expression) { + super.visitAssignmentExpression(expression); + final PsiJavaToken sign = expression.getOperationSign(); + if (sign == null) { + return; + } + if (sign.getTokenType() != JavaTokenType.EQ) { + return; + } + final PsiElement parent = expression.getParent(); + if (parent instanceof PsiIfStatement) { + checkIfStatementCondition((PsiIfStatement) parent, expression); + } + if (parent instanceof PsiWhileStatement) { + checkWhileStatementCondition((PsiWhileStatement) parent, expression); + } + if (parent instanceof PsiForStatement) { + checkForStatementCondition((PsiForStatement) parent, expression); + } + if (parent instanceof PsiDoWhileStatement) { + checkDoWhileStatementCondition((PsiDoWhileStatement) parent, expression); + } + } + + private void checkIfStatementCondition(PsiIfStatement ifStatement, PsiAssignmentExpression expression) { + final PsiExpression condition = ifStatement.getCondition(); + if (condition != null && condition.equals(expression)) { + registerError(expression); + } + } + + private void checkDoWhileStatementCondition(PsiDoWhileStatement doWhileStatement, PsiAssignmentExpression expression) { + final PsiExpression condition = doWhileStatement.getCondition(); + if (condition != null && condition.equals(expression)) { + registerError(expression); + } + } + + private void checkForStatementCondition(PsiForStatement forStatement, PsiAssignmentExpression expression) { + final PsiExpression condition = forStatement.getCondition(); + if (condition != null && condition.equals(expression)) { + registerError(expression); + } + } + + private void checkWhileStatementCondition(PsiWhileStatement whileStatement, PsiAssignmentExpression expression) { + final PsiExpression condition = whileStatement.getCondition(); + if (condition != null && condition.equals(expression)) { + registerError(expression); + } + } + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/bugs/CollectionQueryCalledVisitor.java b/plugins/InspectionGadgets/src/com/siyeh/ig/bugs/CollectionQueryCalledVisitor.java new file mode 100644 index 000000000000..128ac55a1755 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/bugs/CollectionQueryCalledVisitor.java @@ -0,0 +1,100 @@ +package com.siyeh.ig.bugs; + +import com.intellij.psi.*; + +import java.util.Set; +import java.util.HashSet; + +public class CollectionQueryCalledVisitor extends PsiRecursiveElementVisitor { + private static Set queryNames = new HashSet(10); + + static { + queryNames.add("get"); + queryNames.add("contains"); + queryNames.add("containsKey"); + queryNames.add("containsValue"); + queryNames.add("containsAll"); + queryNames.add("size"); + queryNames.add("indexOf"); + queryNames.add("iterator"); + queryNames.add("lastIndexOf"); + queryNames.add("toArray"); + queryNames.add("isEmpty"); + queryNames.add("entrySet"); + queryNames.add("keySet"); + queryNames.add("values"); + } + + private boolean queried = false; + private final PsiVariable variable; + + public CollectionQueryCalledVisitor(PsiVariable variable) { + super(); + this.variable = variable; + } + + public void visitReferenceExpression(PsiReferenceExpression exp) { + final PsiExpression qualifier = exp.getQualifierExpression(); + if (qualifier != null) { + qualifier.accept(this); + } + final PsiReferenceParameterList typeParameters = exp.getParameterList(); + if (typeParameters != null) { + typeParameters.accept(this); + } + } + + public void visitForeachStatement(PsiForeachStatement statement) { + super.visitForeachStatement(statement); + final PsiExpression qualifier = statement.getIteratedValue(); + if (qualifier == null) { + return; + } + if (!(qualifier instanceof PsiReferenceExpression)) { + return; + } + final PsiElement referent = ((PsiReference) qualifier).resolve(); + if (referent == null) { + return; + } + if (!referent.equals(variable)) { + return; + } + queried = true; + } + + public void visitMethodCallExpression(PsiMethodCallExpression call) { + super.visitMethodCallExpression(call); + final PsiReferenceExpression methodExpression = call.getMethodExpression(); + if (methodExpression == null) { + return; + } + final PsiExpression qualifier = methodExpression.getQualifierExpression(); + if (qualifier == null) { + return; + } + if (!(qualifier instanceof PsiReferenceExpression)) { + return; + } + final PsiElement referent = ((PsiReference) qualifier).resolve(); + if (referent == null) { + return; + } + if (!referent.equals(variable)) { + return; + } + final boolean isStatement = call.getParent() instanceof PsiExpressionStatement; + if (!isStatement) { + queried = true; + return; + } + final String methodName = methodExpression.getReferenceName(); + if (queryNames.contains(methodName)) { + queried = true; + } + } + + public boolean isQueried() { + return queried; + } +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/bugs/CollectionUpdateCalledVisitor.java b/plugins/InspectionGadgets/src/com/siyeh/ig/bugs/CollectionUpdateCalledVisitor.java new file mode 100644 index 000000000000..23181345fc1d --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/bugs/CollectionUpdateCalledVisitor.java @@ -0,0 +1,71 @@ +package com.siyeh.ig.bugs; + +import com.intellij.psi.*; + +import java.util.Set; +import java.util.HashSet; + +public class CollectionUpdateCalledVisitor extends PsiRecursiveElementVisitor { + private static Set updateNames = new HashSet(10); + + static { + updateNames.add("add"); + updateNames.add("put"); + updateNames.add("set"); + updateNames.add("remove"); + updateNames.add("addAll"); + updateNames.add("removeAll"); + updateNames.add("retainAll"); + updateNames.add("putAll"); + updateNames.add("clear"); + } + + private boolean updated = false; + private final PsiVariable variable; + + public CollectionUpdateCalledVisitor(PsiVariable variable) { + super(); + this.variable = variable; + } + + public void visitReferenceExpression(PsiReferenceExpression exp) { + final PsiExpression qualifier = exp.getQualifierExpression(); + if (qualifier != null) { + qualifier.accept(this); + } + final PsiReferenceParameterList typeParameters = exp.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 PsiExpression qualifier = methodExpression.getQualifierExpression(); + if (qualifier == null) { + return; + } + if (!(qualifier instanceof PsiReferenceExpression)) { + return; + } + final PsiElement referent = ((PsiReference) qualifier).resolve(); + if (referent == null) { + return; + } + if (!referent.equals(variable)) { + return; + } + final String methodName = methodExpression.getReferenceName(); + if (updateNames.contains(methodName)) { + updated = true; + } + } + + public boolean isUpdated() { + return updated; + } +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/bugs/CompareToUsesNonFinalVariableInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/bugs/CompareToUsesNonFinalVariableInspection.java new file mode 100644 index 000000000000..60933a43b507 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/bugs/CompareToUsesNonFinalVariableInspection.java @@ -0,0 +1,83 @@ +package com.siyeh.ig.bugs; + +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 CompareToUsesNonFinalVariableInspection extends ExpressionInspection { + + public String getDisplayName() { + return "Non-final field referenced in 'compareTo()'"; + } + + public String getGroupDisplayName() { + return GroupNames.BUGS_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "Non-final field #ref accessed in compareTo() #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new CompareToUsesNonFinalVariableVisitor(this, inspectionManager, onTheFly); + } + + private static class CompareToUsesNonFinalVariableVisitor extends BaseInspectionVisitor { + private boolean m_inCompareTo = false; + + private CompareToUsesNonFinalVariableVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitReferenceExpression(PsiReferenceExpression expression) { + super.visitReferenceExpression(expression); + if (!m_inCompareTo) { + return; + } + final PsiElement element = expression.resolve(); + if (!(element instanceof PsiField)) { + return; + } + final PsiField field = (PsiField) element; + if (field.hasModifierProperty(PsiModifier.FINAL)) { + return; + } + registerError(expression); + } + + public void visitMethod(PsiMethod method) { + final boolean isCompareTo = isCompareTo(method); + if (isCompareTo) { + m_inCompareTo = true; + } + + super.visitMethod(method); + if (isCompareTo) { + m_inCompareTo = false; + } + } + + private static boolean isCompareTo(PsiMethod method) { + final String methodName = method.getName(); + if (!"compareTo".equals(methodName)) { + return false; + } + final PsiParameterList parameterList = method.getParameterList(); + if (parameterList == null) { + return false; + } + final PsiParameter[] parameters = parameterList.getParameters(); + if (parameters == null || parameters.length != 1) { + return false; + } + final PsiType returnType = method.getReturnType(); + return TypeUtils.typeEquals("int", returnType); + } + + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/bugs/ComparisonOfShortAndCharInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/bugs/ComparisonOfShortAndCharInspection.java new file mode 100644 index 000000000000..826406cf9d88 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/bugs/ComparisonOfShortAndCharInspection.java @@ -0,0 +1,55 @@ +package com.siyeh.ig.bugs; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.psi.PsiBinaryExpression; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiExpression; +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.ComparisonUtils; +import com.siyeh.ig.psiutils.TypeUtils; + +public class ComparisonOfShortAndCharInspection extends ExpressionInspection { + + public String getDisplayName() { + return "Comparison of short and char values"; + } + + public String getGroupDisplayName() { + return GroupNames.BUGS_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "Equality comparison (#ref) of short and char values #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new ComparisonOfShortAndCharVisitor(this, inspectionManager, onTheFly); + } + + private static class ComparisonOfShortAndCharVisitor extends BaseInspectionVisitor { + private static final String SHORT = "short"; + private static final String CHAR = "char"; + + private ComparisonOfShortAndCharVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitBinaryExpression(PsiBinaryExpression expression) { + super.visitBinaryExpression(expression); + if (!ComparisonUtils.isEqualityComparison(expression)) { + return; + } + final PsiExpression lhs = expression.getLOperand(); + final PsiExpression rhs = expression.getROperand(); + if (TypeUtils.expressionHasType(SHORT, lhs) && TypeUtils.expressionHasType(CHAR, rhs)) { + registerError(expression); + } else if (TypeUtils.expressionHasType(CHAR, lhs) && TypeUtils.expressionHasType(SHORT, rhs)) { + registerError(expression); + } + } + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/bugs/CovariantCompareToInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/bugs/CovariantCompareToInspection.java new file mode 100644 index 000000000000..c8ea8cd7cbad --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/bugs/CovariantCompareToInspection.java @@ -0,0 +1,100 @@ +package com.siyeh.ig.bugs; + +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.MethodInspection; +import com.siyeh.ig.psiutils.TypeUtils; + +public class CovariantCompareToInspection extends MethodInspection { + private static final String COMPARE_TO_METHOD_NAME = "compareTo"; + + public String getDisplayName() { + return "Covariant compareTo()"; + } + + public String getGroupDisplayName() { + return GroupNames.BUGS_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "#ref should take Object as it's argument #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new CovariantCompareToVisitor(this, inspectionManager, onTheFly); + } + + private static class CovariantCompareToVisitor extends BaseInspectionVisitor { + + private CovariantCompareToVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitMethod(PsiMethod method) { + // note: no call to super + final String name = method.getName(); + if (!COMPARE_TO_METHOD_NAME.equals(name)) { + return; + } + if (!method.hasModifierProperty(PsiModifier.PUBLIC)) { + return; + } + final PsiParameterList paramList = method.getParameterList(); + if (paramList == null) { + return; + } + final PsiParameter[] parameters = paramList.getParameters(); + if (parameters.length != 1) { + return; + } + final PsiType argType = parameters[0].getType(); + if (TypeUtils.isJavaLangObject(argType)) { + return; + } + final PsiClass aClass = method.getContainingClass(); + if (aClass == null) { + return; + } + final PsiMethod[] methods = aClass.getMethods(); + for (int i = 0; i < methods.length; i++) { + if (isNonVariantCompareTo(methods[i])) { + return; + } + } + final PsiClassType[] implementsListTypes = aClass.getImplementsListTypes(); + for (int i = 0; i < implementsListTypes.length; i++) { + final PsiClassType implementedType = implementsListTypes[i]; + final String implementedClassName = implementedType.getClassName(); + if (("java.lang.Comparable".equals(implementedClassName) || + "Comparable".equals(implementedClassName) + ) + && implementedType.hasParameters()) { + return; + } + } + registerMethodError(method); + } + + private static boolean isNonVariantCompareTo(PsiMethod method) { + final String methodName = method.getName(); + if (!COMPARE_TO_METHOD_NAME.equals(methodName)) { + return false; + } + final PsiParameterList paramList = method.getParameterList(); + if (paramList == null) { + return false; + } + final PsiParameter[] parameters = paramList.getParameters(); + if (parameters.length != 1) { + return false; + } + final PsiType argType = parameters[0].getType(); + return TypeUtils.isJavaLangObject(argType); + } + + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/bugs/CovariantEqualsInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/bugs/CovariantEqualsInspection.java new file mode 100644 index 000000000000..6cb1299f339d --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/bugs/CovariantEqualsInspection.java @@ -0,0 +1,90 @@ +package com.siyeh.ig.bugs; + +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.MethodInspection; +import com.siyeh.ig.psiutils.TypeUtils; + +public class CovariantEqualsInspection extends MethodInspection { + + public String getDisplayName() { + return "Covariant equals()"; + } + + public String getGroupDisplayName() { + return GroupNames.BUGS_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "#ref should take Object as it's argument #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new CovariantEqualsVisitor(this, inspectionManager, onTheFly); + } + + private static class CovariantEqualsVisitor extends BaseInspectionVisitor { + private static final String EQUALS_METHOD_NAME = "equals"; + + private CovariantEqualsVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitMethod(PsiMethod method) { + // note: no call to super + final String name = method.getName(); + if (!EQUALS_METHOD_NAME.equals(name)) { + return; + } + if (!method.hasModifierProperty(PsiModifier.PUBLIC)) { + return; + } + final PsiParameterList paramList = method.getParameterList(); + if (paramList == null) { + return; + } + final PsiParameter[] parameters = paramList.getParameters(); + if (parameters.length != 1) { + return; + } + final PsiType argType = parameters[0].getType(); + if (TypeUtils.isJavaLangObject(argType)) { + return; + } + final PsiClass aClass = method.getContainingClass(); + if (aClass == null) { + return; + } + final PsiMethod[] methods = aClass.getMethods(); + for (int i = 0; i < methods.length; i++) { + if (isNonVariantEquals(methods[i])) { + return; + } + } + registerMethodError(method); + + } + + private static boolean isNonVariantEquals(PsiMethod method) { + final String name = method.getName(); + if (!EQUALS_METHOD_NAME.equals(name)) { + return false; + } + final PsiParameterList paramList = method.getParameterList(); + if (paramList == null) { + return false; + } + final PsiParameter[] parameters = paramList.getParameters(); + if (parameters.length != 1) { + return false; + } + final PsiType argType = parameters[0].getType(); + return TypeUtils.isJavaLangObject(argType); + } + + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/bugs/DefaultNotLastCaseInSwitchInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/bugs/DefaultNotLastCaseInSwitchInspection.java new file mode 100644 index 000000000000..c621735ab1e7 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/bugs/DefaultNotLastCaseInSwitchInspection.java @@ -0,0 +1,58 @@ +package com.siyeh.ig.bugs; + +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 DefaultNotLastCaseInSwitchInspection extends StatementInspection { + + public String getDisplayName() { + return "'default' not last case in 'switch'"; + } + + public String getGroupDisplayName() { + return GroupNames.BUGS_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "'#ref' branch not last case in 'switch' #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new DefaultNotLastCaseInSwitchVisitor(this, inspectionManager, onTheFly); + } + + private static class DefaultNotLastCaseInSwitchVisitor extends BaseInspectionVisitor { + private DefaultNotLastCaseInSwitchVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitSwitchStatement(PsiSwitchStatement statement) { + super.visitSwitchStatement(statement); + final PsiCodeBlock body = statement.getBody(); + if (body == null) { + return; + } + final PsiStatement[] statements = body.getStatements(); + boolean labelSeen = false; + for (int i = statements.length - 1; i >= 0; i--) { + final PsiStatement child = statements[i]; + if (child instanceof PsiSwitchLabelStatement) { + final PsiSwitchLabelStatement label = (PsiSwitchLabelStatement) child; + if (label.isDefaultCase()) { + if (labelSeen) { + registerStatementError(label); + } + return; + } else { + labelSeen = true; + } + } + } + } + } + +} \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/bugs/EmptyInitializerInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/bugs/EmptyInitializerInspection.java new file mode 100644 index 000000000000..56cfe0405fa9 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/bugs/EmptyInitializerInspection.java @@ -0,0 +1,51 @@ +package com.siyeh.ig.bugs; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.psi.PsiClassInitializer; +import com.intellij.psi.PsiCodeBlock; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiStatement; +import com.siyeh.ig.BaseInspection; +import com.siyeh.ig.BaseInspectionVisitor; +import com.siyeh.ig.GroupNames; +import com.siyeh.ig.StatementInspection; + +public class EmptyInitializerInspection extends StatementInspection { + + public String getDisplayName() { + return "Empty class initializer"; + } + + public String getGroupDisplayName() { + return GroupNames.BUGS_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "Empty class initializer #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new EmptyInitializerVisitor(this, inspectionManager, onTheFly); + } + + private static class EmptyInitializerVisitor extends BaseInspectionVisitor { + private EmptyInitializerVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitClassInitializer(PsiClassInitializer initializer) { + super.visitClassInitializer(initializer); + final PsiCodeBlock body = initializer.getBody(); + if (!codeBlockIsEmpty(body)) { + return; + } + registerError(body.getLBrace()); + } + + + private static boolean codeBlockIsEmpty(PsiCodeBlock codeBlock) { + final PsiStatement[] statements = codeBlock.getStatements(); + return statements.length == 0; + } + } +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/bugs/EmptyStatementBodyInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/bugs/EmptyStatementBodyInspection.java new file mode 100644 index 000000000000..d0a2d15ac752 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/bugs/EmptyStatementBodyInspection.java @@ -0,0 +1,131 @@ +package com.siyeh.ig.bugs; + +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; +import com.siyeh.ig.ui.SingleCheckboxOptionsPanel; + +import javax.swing.*; + +public class EmptyStatementBodyInspection extends StatementInspection { + public boolean m_reportEmptyBlocks = false; + + public String getDisplayName() { + return "Statement with empty body"; + } + + public String getGroupDisplayName() { + return GroupNames.BUGS_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "#ref statement has empty body #loc"; + } + + public JComponent createOptionsPanel() { + return new SingleCheckboxOptionsPanel("Include statement bodies that are empty code blocks", + this, "m_reportEmptyBlocks"); + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new EmptyStatementVisitor(this, inspectionManager, onTheFly); + } + + private class EmptyStatementVisitor extends BaseInspectionVisitor { + private EmptyStatementVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitDoWhileStatement(PsiDoWhileStatement statement) { + super.visitDoWhileStatement(statement); + final PsiStatement body = statement.getBody(); + if (body == null) { + return; + } + if (!isEmpty(body)) { + return; + } + registerStatementError(statement); + } + + public void visitWhileStatement(PsiWhileStatement statement) { + super.visitWhileStatement(statement); + final PsiStatement body = statement.getBody(); + if (body == null) { + return; + } + if (!isEmpty(body)) { + return; + } + registerStatementError(statement); + } + + public void visitForStatement(PsiForStatement statement) { + super.visitForStatement(statement); + + final PsiStatement body = statement.getBody(); + if (body == null) { + return; + } + if (!isEmpty(body)) { + return; + } + registerStatementError(statement); + } + + public void visitForeachStatement(PsiForeachStatement statement) { + super.visitForeachStatement(statement); + + final PsiStatement body = statement.getBody(); + if (body == null) { + return; + } + if (!isEmpty(body)) { + return; + } + registerStatementError(statement); + } + + public void visitIfStatement(PsiIfStatement statement) { + super.visitIfStatement(statement); + final PsiStatement thenBranch = statement.getThenBranch(); + if (thenBranch != null) { + if (isEmpty(thenBranch)) { + registerStatementError(statement); + return; + } + } + final PsiStatement elseBranch = statement.getElseBranch(); + + if (elseBranch != null) { + if (isEmpty(elseBranch)) { + final PsiElement elseToken = statement.getElseElement(); + registerError(elseToken); + return; + } + } + } + + private boolean isEmpty(PsiElement body) { + if (body instanceof PsiEmptyStatement) { + return true; + } else if (m_reportEmptyBlocks && body instanceof PsiBlockStatement) { + final PsiBlockStatement block = (PsiBlockStatement) body; + final PsiCodeBlock codeBlock = block.getCodeBlock(); + return codeBlockIsEmpty(codeBlock); + } else if (body instanceof PsiCodeBlock) { + final PsiCodeBlock codeBlock = (PsiCodeBlock) body; + return codeBlockIsEmpty(codeBlock); + } + return false; + } + + private boolean codeBlockIsEmpty(PsiCodeBlock codeBlock) { + final PsiStatement[] statements = codeBlock.getStatements(); + return statements.length == 0; + } + } +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/bugs/EqualsBetweenInconvertibleTypesInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/bugs/EqualsBetweenInconvertibleTypesInspection.java new file mode 100644 index 000000000000..62aa29f86a1a --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/bugs/EqualsBetweenInconvertibleTypesInspection.java @@ -0,0 +1,97 @@ +package com.siyeh.ig.bugs; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.psi.*; +import com.intellij.psi.util.TypeConversionUtil; +import com.siyeh.ig.BaseInspection; +import com.siyeh.ig.BaseInspectionVisitor; +import com.siyeh.ig.ExpressionInspection; +import com.siyeh.ig.GroupNames; + +public class EqualsBetweenInconvertibleTypesInspection extends ExpressionInspection { + + public String getDisplayName() { + return "equals() between objects of inconvertible types"; + } + + public String getGroupDisplayName() { + return GroupNames.BUGS_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + final PsiReferenceExpression methodExpression = (PsiReferenceExpression) location.getParent(); + final PsiMethodCallExpression expression = + (PsiMethodCallExpression) methodExpression.getParent(); + final PsiExpressionList argumentList = expression.getArgumentList(); + + final PsiExpression[] args = argumentList.getExpressions(); + final PsiType comparedType = args[0].getType(); + final PsiExpression qualifier = methodExpression.getQualifierExpression(); + final PsiType comparisonType = qualifier.getType(); + + return "#ref() between objects of inconvertible types " + + comparisonType.getPresentableText() + " and " + + comparedType.getPresentableText() + " #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new EqualsBetweenInconvertibleTypesVisitor(this, inspectionManager, onTheFly); + } + + private static class EqualsBetweenInconvertibleTypesVisitor extends BaseInspectionVisitor { + private EqualsBetweenInconvertibleTypesVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitMethodCallExpression(PsiMethodCallExpression expression) { + super.visitMethodCallExpression(expression); + final PsiReferenceExpression methodExpression = expression.getMethodExpression(); + if (methodExpression == null) { + return; + } + final String methodName = methodExpression.getReferenceName(); + if (!"equals".equals(methodName)) { + return; + } + final PsiExpressionList argumentList = expression.getArgumentList(); + if (argumentList == null) { + return; + } + final PsiExpression[] args = argumentList.getExpressions(); + if (args == null) { + return; + } + if (args.length != 1) { + return; + } + final PsiExpression arg = args[0]; + final PsiExpression qualifier = methodExpression.getQualifierExpression(); + if (!areIncompatibleTypes(arg, qualifier)) { + return; + } + registerMethodCallError(expression); + } + + private static boolean areIncompatibleTypes(PsiExpression exp1, PsiExpression exp2) { + if (exp1 == null) { + return false; + } + final PsiType comparedType = exp1.getType(); + if (comparedType == null) { + return false; + } + if (exp2 == null) { + return false; + } + final PsiType comparisonType = exp2.getType(); + if (comparisonType == null) { + return false; + } + if (TypeConversionUtil.areTypesConvertible(comparedType, comparisonType)) { + return false; + } + return true; + } + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/bugs/EqualsUsesNonFinalVariableInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/bugs/EqualsUsesNonFinalVariableInspection.java new file mode 100644 index 000000000000..b2a9c78fafbd --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/bugs/EqualsUsesNonFinalVariableInspection.java @@ -0,0 +1,88 @@ +package com.siyeh.ig.bugs; + +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 EqualsUsesNonFinalVariableInspection extends ExpressionInspection { + + public String getDisplayName() { + return "Non-final field referenced in 'equals()'"; + } + + public String getGroupDisplayName() { + return GroupNames.BUGS_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "Non-final field #ref accessed in equals() #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new EqualsUsesNonFinalVariableVisitor(this, inspectionManager, onTheFly); + } + + private static class EqualsUsesNonFinalVariableVisitor extends BaseInspectionVisitor { + private boolean m_inEquals = false; + + private EqualsUsesNonFinalVariableVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitReferenceExpression(PsiReferenceExpression expression) { + super.visitReferenceExpression(expression); + if (!m_inEquals) { + return; + } + final PsiElement element = expression.resolve(); + if (!(element instanceof PsiField)) { + return; + } + final PsiField field = (PsiField) element; + if (field.hasModifierProperty(PsiModifier.FINAL)) { + return; + } + registerError(expression); + } + + public void visitMethod(PsiMethod method) { + final boolean isEquals = isEqualsMethod(method); + if (isEquals) { + m_inEquals = true; + } + + super.visitMethod(method); + if (isEquals) { + m_inEquals = false; + } + } + + private static boolean isEqualsMethod(PsiMethod method) { + final String methodName = method.getName(); + if (!"equals".equals(methodName)) { + return false; + } + final PsiParameterList parameterList = method.getParameterList(); + if (parameterList == null) { + return false; + } + final PsiParameter[] parameters = parameterList.getParameters(); + if (parameters == null || parameters.length != 1) { + return false; + } + final PsiType returnType = method.getReturnType(); + if (returnType == null) { + return false; + } + if (!returnType.equals(PsiType.BOOLEAN)) { + return false; + } + return true; + } + + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/bugs/FallthruInSwitchStatementInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/bugs/FallthruInSwitchStatementInspection.java new file mode 100644 index 000000000000..85809ea8995b --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/bugs/FallthruInSwitchStatementInspection.java @@ -0,0 +1,56 @@ +package com.siyeh.ig.bugs; + +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; +import com.siyeh.ig.psiutils.ControlFlowUtils; + +public class FallthruInSwitchStatementInspection extends StatementInspection { + + public String getDisplayName() { + return "Fallthrough in 'switch' statement"; + } + + public String getGroupDisplayName() { + return GroupNames.BUGS_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "#ref fallthrough in 'switch' statement #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new FallthroughInSwitchStatementVisitor(this, inspectionManager, onTheFly); + } + + private static class FallthroughInSwitchStatementVisitor extends BaseInspectionVisitor { + private FallthroughInSwitchStatementVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitSwitchStatement(PsiSwitchStatement statement) { + super.visitSwitchStatement(statement); + boolean switchLabelValid = true; + final PsiCodeBlock body = statement.getBody(); + if (body == null) { + return; + } + final PsiStatement[] statements = body.getStatements(); + for (int i = 0; i < statements.length; i++) { + final PsiStatement child = statements[i]; + if (child instanceof PsiSwitchLabelStatement) { + if (!switchLabelValid) { + registerError(child); + } + switchLabelValid = true; + } else { + switchLabelValid = !ControlFlowUtils.statementMayCompleteNormally(child); + } + } + } + } + +} \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/bugs/FloatingPointEqualityInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/bugs/FloatingPointEqualityInspection.java new file mode 100644 index 000000000000..35ef8c2a6024 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/bugs/FloatingPointEqualityInspection.java @@ -0,0 +1,70 @@ +package com.siyeh.ig.bugs; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.psi.*; +import com.intellij.psi.tree.IElementType; +import com.intellij.psi.util.TypeConversionUtil; +import com.siyeh.ig.BaseInspection; +import com.siyeh.ig.BaseInspectionVisitor; +import com.siyeh.ig.ExpressionInspection; +import com.siyeh.ig.GroupNames; + +public class FloatingPointEqualityInspection extends ExpressionInspection { + + public String getDisplayName() { + return "Floating point equality comparison"; + } + + public String getGroupDisplayName() { + return GroupNames.BUGS_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "#ref: floating point values compared for exact equality #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new FloatingPointEqualityComparisonVisitor(this, inspectionManager, onTheFly); + } + + private static class FloatingPointEqualityComparisonVisitor extends BaseInspectionVisitor { + private FloatingPointEqualityComparisonVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitBinaryExpression(PsiBinaryExpression expression) { + super.visitBinaryExpression(expression); + final PsiJavaToken sign = expression.getOperationSign(); + if (sign == null) { + return; + } + final IElementType tokenType = sign.getTokenType(); + if (!(tokenType.equals(JavaTokenType.EQEQ) || + tokenType.equals(JavaTokenType.NE))) { + return; + } + final PsiExpression lhs = expression.getLOperand(); + if (isFloatingPointType(lhs)) { + registerError(expression); + return; + } + final PsiExpression rhs = expression.getROperand(); + if (isFloatingPointType(rhs)) { + registerError(expression); + return; + } + } + + private static boolean isFloatingPointType(PsiExpression expression) { + if(expression == null) + { + return false; + } + final PsiType type = expression.getType(); + return TypeConversionUtil.isDoubleType(type) || + TypeConversionUtil.isFloatType(type); + + } + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/bugs/ForLoopThatDoesntUseLoopVariableInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/bugs/ForLoopThatDoesntUseLoopVariableInspection.java new file mode 100644 index 000000000000..479a34714b0c --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/bugs/ForLoopThatDoesntUseLoopVariableInspection.java @@ -0,0 +1,162 @@ +package com.siyeh.ig.bugs; + +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; + +import java.util.ArrayList; +import java.util.List; + +public class ForLoopThatDoesntUseLoopVariableInspection extends StatementInspection { + + public String getDisplayName() { + return "For loop where update or condition doesn't use loop variable"; + } + + public String getGroupDisplayName() { + return GroupNames.BUGS_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + final List compenentsMissing = new ArrayList(3); + final PsiJavaToken forToken = (PsiJavaToken) location; + final PsiForStatement forStatement = (PsiForStatement) forToken.getParent(); + + if (!conditionUsesInitializer(forStatement)) { + compenentsMissing.add("condition"); + } + if (!updateUsesInitializer(forStatement)) { + compenentsMissing.add("update"); + } + final String missingComponents; + final String doString; + if (compenentsMissing.size() == 1) { + missingComponents = (String) compenentsMissing.get(0); + doString = "does"; + } else { + missingComponents = compenentsMissing.get(0) + " and " + compenentsMissing.get(1); + doString = "do"; + } + return "#ref statement has " + missingComponents + " which " + doString + " not use the for loop variable #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new ForLoopThatDoesntUseLoopVariableVisitor(this, inspectionManager, onTheFly); + } + + private static class ForLoopThatDoesntUseLoopVariableVisitor extends BaseInspectionVisitor { + private ForLoopThatDoesntUseLoopVariableVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitForStatement(PsiForStatement statement) { + super.visitForStatement(statement); + + if (conditionUsesInitializer(statement) + && updateUsesInitializer(statement)) { + return; + } + registerStatementError(statement); + } + } + + private static boolean conditionUsesInitializer(PsiForStatement statement) { + final PsiStatement initialization = statement.getInitialization(); + final PsiExpression condition = statement.getCondition(); + + if (initialization == null) { + return true; + } + if (condition == null) { + return true; + } + if (!(initialization instanceof PsiDeclarationStatement)) { + return true; + } + final PsiDeclarationStatement declaration = (PsiDeclarationStatement) initialization; + + final PsiElement[] declaredElements = declaration.getDeclaredElements(); + + if (declaredElements == null || declaredElements.length != 1) { + return true; + } + if (declaredElements[0] == null || !(declaredElements[0] instanceof PsiLocalVariable)) { + return true; + } + final PsiLocalVariable localVar = (PsiLocalVariable) declaredElements[0]; + return expressionUsesVariable(condition, localVar); + } + + private static boolean updateUsesInitializer(PsiForStatement statement) { + final PsiStatement initialization = statement.getInitialization(); + final PsiStatement update = statement.getUpdate(); + + if (initialization == null) { + return true; + } + if (update == null) { + return true; + } + if (!(initialization instanceof PsiDeclarationStatement)) { + return true; + } + final PsiDeclarationStatement declaration = (PsiDeclarationStatement) initialization; + + final PsiElement[] declaredElements = declaration.getDeclaredElements(); + + if (declaredElements == null || declaredElements.length != 1) { + return true; + } + if (declaredElements[0] == null || !(declaredElements[0] instanceof PsiLocalVariable)) { + return true; + } + + final PsiLocalVariable localVar = (PsiLocalVariable) declaredElements[0]; + return statementUsesVariable(update, localVar); + } + + private static boolean statementUsesVariable(PsiStatement statement, PsiLocalVariable localVar) { + final UseVisitor useVisitor = new UseVisitor(localVar); + statement.accept(useVisitor); + return useVisitor.isUsed(); + } + + private static boolean expressionUsesVariable(PsiExpression expression, PsiLocalVariable localVar) { + final UseVisitor useVisitor = new UseVisitor(localVar); + expression.accept(useVisitor); + return useVisitor.isUsed(); + } + + private static class UseVisitor extends PsiRecursiveElementVisitor { + private final PsiLocalVariable m_variable; + private boolean m_used = false; + + private UseVisitor(PsiLocalVariable var) { + super(); + m_variable = var; + } + + 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 resolvedElement = ref.resolve(); + if (m_variable.equals(resolvedElement)) { + m_used = true; + } + } + + private boolean isUsed() { + return m_used; + } + + } +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/bugs/ForLoopWithMissingComponentInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/bugs/ForLoopWithMissingComponentInspection.java new file mode 100644 index 000000000000..65881bae4782 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/bugs/ForLoopWithMissingComponentInspection.java @@ -0,0 +1,83 @@ +package com.siyeh.ig.bugs; + +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; + +import java.util.ArrayList; +import java.util.List; + +public class ForLoopWithMissingComponentInspection extends StatementInspection { + + public String getDisplayName() { + return "For loop with missing components"; + } + + public String getGroupDisplayName() { + return GroupNames.BUGS_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + final List components = new ArrayList(3); + final PsiJavaToken forToken = (PsiJavaToken) location; + final PsiForStatement forStatement = (PsiForStatement) forToken.getParent(); + + if (!hasInitializer(forStatement)) { + components.add("initializer"); + } + if (!hasCondition(forStatement)) { + components.add("condition"); + } + if (!hasUpdate(forStatement)) { + components.add("update"); + } + final String missingComponents; + if (components.size() == 1) { + missingComponents = (String) components.get(0); + } else if (components.size() == 2) { + missingComponents = components.get(0) + " and " + components.get(1); + } else { + missingComponents = components.get(0) + ", " + components.get(1) + " and " + components.get(2); + } + return "#ref statement lacks " + missingComponents + " #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new ForLoopWithMissingComponentVisitor(this, inspectionManager, onTheFly); + } + + private static class ForLoopWithMissingComponentVisitor extends BaseInspectionVisitor { + private ForLoopWithMissingComponentVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitForStatement(PsiForStatement statement) { + super.visitForStatement(statement); + + if (hasCondition(statement) + && hasInitializer(statement) + && hasUpdate(statement)) { + return; + } + registerStatementError(statement); + } + } + + private static boolean hasCondition(PsiForStatement statement) { + return statement.getCondition() != null; + } + + private static boolean hasInitializer(PsiForStatement statement) { + final PsiStatement initialization = statement.getInitialization(); + return initialization != null && !(initialization instanceof PsiEmptyStatement); + } + + private static boolean hasUpdate(PsiForStatement statement) { + final PsiStatement update = statement.getUpdate(); + return update != null && !(update instanceof PsiEmptyStatement); + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/bugs/HashCodeUsesNonFinalVariableInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/bugs/HashCodeUsesNonFinalVariableInspection.java new file mode 100644 index 000000000000..e077b3e13d94 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/bugs/HashCodeUsesNonFinalVariableInspection.java @@ -0,0 +1,88 @@ +package com.siyeh.ig.bugs; + +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 HashCodeUsesNonFinalVariableInspection extends ExpressionInspection { + + public String getDisplayName() { + return "Non-final field referenced in 'hashCode()'"; + } + + public String getGroupDisplayName() { + return GroupNames.BUGS_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "Non-final field #ref accessed in hashCode() #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new HashCodeUsesNonFinalVariableVisitor(this, inspectionManager, onTheFly); + } + + private static class HashCodeUsesNonFinalVariableVisitor extends BaseInspectionVisitor { + private boolean m_inHashcode = false; + + private HashCodeUsesNonFinalVariableVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitReferenceExpression(PsiReferenceExpression expression) { + super.visitReferenceExpression(expression); + if (!m_inHashcode) { + return; + } + final PsiElement element = expression.resolve(); + if (!(element instanceof PsiField)) { + return; + } + final PsiField field = (PsiField) element; + if (field.hasModifierProperty(PsiModifier.FINAL)) { + return; + } + registerError(expression); + } + + public void visitMethod(PsiMethod method) { + final boolean isHashCode = isHashCode(method); + if (isHashCode) { + m_inHashcode = true; + } + + super.visitMethod(method); + if (isHashCode) { + m_inHashcode = false; + } + } + + private static boolean isHashCode(PsiMethod method) { + final String methodName = method.getName(); + if (!"hashCode".equals(methodName)) { + return false; + } + final PsiParameterList parameterList = method.getParameterList(); + if (parameterList == null) { + return false; + } + final PsiParameter[] parameters = parameterList.getParameters(); + if (parameters == null || parameters.length != 0) { + return false; + } + final PsiType returnType = method.getReturnType(); + if (returnType == null) { + return false; + } + if (!returnType.equals(PsiType.INT)) { + return false; + } + return true; + } + + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/bugs/IgnoreResultOfCallInspection.form b/plugins/InspectionGadgets/src/com/siyeh/ig/bugs/IgnoreResultOfCallInspection.form new file mode 100644 index 000000000000..620f2db837d7 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/bugs/IgnoreResultOfCallInspection.form @@ -0,0 +1,46 @@ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/bugs/IgnoreResultOfCallInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/bugs/IgnoreResultOfCallInspection.java new file mode 100644 index 000000000000..14981d9d140a --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/bugs/IgnoreResultOfCallInspection.java @@ -0,0 +1,241 @@ +package com.siyeh.ig.bugs; + +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 com.siyeh.ig.psiutils.ClassUtils; +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; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class IgnoreResultOfCallInspection extends ExpressionInspection { + public String callCheckString = "java.io.InputStream,read," + + "java.io.InputStream,skip," + + "java.lang.StringBuffer,toString," + + "java.lang.StringBuilder,toString," + + "java.lang.String,.*," + + "java.math.BigInteger,.*," + + "java.math.BigDecimal,.*," + + "java.net.InetAddress,.*"; + + private List callsToCheck = new ArrayList(32); + + { + parseCallCheckString(); + } + + public void readSettings(Element element) throws InvalidDataException { + super.readSettings(element); + parseCallCheckString(); + } + + private void parseCallCheckString() { + callsToCheck.clear(); + final String[] strings = callCheckString.split(","); + for (int i = 0; i < strings.length; i += 2) { + final String className = strings[i]; + final String methodName = strings[i + 1]; + callsToCheck.add(new ReturnCheckSpecification(className, methodName)); + } + } + + 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 = callsToCheck.iterator(); iterator.hasNext();) { + if (first) { + first = false; + } else { + buffer.append(','); + } + final ReturnCheckSpecification returnCheckSpecification = + (ReturnCheckSpecification) iterator.next(); + final String methodName = returnCheckSpecification.getMethodName(); + final String className = returnCheckSpecification.getClassName(); + buffer.append(className); + buffer.append(','); + buffer.append(methodName); + } + callCheckString = buffer.toString(); + } + + public String getDisplayName() { + return "Result of method call ignored"; + } + + public String getGroupDisplayName() { + return GroupNames.BUGS_GROUP_NAME; + } + + public JComponent createOptionsPanel() { + final Form form = new Form(); + return form.getContentPanel(); + } + + public String buildErrorString(PsiElement location) { + final PsiElement parent = location.getParent(); + final PsiMethodCallExpression methodCallExpression = (PsiMethodCallExpression) parent.getParent(); + final PsiMethod method = methodCallExpression.resolveMethod(); + final PsiClass containingClass = method.getContainingClass(); + final String className = containingClass.getName(); + return "result of " + className + ".#ref() is ignored. #loc "; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new IgnoreResultOfCallVisitor(this, inspectionManager, onTheFly); + } + + private class IgnoreResultOfCallVisitor extends BaseInspectionVisitor { + private IgnoreResultOfCallVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitExpressionStatement(PsiExpressionStatement statement) { + super.visitExpressionStatement(statement); + if (!(statement.getExpression() instanceof PsiMethodCallExpression)) { + return; + } + final PsiMethodCallExpression call = (PsiMethodCallExpression) statement.getExpression(); + final PsiReferenceExpression methodExpression = call.getMethodExpression(); + final String methodName = methodExpression.getReferenceName(); + if (methodName == null) { + return; + } + + final PsiMethod method = call.resolveMethod(); + if (method == null) { + return; + } + final PsiClass aClass = method.getContainingClass(); + if (aClass == null) { + return; + } + + for (Iterator iterator = callsToCheck.iterator(); iterator.hasNext();) { + final ReturnCheckSpecification spec = (ReturnCheckSpecification) iterator.next(); + final Pattern methodNamePattern = spec.getMethodNamePattern(); + if (methodNamePattern != null && + methodNamesMatch(methodName, methodNamePattern)) { + final String classNameToCompare = spec.getClassName(); + if (ClassUtils.isSubclass(aClass, classNameToCompare)) { + registerMethodCallError(call); + return; + } + } + } + + } + + private boolean methodNamesMatch(String methodName, Pattern methodNamePattern) { + final Matcher matcher = methodNamePattern.matcher(methodName); + return matcher.matches(); + } + + } + + 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) { + callsToCheck.add(new ReturnCheckSpecification()); + 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--) { + callsToCheck.remove(selectedRows[i]); + } + model.fireTableStructureChanged(); + } + }); + } + + public JComponent getContentPanel() { + return contentPanel; + } + } + + private class ReturnCheckSpecificationTableModel extends AbstractTableModel { + + public int getRowCount() { + return callsToCheck.size(); + } + + public int getColumnCount() { + return 2; + } + + public String getColumnName(int columnIndex) { + if (columnIndex == 0) { + return "Class name"; + } + return "Method name"; + } + + public Class getColumnClass(int columnIndex) { + return String.class; + } + + public boolean isCellEditable(int rowIndex, int columnIndex) { + return true; + } + + public Object getValueAt(int rowIndex, int columnIndex) { + final ReturnCheckSpecification spec = (ReturnCheckSpecification) callsToCheck.get(rowIndex); + if (columnIndex == 0) { + return spec.getClassName(); + } else { + return spec.getMethodName(); + } + } + + public void setValueAt(Object aValue, int rowIndex, int columnIndex) { + final ReturnCheckSpecification spec = (ReturnCheckSpecification) callsToCheck.get(rowIndex); + if (columnIndex == 0) { + spec.setClassName((String) aValue); + } else { + spec.setMethodName((String) aValue); + } + } + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/bugs/IncompatibleMaskInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/bugs/IncompatibleMaskInspection.java new file mode 100644 index 000000000000..679ad205d17c --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/bugs/IncompatibleMaskInspection.java @@ -0,0 +1,171 @@ +package com.siyeh.ig.bugs; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.psi.*; +import com.intellij.psi.tree.IElementType; +import com.intellij.psi.util.ConstantExpressionUtil; +import com.intellij.psi.util.IsConstantExpressionVisitor; +import com.siyeh.ig.BaseInspection; +import com.siyeh.ig.BaseInspectionVisitor; +import com.siyeh.ig.ExpressionInspection; +import com.siyeh.ig.GroupNames; + +public class IncompatibleMaskInspection extends ExpressionInspection { + + + public String getDisplayName() { + return "Incompatible bitwise mask operation"; + } + + public String getGroupDisplayName() { + return GroupNames.BUGS_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + final PsiBinaryExpression binaryExpression = (PsiBinaryExpression) location; + final PsiJavaToken operationSign = binaryExpression.getOperationSign(); + final IElementType tokenType = operationSign.getTokenType(); + if (tokenType.equals(JavaTokenType.EQEQ)) { + return "#ref is always false #loc"; + } else { + return "#ref is always true #loc"; + } + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new IncompatibleMaskVisitor(this, inspectionManager, onTheFly); + } + + + private static class IncompatibleMaskVisitor extends BaseInspectionVisitor { + private IncompatibleMaskVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitBinaryExpression(PsiBinaryExpression expression) { + super.visitBinaryExpression(expression); + final PsiType expressionType = expression.getType(); + if (expressionType == null) { + return; + } + final PsiJavaToken sign = expression.getOperationSign(); + if (sign == null) { + return; + } + final IElementType tokenType = sign.getTokenType(); + if (!tokenType.equals(JavaTokenType.EQEQ) && !tokenType.equals(JavaTokenType.NE)) { + return; + } + final PsiExpression rhs = expression.getROperand(); + final PsiExpression strippedRhs = stripExpression(rhs); + if (strippedRhs == null) { + return; + } + final PsiExpression lhs = expression.getLOperand(); + final PsiExpression strippedLhs = stripExpression(lhs); + if (strippedLhs == null) { + return; + } + if (isConstantMask(strippedLhs) && isConstant(strippedRhs)) { + if (isIncompatibleMask((PsiBinaryExpression) strippedLhs, strippedRhs)) { + registerError(expression); + } + } else if (isConstantMask(strippedRhs) && isConstant(strippedLhs)) { + if (isIncompatibleMask((PsiBinaryExpression) strippedRhs, strippedLhs)) { + registerError(expression); + } + } + } + + } + + private static PsiExpression stripExpression(PsiExpression exp) { + if (exp == null) { + return null; + } + if (exp instanceof PsiParenthesizedExpression) { + final PsiExpression body = + ((PsiParenthesizedExpression) exp).getExpression(); + return stripExpression(body); + } + return exp; + } + + private static boolean isIncompatibleMask(PsiBinaryExpression maskExpression, PsiExpression constantExpression) { + final PsiJavaToken sign = maskExpression.getOperationSign(); + final IElementType tokenType = sign.getTokenType(); + final Object constantValue = + ConstantExpressionUtil.computeCastTo(constantExpression, PsiType.LONG); + if (constantValue == null) { + return false; + } + final long constantLongValue = ((Long) constantValue).longValue(); + + final long constantMaskValue; + final PsiExpression maskRhs = maskExpression.getROperand(); + final PsiExpression maskLhs = maskExpression.getLOperand(); + if (isConstant(maskRhs)) { + final Object rhsValue = + ConstantExpressionUtil.computeCastTo(maskRhs, PsiType.LONG); + constantMaskValue = ((Long) rhsValue).longValue(); + } else { + final Object lhsValue = + ConstantExpressionUtil.computeCastTo(maskLhs, PsiType.LONG); + constantMaskValue = ((Long) lhsValue).longValue(); + } + + if (tokenType.equals(JavaTokenType.OR)) { + if ((constantMaskValue | constantLongValue) != constantLongValue) { + return true; + } + } + if (tokenType.equals(JavaTokenType.AND)) { + if ((constantMaskValue | constantLongValue) != constantMaskValue) { + return true; + } + } + return false; + } + + private static boolean isConstant(PsiExpression expression) { + if (expression == null) { + return false; + } + final IsConstantExpressionVisitor visitor = + new IsConstantExpressionVisitor(); + expression.accept(visitor); + if (!visitor.isConstant()) { + return false; + } + return true; + } + + private static boolean isConstantMask(PsiExpression expression) { + if (expression == null) { + return false; + } + if (!(expression instanceof PsiBinaryExpression)) { + return false; + } + + final PsiBinaryExpression binaryExpression = (PsiBinaryExpression) expression; + final PsiJavaToken sign = binaryExpression.getOperationSign(); + if (sign == null) { + return false; + } + final IElementType tokenType = sign.getTokenType(); + if (!tokenType.equals(JavaTokenType.OR) && !tokenType.equals(JavaTokenType.AND)) { + return false; + } + final PsiExpression rhs = binaryExpression.getROperand(); + if (isConstant(rhs)) { + return true; + } + final PsiExpression lhs = binaryExpression.getLOperand(); + if (isConstant(lhs)) { + return true; + } + return false; + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/bugs/InfiniteLoopStatementInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/bugs/InfiniteLoopStatementInspection.java new file mode 100644 index 000000000000..7304ec2f5f3f --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/bugs/InfiniteLoopStatementInspection.java @@ -0,0 +1,73 @@ +package com.siyeh.ig.bugs; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.psi.PsiDoWhileStatement; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiForStatement; +import com.intellij.psi.PsiWhileStatement; +import com.siyeh.ig.BaseInspection; +import com.siyeh.ig.BaseInspectionVisitor; +import com.siyeh.ig.GroupNames; +import com.siyeh.ig.StatementInspection; +import com.siyeh.ig.psiutils.ControlFlowUtils; + +public class InfiniteLoopStatementInspection extends StatementInspection { + + public String getDisplayName() { + return "Infinite loop statement"; + } + + public String getGroupDisplayName() { + return GroupNames.BUGS_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "#ref statement cannot complete without throwing an exception #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new InfiniteLoopStatementsVisitor(this, inspectionManager, onTheFly); + } + + private static class InfiniteLoopStatementsVisitor extends BaseInspectionVisitor { + private InfiniteLoopStatementsVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitForStatement(PsiForStatement statement) { + super.visitForStatement(statement); + if (ControlFlowUtils.statementMayCompleteNormally(statement)) { + return; + } + if (ControlFlowUtils.statementContainsReturn(statement)) { + return; + } + registerStatementError(statement); + } + + public void visitWhileStatement(PsiWhileStatement statement) { + + super.visitWhileStatement(statement); + if (ControlFlowUtils.statementMayCompleteNormally(statement)) { + return; + } + if (ControlFlowUtils.statementContainsReturn(statement)) { + return; + } + registerStatementError(statement); + } + + public void visitDoWhileStatement(PsiDoWhileStatement statement) { + super.visitDoWhileStatement(statement); + if (ControlFlowUtils.statementMayCompleteNormally(statement)) { + return; + } + if (ControlFlowUtils.statementContainsReturn(statement)) { + return; + } + registerStatementError(statement); + } + + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/bugs/InfiniteRecursionInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/bugs/InfiniteRecursionInspection.java new file mode 100644 index 000000000000..5f6218991e66 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/bugs/InfiniteRecursionInspection.java @@ -0,0 +1,52 @@ +package com.siyeh.ig.bugs; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiMethod; +import com.intellij.psi.PsiModifier; +import com.siyeh.ig.BaseInspection; +import com.siyeh.ig.BaseInspectionVisitor; +import com.siyeh.ig.GroupNames; +import com.siyeh.ig.MethodInspection; +import com.siyeh.ig.psiutils.RecursionUtils; + +public class InfiniteRecursionInspection extends MethodInspection { + + public String getDisplayName() { + return "Infinite recursion"; + } + + public String getGroupDisplayName() { + return GroupNames.BUGS_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "Method #ref recurses infinitely, and can only end by throw an exception #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new InfiniteRecursionVisitor(this, inspectionManager, onTheFly); + } + + private static class InfiniteRecursionVisitor extends BaseInspectionVisitor { + private InfiniteRecursionVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitMethod(PsiMethod method) { + super.visitMethod(method); + if (method.hasModifierProperty(PsiModifier.ABSTRACT)) { + return; + } + if (!RecursionUtils.methodMayRecurse(method)) { + return; + } + if (!RecursionUtils.methodMustRecurseBeforeReturning(method)) { + return; + } + registerMethodError(method); + } + + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/bugs/IntegerDivisionInFloatingPointContextInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/bugs/IntegerDivisionInFloatingPointContextInspection.java new file mode 100644 index 000000000000..d16234237f7e --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/bugs/IntegerDivisionInFloatingPointContextInspection.java @@ -0,0 +1,122 @@ +package com.siyeh.ig.bugs; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.psi.*; +import com.intellij.psi.tree.IElementType; +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.ExpectedTypeUtils; + +import java.util.Set; +import java.util.HashSet; + +public class IntegerDivisionInFloatingPointContextInspection extends ExpressionInspection { + private static final Set s_integralTypes = new HashSet(10); + + static { + s_integralTypes.add("int"); + s_integralTypes.add("long"); + s_integralTypes.add("short"); + s_integralTypes.add("byte"); + s_integralTypes.add("char"); + s_integralTypes.add("java.lang.Integer"); + s_integralTypes.add("java.lang.Long"); + s_integralTypes.add("java.lang.Short"); + s_integralTypes.add("java.lang.Byte"); + s_integralTypes.add("java.lang.Char"); + } + + public String getDisplayName() { + return "Integer division in floating point context"; + } + + public String getGroupDisplayName() { + return GroupNames.BUGS_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "#ref: integer division in floating-point context #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new FloatingPointEqualityComparisonVisitor(this, inspectionManager, onTheFly); + } + + private static class FloatingPointEqualityComparisonVisitor extends BaseInspectionVisitor { + + private FloatingPointEqualityComparisonVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitBinaryExpression(PsiBinaryExpression expression) { + super.visitBinaryExpression(expression); + final PsiJavaToken sign = expression.getOperationSign(); + if (sign == null) { + return; + } + final IElementType tokenType = sign.getTokenType(); + if (!tokenType.equals(JavaTokenType.DIV)) { + return; + } + final PsiExpression lhs = expression.getLOperand(); + if (lhs == null) { + return; + } + final PsiType lhsType = lhs.getType(); + if (!isIntegral(lhsType)) { + return; + } + final PsiExpression rhs = expression.getROperand(); + if (rhs == null) { + return; + } + final PsiType rhsType = rhs.getType(); + if (!isIntegral(rhsType)) { + return; + } + final PsiExpression context = getContainingExpression(expression); + if (context == null) { + return; + } + final PsiType contextType = ExpectedTypeUtils.findExpectedType(context); + if (contextType == null) { + return; + } + if (!(contextType.equals(PsiType.FLOAT) + || contextType.equals(PsiType.DOUBLE))) { + return; + } + registerError(expression); + } + + + private PsiExpression getContainingExpression(PsiExpression expression) { + final PsiElement parent = expression.getParent(); + if (parent == null) { + return expression; + } + if (parent instanceof PsiPrefixExpression || + parent instanceof PsiPostfixExpression || + parent instanceof PsiBinaryExpression || + parent instanceof PsiParenthesizedExpression) { + return getContainingExpression((PsiExpression) parent); + } + return expression; + } + } + + private static boolean isIntegral(PsiType type) { + + if (type == null) { + return false; + } + final String text = type.getCanonicalText(); + if (text == null) { + return false; + } + return s_integralTypes.contains(text); + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/bugs/LoopStatementsThatDontLoopInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/bugs/LoopStatementsThatDontLoopInspection.java new file mode 100644 index 000000000000..1f45b8b99d4f --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/bugs/LoopStatementsThatDontLoopInspection.java @@ -0,0 +1,96 @@ +package com.siyeh.ig.bugs; + +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; +import com.siyeh.ig.psiutils.ControlFlowUtils; + +public class LoopStatementsThatDontLoopInspection extends StatementInspection { + + public String getDisplayName() { + return "Loop statement that doesn't loop"; + } + + public String getGroupDisplayName() { + return GroupNames.BUGS_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "#ref statement doesn't loop #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new LoopStatementsThatDontLoopVisitor(this, inspectionManager, onTheFly); + } + + private static class LoopStatementsThatDontLoopVisitor extends BaseInspectionVisitor { + private LoopStatementsThatDontLoopVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitForStatement(PsiForStatement statement) { + super.visitForStatement(statement); + final PsiStatement body = statement.getBody(); + if (body == null) { + return; + } + if (ControlFlowUtils.statementMayCompleteNormally(body)) { + return; + } + if (ControlFlowUtils.statementIsContinueTarget(statement)) { + return; + } + registerStatementError(statement); + } + + public void visitForeachStatement(PsiForeachStatement statement) { + super.visitForeachStatement(statement); + final PsiStatement body = statement.getBody(); + if (body == null) { + return; + } + if (ControlFlowUtils.statementMayCompleteNormally(body)) { + return; + } + if (ControlFlowUtils.statementIsContinueTarget(statement)) { + return; + } + registerStatementError(statement); + } + + public void visitWhileStatement(PsiWhileStatement statement) { + super.visitWhileStatement(statement); + final PsiStatement body = statement.getBody(); + if (body == null) { + return; + } + if (ControlFlowUtils.statementMayCompleteNormally(body)) { + return; + } + if (ControlFlowUtils.statementIsContinueTarget(statement)) { + return; + } + registerStatementError(statement); + } + + public void visitDoWhileStatement(PsiDoWhileStatement statement) { + super.visitDoWhileStatement(statement); + final PsiStatement body = statement.getBody(); + if (body == null) { + return; + } + if (ControlFlowUtils.statementMayCompleteNormally(body)) { + return; + } + if (ControlFlowUtils.statementIsContinueTarget(statement)) { + return; + } + registerStatementError(statement); + } + + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/bugs/MismatchedArrayReadWriteInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/bugs/MismatchedArrayReadWriteInspection.java new file mode 100644 index 000000000000..a683f0a5bc91 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/bugs/MismatchedArrayReadWriteInspection.java @@ -0,0 +1,145 @@ +package com.siyeh.ig.bugs; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.psi.*; +import com.intellij.psi.util.PsiTreeUtil; +import com.siyeh.ig.*; +import com.siyeh.ig.psiutils.*; + +public class MismatchedArrayReadWriteInspection extends VariableInspection { + + public String getDisplayName() { + return "Mismatched read and write of array"; + } + + public String getGroupDisplayName() { + return GroupNames.BUGS_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + final PsiVariable variable = (PsiVariable) location.getParent(); + final PsiElement context; + if (variable instanceof PsiField) { + context = ((PsiMember) variable).getContainingClass(); + } else { + context = PsiTreeUtil.getParentOfType(variable, PsiCodeBlock.class); + } + final boolean written = arrayContentsAreWritten(variable, context); + final boolean read = arrayContentsAreRead(variable, context); + if (written) { + return "Contents of array #ref are written to, but never read #loc"; + } else if (read) { + return "Contents of array #ref are read, but never written to #loc"; + } else { + return "Contents of array #ref are neither read nor written to #loc"; + } + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new MismatchedArrayReadWriteVisitor(this, inspectionManager, onTheFly); + } + + private static class MismatchedArrayReadWriteVisitor extends BaseInspectionVisitor { + private MismatchedArrayReadWriteVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitField(PsiField field) { + super.visitField(field); + if (!field.hasModifierProperty(PsiModifier.PRIVATE)) { + return; + } + final PsiClass containingClass = field.getContainingClass(); + if (containingClass == null) { + return; + } + final PsiType type = field.getType(); + if (type.getArrayDimensions() == 0) { + return; + } + final boolean written = arrayContentsAreWritten(field, containingClass); + final boolean read = arrayContentsAreRead(field, containingClass); + if (written && read) { + return; + } + registerFieldError(field); + } + + + public void visitLocalVariable(PsiLocalVariable variable) { + super.visitLocalVariable(variable); + final PsiCodeBlock codeBlock = + (PsiCodeBlock) PsiTreeUtil.getParentOfType(variable, PsiCodeBlock.class); + if (codeBlock == null) { + return; + } + final PsiType type = variable.getType(); + if (type.getArrayDimensions() == 0) { + return; + } + final boolean written = arrayContentsAreWritten(variable, codeBlock); + final boolean read = arrayContentsAreRead(variable, codeBlock); + if (written && read) { + return; + } + registerVariableError(variable); + } + + } + + static boolean arrayContentsAreWritten(PsiVariable variable, PsiElement context) { + final PsiExpression initializer = variable.getInitializer(); + if (initializer != null && !isDefaultArrayInitializer(initializer)) { + return true; + } + if (VariableAccessUtils.variableIsAssigned(variable, context)) { + return true; + } + if (VariableAccessUtils.variableIsAssignedFrom(variable, context)) { + return true; + } + if (VariableAccessUtils.variableIsPassedAsMethodArgument(variable, context)) { + return true; + } + if (VariableAccessUtils.arrayContentsAreAssigned(variable, context)) { + return true; + } + return false; + } + + private static boolean isDefaultArrayInitializer(PsiExpression initializer) { + if (!(initializer instanceof PsiNewExpression)) { + return false; + } + final PsiNewExpression newExpression = (PsiNewExpression) initializer; + if (newExpression.getArrayInitializer() != null) { + return false; + } + return true; + } + + public static boolean arrayContentsAreRead(PsiVariable variable, PsiElement context) { + final PsiExpression initializer = variable.getInitializer(); + if (initializer != null && !isDefaultArrayInitializer(initializer)) { + return true; + } + if (VariableAccessUtils.variableIsAssigned(variable, context)) { + return true; + } + if (VariableAccessUtils.variableIsAssignedFrom(variable, context)) { + return true; + } + if (VariableAccessUtils.variableIsReturned(variable, context)) { + return true; + } + if (VariableAccessUtils.variableIsPassedAsMethodArgument(variable, context)) { + return true; + } + if (VariableAccessUtils.arrayContentsAreAccessed(variable, context)) { + return true; + } + return false; + } + + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/bugs/MismatchedCollectionQueryUpdateInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/bugs/MismatchedCollectionQueryUpdateInspection.java new file mode 100644 index 000000000000..61b5fb8174da --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/bugs/MismatchedCollectionQueryUpdateInspection.java @@ -0,0 +1,197 @@ +package com.siyeh.ig.bugs; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.psi.*; +import com.intellij.psi.util.PsiTreeUtil; +import com.siyeh.ig.*; +import com.siyeh.ig.psiutils.CollectionUtils; +import com.siyeh.ig.psiutils.VariableAssignedFromVisitor; +import com.siyeh.ig.psiutils.VariablePassedAsArgumentVisitor; +import com.siyeh.ig.psiutils.VariableReturnedVisitor; + +public class MismatchedCollectionQueryUpdateInspection extends VariableInspection { + + public String getDisplayName() { + return "Mismatched query and update of collection"; + } + + public String getGroupDisplayName() { + return GroupNames.BUGS_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + final PsiVariable variable = (PsiVariable) location.getParent(); + final PsiElement context; + if (variable instanceof PsiField) { + context = ((PsiMember) variable).getContainingClass(); + } else { + context = PsiTreeUtil.getParentOfType(variable, PsiCodeBlock.class); + } + final boolean updated = collectionContentsAreUpdated(variable, context); + final boolean queried = collectionContentsAreQueried(variable, context); + if (updated) { + return "Contents of collection #ref are updated, but never queried #loc"; + } else if (queried) { + return "Contents of collection #ref are queried, but never updated #loc"; + } else { + return "Contents of collection #ref are neither queried nor updated #loc"; + } + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new MismatchedCollectionQueryUpdateVisitor(this, inspectionManager, onTheFly); + } + + private static class MismatchedCollectionQueryUpdateVisitor extends BaseInspectionVisitor { + private MismatchedCollectionQueryUpdateVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitField(PsiField field) { + super.visitField(field); + if (!field.hasModifierProperty(PsiModifier.PRIVATE)) { + return; + } + final PsiClass containingClass = field.getContainingClass(); + if (containingClass == null) { + return; + } + final PsiType type = field.getType(); + if (!CollectionUtils.isCollectionClassOrInterface(type)) { + return; + } + final boolean written = collectionContentsAreUpdated(field, containingClass); + final boolean read = collectionContentsAreQueried(field, containingClass); + if (written && read) { + return; + } + registerFieldError(field); + } + + + public void visitLocalVariable(PsiLocalVariable variable) { + super.visitLocalVariable(variable); + + final PsiCodeBlock codeBlock = + (PsiCodeBlock) PsiTreeUtil.getParentOfType(variable, PsiCodeBlock.class); + if (codeBlock == null) { + return; + } + final PsiType type = variable.getType(); + if (!CollectionUtils.isCollectionClassOrInterface(type)) { + return; + } + final boolean written = collectionContentsAreUpdated(variable, codeBlock); + final boolean read = collectionContentsAreQueried(variable, codeBlock); + if (written && read) { + return; + } + registerVariableError(variable); + } + + } + + static boolean collectionContentsAreUpdated(PsiVariable variable, PsiElement context) { + final PsiExpression initializer = variable.getInitializer(); + if (initializer != null && !isEmptyCollectionInitializer(initializer)) { + return true; + } + if (variableIsAssigned(variable, context)) { + return true; + } + if (variableIsAssignedFrom(variable, context)) { + return true; + } + if (variableIsPassedAsMethodArgument(variable, context)) { + return true; + } + if (collectionUpdateCalled(variable, context)) { + return true; + } + return false; + } + + static boolean collectionContentsAreQueried(PsiVariable variable, PsiElement context) { + final PsiExpression initializer = variable.getInitializer(); + if (initializer != null && !isEmptyCollectionInitializer(initializer)) { + return true; + } + if (variableIsAssigned(variable, context)) { + return true; + } + if (variableIsAssignedFrom(variable, context)) { + return true; + } + if (variableIsReturned(variable, context)) { + return true; + } + if (variableIsPassedAsMethodArgument(variable, context)) { + return true; + } + if (collectionQueryCalled(variable, context)) { + return true; + } + return false; + } + + private static boolean variableIsAssignedFrom(PsiVariable variable, PsiElement context) { + final VariableAssignedFromVisitor visitor = new VariableAssignedFromVisitor(variable); + context.accept(visitor); + return visitor.isAssignedFrom(); + } + + private static boolean variableIsPassedAsMethodArgument(PsiVariable variable, PsiElement context) { + final VariablePassedAsArgumentVisitor visitor = new VariablePassedAsArgumentVisitor(variable); + context.accept(visitor); + return visitor.isPassed(); + } + + private static boolean variableIsAssigned(PsiVariable variable, PsiElement context) { + final VariableAssignedFromVisitor visitor = new VariableAssignedFromVisitor(variable); + context.accept(visitor); + return visitor.isAssignedFrom(); + } + + + private static boolean variableIsReturned(PsiVariable variable, PsiElement context) { + final VariableReturnedVisitor visitor = new VariableReturnedVisitor(variable); + context.accept(visitor); + return visitor.isReturned(); + } + + private static boolean collectionQueryCalled(PsiVariable variable, PsiElement context) { + final CollectionQueryCalledVisitor visitor = new CollectionQueryCalledVisitor(variable); + context.accept(visitor); + return visitor.isQueried(); + } + + private static boolean collectionUpdateCalled(PsiVariable variable, PsiElement context) { + final CollectionUpdateCalledVisitor visitor = new CollectionUpdateCalledVisitor(variable); + context.accept(visitor); + return visitor.isUpdated(); + } + + private static boolean isEmptyCollectionInitializer(PsiExpression initializer) { + if (!(initializer instanceof PsiNewExpression)) { + return false; + } + final PsiNewExpression newExpression = (PsiNewExpression) initializer; + final PsiExpressionList argumentList = newExpression.getArgumentList(); + if (argumentList == null) { + return false; + } + final PsiExpression[] expressions = argumentList.getExpressions(); + for (int i = 0; i < expressions.length; i++) { + final PsiExpression arg = expressions[i]; + final PsiType argType = arg.getType(); + if (argType == null) { + return false; + } + if (CollectionUtils.isCollectionClassOrInterface(argType)) { + return false; + } + } + return true; + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/bugs/MisspelledCompareToInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/bugs/MisspelledCompareToInspection.java new file mode 100644 index 000000000000..286e75b98b3c --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/bugs/MisspelledCompareToInspection.java @@ -0,0 +1,58 @@ +package com.siyeh.ig.bugs; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiMethod; +import com.intellij.psi.PsiParameterList; +import com.siyeh.ig.*; +import com.siyeh.ig.fixes.RenameFix; + +public class MisspelledCompareToInspection extends MethodInspection { + private final RenameFix fix = new RenameFix("compareTo"); + + public String getDisplayName() { + return "'compareto()' instead of 'compareTo()'"; + } + + public String getGroupDisplayName() { + return GroupNames.BUGS_GROUP_NAME; + } + + protected InspectionGadgetsFix buildFix(PsiElement location) { + return fix; + } + + public String buildErrorString(PsiElement location) { + return "#ref() method should probably be compareTo() #loc"; + } + + protected boolean buildQuickFixesOnlyForOnTheFlyErrors() { + return false; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new MisspelledCompareToVisitor(this, inspectionManager, onTheFly); + } + + private static class MisspelledCompareToVisitor extends BaseInspectionVisitor { + private MisspelledCompareToVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitMethod(PsiMethod method) { + //note: no call to super + final String methodName = method.getName(); + if (!"compareto".equals(methodName)) { + return; + } + final PsiParameterList parameterList = method.getParameterList(); + if (parameterList.getParameters().length != 1) { + return; + } + registerMethodError(method); + } + + + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/bugs/MisspelledEqualsInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/bugs/MisspelledEqualsInspection.java new file mode 100644 index 000000000000..00bff6c06a61 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/bugs/MisspelledEqualsInspection.java @@ -0,0 +1,57 @@ +package com.siyeh.ig.bugs; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiMethod; +import com.intellij.psi.PsiParameterList; +import com.siyeh.ig.*; +import com.siyeh.ig.fixes.RenameFix; + +public class MisspelledEqualsInspection extends MethodInspection { + private final RenameFix fix = new RenameFix("equals"); + + public String getDisplayName() { + return "'equal()' instead of 'equals()'"; + } + + public String getGroupDisplayName() { + return GroupNames.BUGS_GROUP_NAME; + } + + protected InspectionGadgetsFix buildFix(PsiElement location) { + return fix; + } + + public String buildErrorString(PsiElement location) { + return "#ref() method should probably be equals() #loc"; + } + + protected boolean buildQuickFixesOnlyForOnTheFlyErrors() { + return false; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new MisspelledToStringVisitor(this, inspectionManager, onTheFly); + } + + private static class MisspelledToStringVisitor extends BaseInspectionVisitor { + private MisspelledToStringVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitMethod(PsiMethod method) { + //note: no call to super + final String methodName = method.getName(); + if (!"equal".equals(methodName)) { + return; + } + final PsiParameterList parameterList = method.getParameterList(); + if (parameterList.getParameters().length != 1) { + return; + } + registerMethodError(method); + } + + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/bugs/MisspelledHashcodeInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/bugs/MisspelledHashcodeInspection.java new file mode 100644 index 000000000000..5f549a2b4c07 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/bugs/MisspelledHashcodeInspection.java @@ -0,0 +1,57 @@ +package com.siyeh.ig.bugs; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiMethod; +import com.intellij.psi.PsiParameterList; +import com.siyeh.ig.*; +import com.siyeh.ig.fixes.RenameFix; + +public class MisspelledHashcodeInspection extends MethodInspection { + private final RenameFix fix = new RenameFix("hashCode"); + + public String getDisplayName() { + return "'hashcode()' instead of 'hashCode()'"; + } + + public String getGroupDisplayName() { + return GroupNames.BUGS_GROUP_NAME; + } + + protected InspectionGadgetsFix buildFix(PsiElement location) { + return fix; + } + + public String buildErrorString(PsiElement location) { + return "#ref() should probably be hashCode() #loc"; + } + + protected boolean buildQuickFixesOnlyForOnTheFlyErrors() { + return true; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new MisspelledHashcodeVisitor(this, inspectionManager, onTheFly); + } + + private static class MisspelledHashcodeVisitor extends BaseInspectionVisitor { + private MisspelledHashcodeVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitMethod(PsiMethod method) { + //note: no call to super + final String methodName = method.getName(); + if (!"hashcode".equals(methodName)) { + return; + } + final PsiParameterList parameterList = method.getParameterList(); + if (parameterList.getParameters().length != 0) { + return; + } + registerMethodError(method); + } + + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/bugs/MisspelledToStringInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/bugs/MisspelledToStringInspection.java new file mode 100644 index 000000000000..9c8c450abba5 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/bugs/MisspelledToStringInspection.java @@ -0,0 +1,57 @@ +package com.siyeh.ig.bugs; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiMethod; +import com.intellij.psi.PsiParameterList; +import com.siyeh.ig.*; +import com.siyeh.ig.fixes.RenameFix; + +public class MisspelledToStringInspection extends MethodInspection { + private final RenameFix fix = new RenameFix("toString"); + + public String getDisplayName() { + return "'tostring()' instead of 'toString()'"; + } + + public String getGroupDisplayName() { + return GroupNames.BUGS_GROUP_NAME; + } + + protected InspectionGadgetsFix buildFix(PsiElement location) { + return fix; + } + + protected boolean buildQuickFixesOnlyForOnTheFlyErrors() { + return false; + } + + public String buildErrorString(PsiElement location) { + return "#ref() method should probably be toString() #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new MisspelledToStringVisitor(this, inspectionManager, onTheFly); + } + + private static class MisspelledToStringVisitor extends BaseInspectionVisitor { + private MisspelledToStringVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitMethod(PsiMethod method) { + //note: no call to super + final String methodName = method.getName(); + if (!"tostring".equals(methodName)) { + return; + } + final PsiParameterList parameterList = method.getParameterList(); + if (parameterList.getParameters().length != 0) { + return; + } + registerMethodError(method); + } + + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/bugs/NonShortCircuitBooleanInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/bugs/NonShortCircuitBooleanInspection.java new file mode 100644 index 000000000000..d822e9940d4c --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/bugs/NonShortCircuitBooleanInspection.java @@ -0,0 +1,121 @@ +package com.siyeh.ig.bugs; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.codeInspection.ProblemDescriptor; +import com.intellij.psi.*; +import com.intellij.psi.tree.IElementType; +import com.intellij.openapi.project.Project; +import com.siyeh.ig.*; + +public class NonShortCircuitBooleanInspection extends ExpressionInspection { + private final InspectionGadgetsFix fix = new NonShortCircuitBooleanFix(); + + public String getDisplayName() { + return "Non-short-circuit boolean expression"; + } + + public String getGroupDisplayName() { + return GroupNames.BUGS_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "Non-short-circuit boolean expression #loc"; + } + + public InspectionGadgetsFix buildFix(PsiElement location) { + return fix; + } + + private static class NonShortCircuitBooleanFix extends InspectionGadgetsFix { + public String getName() { + return "Replace with short circuit expression"; + } + + public void applyFix(Project project, ProblemDescriptor descriptor) { + if (descriptor.getPsiElement() instanceof PsiBinaryExpression) { + final PsiBinaryExpression expression = (PsiBinaryExpression) descriptor.getPsiElement(); + final PsiExpression lhs = expression.getLOperand(); + final PsiExpression rhs = expression.getROperand(); + final PsiJavaToken operationSign = expression.getOperationSign(); + final IElementType tokenType = operationSign.getTokenType(); + final String newExpression = lhs.getText() + getShortCircuitOperand(tokenType) + rhs.getText(); + replaceExpression(project, expression, newExpression); + } else { + final PsiAssignmentExpression expression = (PsiAssignmentExpression) descriptor.getPsiElement(); + final PsiExpression lhs = expression.getLExpression(); + final PsiExpression rhs = expression.getRExpression(); + final PsiJavaToken operationSign = expression.getOperationSign(); + final IElementType tokenType = operationSign.getTokenType(); + final String newExpression = lhs.getText() + getShortCircuitOperand(tokenType) + rhs.getText(); + replaceExpression(project, expression, newExpression); + } + } + + private static String getShortCircuitOperand(IElementType tokenType) { + if (tokenType.equals(JavaTokenType.AND)) { + return "&&"; + } + if (tokenType.equals(JavaTokenType.ANDEQ)) { + return "&&="; + } + if (tokenType.equals(JavaTokenType.OR)) { + return "||"; + } + return "||="; + } + + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new NonShortCircuitBooleanVisitor(this, inspectionManager, onTheFly); + } + + private static class NonShortCircuitBooleanVisitor extends BaseInspectionVisitor { + private NonShortCircuitBooleanVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitBinaryExpression(PsiBinaryExpression expression) { + super.visitBinaryExpression(expression); + final PsiJavaToken sign = expression.getOperationSign(); + if (sign == null) { + return; + } + final IElementType tokenType = sign.getTokenType(); + if (!tokenType.equals(JavaTokenType.AND) && + !tokenType.equals(JavaTokenType.OR)) { + return; + } + final PsiType type = expression.getType(); + if (type == null) { + return; + } + if (!type.equals(PsiType.BOOLEAN)) { + return; + } + registerError(expression); + } + + public void visitAssignmentExpression(PsiAssignmentExpression expression) { + super.visitAssignmentExpression(expression); + final PsiJavaToken sign = expression.getOperationSign(); + if (sign == null) { + return; + } + final IElementType tokenType = sign.getTokenType(); + if (!tokenType.equals(JavaTokenType.ANDEQ) && + !tokenType.equals(JavaTokenType.OREQ)) { + return; + } + final PsiType type = expression.getType(); + if (type == null) { + return; + } + if (!type.equals(PsiType.BOOLEAN)) { + return; + } + registerError(expression); + } + + } +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/bugs/ObjectEqualityInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/bugs/ObjectEqualityInspection.java new file mode 100644 index 000000000000..b03e972f9ed5 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/bugs/ObjectEqualityInspection.java @@ -0,0 +1,162 @@ +package com.siyeh.ig.bugs; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.codeInspection.ProblemDescriptor; +import com.intellij.openapi.project.Project; +import com.intellij.psi.*; +import com.intellij.psi.util.PsiTreeUtil; +import com.siyeh.ig.*; +import com.siyeh.ig.ui.SingleCheckboxOptionsPanel; +import com.siyeh.ig.psiutils.ClassUtils; +import com.siyeh.ig.psiutils.ComparisonUtils; +import com.siyeh.ig.psiutils.ParenthesesUtils; +import com.siyeh.ig.psiutils.TypeUtils; + +import javax.swing.*; + +public class ObjectEqualityInspection extends ExpressionInspection { + public boolean m_ignoreEnums = false; + + private final EqualityToEqualsFix fix = new EqualityToEqualsFix(); + + public String getDisplayName() { + return "Object comparison using ==, instead of '.equals()'"; + } + + public String getGroupDisplayName() { + return GroupNames.BUGS_GROUP_NAME; + } + + public JComponent createOptionsPanel() { + return new SingleCheckboxOptionsPanel("Ignore == between enumerated types", + this, "m_ignoreEnums"); + } + + public String buildErrorString(PsiElement location) { + return "Object values are compared using '#ref', not '.equals()' #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new ObjectEqualityVisitor(this, inspectionManager, onTheFly); + } + + public InspectionGadgetsFix buildFix(PsiElement location) { + return fix; + } + + private class EqualityToEqualsFix extends InspectionGadgetsFix { + public String getName() { + return "Replace with .equals()"; + } + + public void applyFix(Project project, ProblemDescriptor descriptor) { + final PsiElement comparisonToken = descriptor.getPsiElement(); + final PsiBinaryExpression + expression = (PsiBinaryExpression) comparisonToken.getParent(); + boolean negated = false; + final PsiJavaToken sign = expression.getOperationSign(); + if (sign == null) { + return; + } + if (sign.getTokenType() == JavaTokenType.NE) { + negated = true; + } + final PsiExpression lhs = expression.getLOperand(); + if (lhs == null) { + return; + } + final PsiExpression strippedLhs = ParenthesesUtils.stripParentheses(lhs); + final PsiExpression rhs = expression.getROperand(); + if (rhs == null) { + return; + } + final PsiExpression strippedRhs = ParenthesesUtils.stripParentheses(rhs); + + final String expString; + if (ParenthesesUtils.getPrecendence(strippedLhs) > ParenthesesUtils.METHOD_CALL_PRECEDENCE) { + expString = '(' + strippedLhs.getText() + ").equals(" + strippedRhs.getText() + ')'; + } else { + expString = strippedLhs.getText() + ".equals(" + strippedRhs.getText() + ')'; + } + final String newExpression; + if (negated) { + newExpression = '!' + expString; + } else { + newExpression = expString; + } + replaceExpression(project, expression, newExpression); + } + } + + private class ObjectEqualityVisitor extends BaseInspectionVisitor { + private ObjectEqualityVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitBinaryExpression(PsiBinaryExpression expression) { + super.visitBinaryExpression(expression); + if (!ComparisonUtils.isEqualityComparison(expression)) { + return; + } + final PsiExpression rhs = expression.getROperand(); + if (!isObjectType(rhs)) { + return; + } + + final PsiExpression lhs = expression.getLOperand(); + if (!isObjectType(lhs)) { + return; + } + if (m_ignoreEnums && isEnumType(rhs) && isEnumType(lhs)) { + return; + } + final PsiMethod method = (PsiMethod) PsiTreeUtil.getParentOfType(expression, PsiMethod.class); + final String methodName = method.getName(); + if ("equals".equals(methodName)) { + return; + } + final PsiJavaToken sign = expression.getOperationSign(); + if (sign == null) { + return; + } + registerError(sign); + } + + private boolean isEnumType(PsiExpression exp) { + if (exp == null) { + return false; + } + + final PsiType type = exp.getType(); + if (type == null) { + return false; + } + if(!(type instanceof PsiClassType)) + { + return false; + } + final PsiClass aClass = ((PsiClassType)type).resolve(); + if(aClass == null) + { + return false; + } + return aClass.isEnum(); + } + + private boolean isObjectType(PsiExpression exp) { + if (exp == null) { + return false; + } + + final PsiType type = exp.getType(); + if (type == null) { + return false; + } + return !ClassUtils.isPrimitive(type) + && !type.equals(PsiType.NULL) + && !TypeUtils.isJavaLangString(type); + } + + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/bugs/ObjectEqualsNullInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/bugs/ObjectEqualsNullInspection.java new file mode 100644 index 000000000000..46519257804c --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/bugs/ObjectEqualsNullInspection.java @@ -0,0 +1,64 @@ +package com.siyeh.ig.bugs; + +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 ObjectEqualsNullInspection extends ExpressionInspection { + + public String getDisplayName() { + return "Object.equals(null)"; + } + + public String getGroupDisplayName() { + return GroupNames.BUGS_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return ".equals(#ref) is probably not what was intended #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new ObjectEqualsNullVisitor(this, inspectionManager, onTheFly); + } + + private static class ObjectEqualsNullVisitor extends BaseInspectionVisitor { + private ObjectEqualsNullVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitMethodCallExpression(PsiMethodCallExpression call) { + super.visitMethodCallExpression(call); + final PsiReferenceExpression methodExpression = call.getMethodExpression(); + final String methodName = methodExpression.getReferenceName(); + if (!"equals".equals(methodName)) { + return; + } + final PsiExpressionList argumentList = call.getArgumentList(); + if (argumentList == null) { + return; + } + final PsiExpression[] args = argumentList.getExpressions(); + if (args.length != 1) { + return; + } + if (!isNull(args[0])) { + return; + } + registerError(args[0]); + } + + private static boolean isNull(PsiExpression arg) { + if (!(arg instanceof PsiLiteralExpression)) { + return false; + } + final String text = arg.getText(); + return "null".equals(text); + } + + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/bugs/OctalAndDecimalIntegersMixedInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/bugs/OctalAndDecimalIntegersMixedInspection.java new file mode 100644 index 000000000000..d846dc36e575 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/bugs/OctalAndDecimalIntegersMixedInspection.java @@ -0,0 +1,88 @@ +package com.siyeh.ig.bugs; + +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 OctalAndDecimalIntegersMixedInspection extends ExpressionInspection { + + public String getDisplayName() { + return "Octal and decimal integers in same array"; + } + + public String getGroupDisplayName() { + return GroupNames.BUGS_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "Octal and decimal integers are in the same array initializer #loc "; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new OctalAndDecimalIntegersMixedVisitor(this, inspectionManager, onTheFly); + } + + private static class OctalAndDecimalIntegersMixedVisitor extends BaseInspectionVisitor { + private OctalAndDecimalIntegersMixedVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitArrayInitializerExpression(PsiArrayInitializerExpression expression) { + super.visitArrayInitializerExpression(expression); + final PsiExpression[] initializers = expression.getInitializers(); + boolean hasDecimalLiteral = false; + boolean hasOctalLiteral = false; + for (int i = 0; i < initializers.length; i++) { + final PsiExpression initializer = initializers[i]; + if (initializer instanceof PsiLiteralExpression) { + final PsiLiteralExpression literal = (PsiLiteralExpression) initializer; + if (isDecimalLiteral(literal)) { + hasDecimalLiteral = true; + } + if (isOctalLiteral(literal)) { + hasOctalLiteral = true; + } + } + } + if (hasOctalLiteral && hasDecimalLiteral) { + registerError(expression); + } + } + + private static boolean isDecimalLiteral(PsiLiteralExpression literal) { + final PsiType type = literal.getType(); + if (type == null) { + return false; + } + if (!type.equals(PsiType.INT) && + !type.equals(PsiType.LONG)) { + return false; + } + final String text = literal.getText(); + if ("0".equals(text)) { + return false; + } + return text.charAt(0) != '0'; + } + + private static boolean isOctalLiteral(PsiLiteralExpression literal) { + final PsiType type = literal.getType(); + if (type == null) { + return false; + } + if (!(type.equals(PsiType.INT) + || type.equals(PsiType.LONG))) { + return false; + } + final String text = literal.getText(); + if ("0".equals(text) || "0L".equals(text)) { + return false; + } + return text.charAt(0) == '0' && !text.startsWith("0x") && !text.startsWith("0X"); + } + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/bugs/ResultOfObjectAllocationIgnoredInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/bugs/ResultOfObjectAllocationIgnoredInspection.java new file mode 100644 index 000000000000..2950ce78b983 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/bugs/ResultOfObjectAllocationIgnoredInspection.java @@ -0,0 +1,54 @@ +package com.siyeh.ig.bugs; + +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 ResultOfObjectAllocationIgnoredInspection extends ExpressionInspection { + + + public String getDisplayName() { + return "Result of object allocation ignored"; + } + + public String getGroupDisplayName() { + return GroupNames.BUGS_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "result of new #ref() is ignored. #loc "; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new IgnoreResultOfCallVisitor(this, inspectionManager, onTheFly); + } + + private static class IgnoreResultOfCallVisitor extends BaseInspectionVisitor { + private IgnoreResultOfCallVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitExpressionStatement(PsiExpressionStatement statement) { + super.visitExpressionStatement(statement); + if (!(statement.getExpression() instanceof PsiNewExpression)) { + return; + } + final PsiNewExpression newExpression = (PsiNewExpression) statement.getExpression(); + final PsiExpression[] arrayDimensions = newExpression.getArrayDimensions(); + if (arrayDimensions != null && arrayDimensions.length != 0) { + return; + } + if (newExpression.getArrayInitializer() != null) { + return; + } + final PsiJavaCodeReferenceElement classReference = + newExpression.getClassReference(); + registerError(classReference); + + } + + } +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/bugs/ResultSetIndexZeroInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/bugs/ResultSetIndexZeroInspection.java new file mode 100644 index 000000000000..bbc90b106d11 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/bugs/ResultSetIndexZeroInspection.java @@ -0,0 +1,90 @@ +package com.siyeh.ig.bugs; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.psi.*; +import com.intellij.psi.util.IsConstantExpressionVisitor; +import com.intellij.psi.util.ConstantExpressionUtil; +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 ResultSetIndexZeroInspection extends ExpressionInspection { + + public String getDisplayName() { + return "Use on index 0 with JDBC ResultSet"; + } + + public String getGroupDisplayName() { + return GroupNames.BUGS_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "Use on index 0 with JDBC ResultSet #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new ResultSetIndexZeroVisitor(this, inspectionManager, onTheFly); + } + + private static class ResultSetIndexZeroVisitor extends BaseInspectionVisitor { + private ResultSetIndexZeroVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitMethodCallExpression(PsiMethodCallExpression expression) { + super.visitMethodCallExpression(expression); + final PsiReferenceExpression methodExpression = expression.getMethodExpression(); + if (methodExpression == null) { + return; + } + final String methodName = methodExpression.getReferenceName(); + if (!methodName.startsWith("get") && !methodName.startsWith("update") ) { + return; + } + final PsiExpressionList argumentList = expression.getArgumentList(); + if (argumentList == null) { + return; + } + final PsiExpression[] args = argumentList.getExpressions(); + if (args == null) { + return; + } + if(args.length== 0) + { + return; + } + final PsiExpression arg = args[0]; + if (!TypeUtils.expressionHasType("int", arg)) { + return; + } + if(!isConstant(arg)) + { + return; + } + final Integer val = (Integer) ConstantExpressionUtil.computeCastTo(arg, PsiType.INT); + if(val == null || val.intValue()!=0) + { + return; + } + final PsiExpression qualifier = methodExpression.getQualifierExpression(); + if (!TypeUtils.expressionHasTypeOrSubtype("java.sql.ResultSet", qualifier)) { + return; + } + registerError(arg); + } + + private static boolean isConstant(PsiExpression expression) { + if (expression == null) { + return false; + } + final IsConstantExpressionVisitor visitor = + new IsConstantExpressionVisitor(); + expression.accept(visitor); + return visitor.isConstant(); + } + + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/bugs/ReturnNullInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/bugs/ReturnNullInspection.java new file mode 100644 index 000000000000..3d179bc65bcc --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/bugs/ReturnNullInspection.java @@ -0,0 +1,107 @@ +package com.siyeh.ig.bugs; + +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.GroupNames; +import com.siyeh.ig.StatementInspection; + +import javax.swing.*; +import javax.swing.event.ChangeEvent; +import javax.swing.event.ChangeListener; +import java.awt.*; + +public class ReturnNullInspection extends StatementInspection { + public boolean m_reportObjectMethods = true; + public boolean m_reportArrayMethods = true; + + public String getDisplayName() { + return "Return of 'null'"; + } + + public String getGroupDisplayName() { + return GroupNames.BUGS_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "Return of '#ref' #loc"; + } + + public JComponent createOptionsPanel() { + final GridBagLayout layout = new GridBagLayout(); + final JPanel panel = new JPanel(layout); + final JCheckBox arrayCheckBox = new JCheckBox("Methods that return arrays", m_reportArrayMethods); + final ButtonModel arrayModel = arrayCheckBox.getModel(); + arrayModel.addChangeListener(new ChangeListener() { + + public void stateChanged(ChangeEvent e) { + m_reportArrayMethods = arrayModel.isSelected(); + } + }); + final JCheckBox objectCheckBox = new JCheckBox("Methods that return objects", m_reportObjectMethods); + final ButtonModel model = objectCheckBox.getModel(); + model.addChangeListener(new ChangeListener() { + + public void stateChanged(ChangeEvent e) { + m_reportObjectMethods = model.isSelected(); + } + }); + final GridBagConstraints constraints = new GridBagConstraints(); + constraints.gridx = 0; + constraints.gridy = 0; + constraints.fill = GridBagConstraints.HORIZONTAL; + panel.add(arrayCheckBox, constraints); + + constraints.gridx = 0; + constraints.gridy = 1; + panel.add(objectCheckBox, constraints); + return panel; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new ReturnNullVisitor(this, inspectionManager, onTheFly); + } + + private class ReturnNullVisitor extends BaseInspectionVisitor { + private ReturnNullVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitLiteralExpression(PsiLiteralExpression value) { + super.visitLiteralExpression(value); + final String text = value.getText(); + if (!"null".equals(text)) { + return; + } + PsiElement parent = value.getParent(); + while (parent != null && + (parent instanceof PsiParenthesizedExpression || + parent instanceof PsiConditionalExpression || + parent instanceof PsiTypeCastExpression)) { + parent = parent.getParent(); + } + if (parent == null || !(parent instanceof PsiReturnStatement)) { + return; + } + final PsiMethod method = (PsiMethod) PsiTreeUtil.getParentOfType(value, PsiMethod.class); + if (method == null) { + return; + } + final PsiType returnType = method.getReturnType(); + if (returnType == null) { + return; + } + final boolean isArray = returnType.getArrayDimensions() > 0; + if (m_reportArrayMethods && isArray) { + registerError(value); + } + if (m_reportObjectMethods && !isArray) { + registerError(value); + } + } + + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/bugs/StringEqualityInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/bugs/StringEqualityInspection.java new file mode 100644 index 000000000000..5d1f2d8a5603 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/bugs/StringEqualityInspection.java @@ -0,0 +1,121 @@ +package com.siyeh.ig.bugs; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.codeInspection.ProblemDescriptor; +import com.intellij.openapi.project.Project; +import com.intellij.psi.*; +import com.siyeh.ig.*; +import com.siyeh.ig.psiutils.ClassUtils; +import com.siyeh.ig.psiutils.ComparisonUtils; +import com.siyeh.ig.psiutils.ParenthesesUtils; +import com.siyeh.ig.psiutils.TypeUtils; + +public class StringEqualityInspection extends ExpressionInspection { + private final EqualityToEqualsFix fix = new EqualityToEqualsFix(); + + public String getDisplayName() { + return "String comparison using ==, instead of '.equals()'"; + } + + public String getGroupDisplayName() { + return GroupNames.BUGS_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "String values are compared using '#ref', not '.equals()' #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new ObjectEqualityVisitor(this, inspectionManager, onTheFly); + } + + public InspectionGadgetsFix buildFix(PsiElement location) { + return fix; + } + + private static class EqualityToEqualsFix extends InspectionGadgetsFix { + public String getName() { + return "Replace with .equals()"; + } + + public void applyFix(Project project, ProblemDescriptor descriptor) { + final PsiElement comparisonToken = descriptor.getPsiElement(); + boolean negated = false; + final PsiBinaryExpression expression = + (PsiBinaryExpression) comparisonToken.getParent(); + final PsiJavaToken sign = expression.getOperationSign(); + if (sign.getTokenType() == JavaTokenType.NE) { + negated = true; + } + final PsiExpression lhs = expression.getLOperand(); + if (lhs == null) { + return; + } + final PsiExpression strippedLhs = ParenthesesUtils.stripParentheses(lhs); + final PsiExpression rhs = expression.getROperand(); + if (rhs == null) { + return; + } + final PsiExpression strippedRhs = ParenthesesUtils.stripParentheses(rhs); + + final String expString; + if (ParenthesesUtils.getPrecendence(strippedLhs) > ParenthesesUtils.METHOD_CALL_PRECEDENCE) { + expString = '(' + strippedLhs.getText() + ").equals(" + strippedRhs.getText() + ')'; + } else { + expString = strippedLhs.getText() + ".equals(" + strippedRhs.getText() + ')'; + } + final String newExpression; + if (negated) { + newExpression = '!' + expString; + } else { + newExpression = expString; + } + replaceExpression(project, expression, newExpression); + } + } + + private static class ObjectEqualityVisitor extends BaseInspectionVisitor { + private ObjectEqualityVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitBinaryExpression(PsiBinaryExpression expression) { + super.visitBinaryExpression(expression); + if (!ComparisonUtils.isEqualityComparison(expression)) { + return; + } + final PsiExpression lhs = expression.getLOperand(); + if (!isStringType(lhs)) { + return; + } + final PsiExpression rhs = expression.getROperand(); + if (!isStringType(rhs)) { + return; + } + final String lhsText = lhs.getText(); + if ("null".equals(lhsText)) { + return; + } + final String rhsText = rhs.getText(); + if ("null".equals(rhsText)) { + return; + } + final PsiJavaToken sign = expression.getOperationSign(); + registerError(sign); + } + + private static boolean isStringType(PsiExpression lhs) { + if (lhs == null) { + return false; + } + final PsiType lhsType = lhs.getType(); + if (lhsType == null) { + return false; + } + return !ClassUtils.isPrimitive(lhsType) + && !lhsType.equals(PsiType.NULL) + && TypeUtils.isJavaLangString(lhsType); + } + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/bugs/SubtractionInCompareToInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/bugs/SubtractionInCompareToInspection.java new file mode 100644 index 000000000000..35d37fb95049 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/bugs/SubtractionInCompareToInspection.java @@ -0,0 +1,91 @@ +package com.siyeh.ig.bugs; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.psi.*; +import com.intellij.psi.tree.IElementType; +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 SubtractionInCompareToInspection extends ExpressionInspection { + + public String getDisplayName() { + return "Subtraction in compareTo()"; + } + + public String getGroupDisplayName() { + return GroupNames.BUGS_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "Subtraction (#ref) in compareTo() may result in overflow errors #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new SubtractionInCompareToVisitor(this, inspectionManager, onTheFly); + } + + private static class SubtractionInCompareToVisitor extends BaseInspectionVisitor { + private SubtractionInCompareToVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitBinaryExpression(PsiBinaryExpression exp) { + super.visitBinaryExpression(exp); + if (!isSubtraction(exp)) { + return; + } + final PsiMethod method = + (PsiMethod) PsiTreeUtil.getParentOfType(exp, PsiMethod.class); + if (!isCompareTo(method)) { + return; + } + registerError(exp); + } + + private static boolean isCompareTo(PsiMethod method) { + if (method == null) { + return false; + } + final String methodName = method.getName(); + if (!"compareTo".equals(methodName)) { + return false; + } + final PsiParameterList parameterList = method.getParameterList(); + if (parameterList == null) { + return false; + } + final PsiParameter[] parameters = parameterList.getParameters(); + if (parameters.length != 1) { + return false; + } + final PsiType returnType = method.getReturnType(); + if (!TypeUtils.typeEquals("int", returnType)) { + return false; + } + return true; + } + + private static boolean isSubtraction(PsiBinaryExpression exp) { + final PsiExpression lhs = exp.getLOperand(); + if (lhs == null) { + return false; + } + final PsiExpression rhs = exp.getROperand(); + if (rhs == null) { + return false; + } + final PsiJavaToken sign = exp.getOperationSign(); + if (sign == null) { + return false; + } + final IElementType tokenType = sign.getTokenType(); + return tokenType.equals(JavaTokenType.MINUS); + } + + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/bugs/SwitchStatementsWithoutDefaultInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/bugs/SwitchStatementsWithoutDefaultInspection.java new file mode 100644 index 000000000000..f00c3fadce9b --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/bugs/SwitchStatementsWithoutDefaultInspection.java @@ -0,0 +1,117 @@ +package com.siyeh.ig.bugs; + +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; +import com.siyeh.ig.ui.SingleCheckboxOptionsPanel; + +import javax.swing.*; + +public class SwitchStatementsWithoutDefaultInspection extends StatementInspection { + private boolean m_ignoreFullyCoveredEnums = true; + + public String getDisplayName() { + return "'switch' statement without 'default' branch"; + } + + public String getGroupDisplayName() { + return GroupNames.BUGS_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "'#ref' statement without 'default' branch #loc"; + } + + public JComponent createOptionsPanel() { + return new SingleCheckboxOptionsPanel("Ignore if all cases of an enumerated type are covered", + this, "m_ignoreFullyCoveredEnums"); + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new SwitchStatementsWithoutDefaultVisitor(this, inspectionManager, onTheFly); + } + + private class SwitchStatementsWithoutDefaultVisitor extends BaseInspectionVisitor { + private SwitchStatementsWithoutDefaultVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitSwitchStatement(PsiSwitchStatement statement) { + super.visitSwitchStatement(statement); + if (switchStatementHasDefault(statement)) { + return; + } + if (m_ignoreFullyCoveredEnums && switchStatementIsFullyCoveredEnum(statement)) { + return; + } + registerStatementError(statement); + } + + private boolean switchStatementHasDefault(PsiSwitchStatement statement) { + final PsiCodeBlock body = statement.getBody(); + if (body == null) { + return false; + } + final PsiStatement[] statements = body.getStatements(); + for (int i = 0; i < statements.length; i++) { + final PsiStatement child = statements[i]; + if (child instanceof PsiSwitchLabelStatement && + ((PsiSwitchLabelStatement) child).isDefaultCase()) { + return true; + } + } + return false; + } + + private boolean switchStatementIsFullyCoveredEnum(PsiSwitchStatement statement) { + final PsiExpression expression = statement.getExpression(); + if (expression == null) { + return false; + } + final PsiType type = expression.getType(); + if (type == null) { + return false; + } + if (!(type instanceof PsiClassType)) { + return false; + } + final PsiClass aClass = ((PsiClassType) type).resolve(); + if (aClass == null) { + return false; + } + if (!aClass.isEnum()) { + return false; + } + int numCases = 0; + final PsiCodeBlock body = statement.getBody(); + if (body == null) { + return false; + } + final PsiStatement[] statements = body.getStatements(); + if (statements == null) { + return false; + } + for (int i = 0; i < statements.length; i++) { + final PsiStatement child = statements[i]; + if (child instanceof PsiSwitchLabelStatement) { + numCases++; + } + } + final PsiField[] fields = aClass.getFields(); + int numEnums = 0; + for (int i = 0; i < fields.length; i++) { + final PsiField field = fields[i]; + final PsiType fieldType = field.getType(); + if (fieldType.equals(type)) { + numEnums++; + } + + } + return numEnums == numCases; + } + } + +} \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/bugs/TextLabelInSwitchStatementInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/bugs/TextLabelInSwitchStatementInspection.java new file mode 100644 index 000000000000..dfd429e406d2 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/bugs/TextLabelInSwitchStatementInspection.java @@ -0,0 +1,57 @@ +package com.siyeh.ig.bugs; + +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 TextLabelInSwitchStatementInspection extends StatementInspection { + + public String getDisplayName() { + return "Text label in 'switch' statement"; + } + + public String getGroupDisplayName() { + return GroupNames.BUGS_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "Text label #ref: in 'switch' statement #loc "; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new TextLabelInSwitchStatementVisitor(this, inspectionManager, onTheFly); + } + + private static class TextLabelInSwitchStatementVisitor extends BaseInspectionVisitor { + private TextLabelInSwitchStatementVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitSwitchStatement(PsiSwitchStatement statement) { + super.visitSwitchStatement(statement); + final PsiCodeBlock body = statement.getBody(); + if (body == null) { + return; + } + final PsiStatement[] statements = body.getStatements(); + if (statements == null) { + return; + } + for (int i = 0; i < statements.length; i++) { + checkForLabel(statements[i]); + } + } + + private void checkForLabel(PsiStatement statement) { + if (!(statement instanceof PsiLabeledStatement)) { + return; + } + final PsiIdentifier label = ((PsiLabeledStatement) statement).getLabelIdentifier(); + registerError(label); + } + } + +} \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/classlayout/AbstractClassExtendsConcreteClassInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/classlayout/AbstractClassExtendsConcreteClassInspection.java new file mode 100644 index 000000000000..fb2b42553ea7 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/classlayout/AbstractClassExtendsConcreteClassInspection.java @@ -0,0 +1,59 @@ +package com.siyeh.ig.classlayout; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.psi.PsiClass; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiModifier; +import com.siyeh.ig.BaseInspection; +import com.siyeh.ig.BaseInspectionVisitor; +import com.siyeh.ig.ClassInspection; +import com.siyeh.ig.GroupNames; + +public class AbstractClassExtendsConcreteClassInspection extends ClassInspection { + + public String getDisplayName() { + return "Abstract class extends concrete class"; + } + + public String getGroupDisplayName() { + return GroupNames.CLASSLAYOUT_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "Class #ref is declared 'abstract', and extends a concrete class #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new AbstractClassExtendsConcreteClassVisitor(this, inspectionManager, onTheFly); + } + + private static class AbstractClassExtendsConcreteClassVisitor extends BaseInspectionVisitor { + private AbstractClassExtendsConcreteClassVisitor(BaseInspection inspection, + InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitClass(PsiClass aClass) { + // no call to super, so that it doesn't drill down to inner classes + if (aClass.isInterface()|| aClass.isAnnotationType()) { + return; + } + if (!aClass.hasModifierProperty(PsiModifier.ABSTRACT)) { + return; + } + final PsiClass superClass = aClass.getSuperClass(); + if (superClass == null) { + return; + } + if (superClass.hasModifierProperty(PsiModifier.ABSTRACT)) { + return; + } + final String superclassName = superClass.getQualifiedName(); + if ("java.lang.Object".equals(superclassName)) { + return; + } + registerClassError(aClass); + } + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/classlayout/AbstractClassWithoutAbstractMethodsInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/classlayout/AbstractClassWithoutAbstractMethodsInspection.java new file mode 100644 index 000000000000..4219dfbd36b7 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/classlayout/AbstractClassWithoutAbstractMethodsInspection.java @@ -0,0 +1,85 @@ +package com.siyeh.ig.classlayout; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.psi.*; +import com.intellij.psi.util.PsiSuperMethodUtil; +import com.siyeh.ig.BaseInspection; +import com.siyeh.ig.BaseInspectionVisitor; +import com.siyeh.ig.ClassInspection; +import com.siyeh.ig.GroupNames; + +import java.util.HashSet; +import java.util.Set; + +public class AbstractClassWithoutAbstractMethodsInspection extends ClassInspection { + + public String getDisplayName() { + return "Abstract class without abstract methods"; + } + + public String getGroupDisplayName() { + return GroupNames.CLASSLAYOUT_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "Class #ref is declared 'abstract', and has no 'abstract' methods #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new AbstractClassWithoutAbstractMethodsVisitor(this, inspectionManager, onTheFly); + } + + private static class AbstractClassWithoutAbstractMethodsVisitor extends BaseInspectionVisitor { + private AbstractClassWithoutAbstractMethodsVisitor(BaseInspection inspection, + InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitClass(PsiClass aClass) { + // no call to super, so that it doesn't drill down to inner classes + if (aClass.isInterface() || aClass.isAnnotationType()) { + return; + } + if (!aClass.hasModifierProperty(PsiModifier.ABSTRACT)) { + return; + } + if (hasAbstractMethods(aClass)) { + return; + } + registerClassError(aClass); + } + + private static boolean hasAbstractMethods(PsiClass aClass) { + final PsiMethod[] methods = aClass.getMethods(); + final Set overriddenMethods = calculateOverriddenMethods(methods); + final PsiMethod[] allMethods = aClass.getAllMethods(); + for (int i = 0; i < allMethods.length; i++) { + final PsiMethod method = allMethods[i]; + if (method.hasModifierProperty(PsiModifier.ABSTRACT) && + !overriddenMethods.contains(method)) { + return true; + } + } + return false; + } + + private static Set calculateOverriddenMethods(PsiMethod[] methods) { + final Set overriddenMethods = new HashSet(methods.length); + for (int i = 0; i < methods.length; i++) { + final PsiMethod method = methods[i]; + calculateOverriddenMethods(method, overriddenMethods); + } + return overriddenMethods; + } + + private static void calculateOverriddenMethods(PsiMethod method, Set overriddenMethods) { + final PsiMethod[] superMethods = PsiSuperMethodUtil.findSuperMethods(method); + for (int j = 0; j < superMethods.length; j++) { + final PsiMethod superMethod = superMethods[j]; + overriddenMethods.add(superMethod); + } + } + + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/classlayout/AbstractMethodOverridesAbstractMethodInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/classlayout/AbstractMethodOverridesAbstractMethodInspection.java new file mode 100644 index 000000000000..8c3ad639de86 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/classlayout/AbstractMethodOverridesAbstractMethodInspection.java @@ -0,0 +1,73 @@ +package com.siyeh.ig.classlayout; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.codeInspection.ProblemDescriptor; +import com.intellij.psi.*; +import com.intellij.psi.util.PsiSuperMethodUtil; +import com.intellij.openapi.project.Project; +import com.siyeh.ig.*; + +public class AbstractMethodOverridesAbstractMethodInspection extends MethodInspection { + private final AbstractMethodOverridesAbstractMethodFix fix = new AbstractMethodOverridesAbstractMethodFix(); + + public String getDisplayName() { + return "Abstract method overrides abstract method"; + } + + public String getGroupDisplayName() { + return GroupNames.CLASSLAYOUT_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "Abstract method '#ref' overrides abstract method #loc"; + } + + protected InspectionGadgetsFix buildFix(PsiElement location) { + return fix; + } + + private static class AbstractMethodOverridesAbstractMethodFix extends InspectionGadgetsFix { + public String getName() { + return "Remove redundant abstract method declaration"; + } + + public void applyFix(Project project, ProblemDescriptor descriptor) { + final PsiElement methodNameIdentifier = descriptor.getPsiElement(); + final PsiElement method = methodNameIdentifier.getParent(); + deleteElement(method); + } + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new AbstractMethodOverridesAbstractMethodVisitor(this, inspectionManager, onTheFly); + } + + private static class AbstractMethodOverridesAbstractMethodVisitor extends BaseInspectionVisitor { + private AbstractMethodOverridesAbstractMethodVisitor(BaseInspection inspection, + InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitMethod(PsiMethod method) { + //no call to super, so we don't drill into anonymous classes + if (method.isConstructor()) { + return; + } + final PsiClass containingClass = method.getContainingClass(); + if (!method.hasModifierProperty(PsiModifier.ABSTRACT) && + !containingClass.isInterface()) { + return; + } + final PsiMethod[] superMethods = PsiSuperMethodUtil.findSuperMethods(method); + for (int i = 0; i < superMethods.length; i++) { + final PsiMethod superMethod = superMethods[i]; + final PsiClass superClass = superMethod.getContainingClass(); + if (superClass.isInterface() || + superMethod.hasModifierProperty(PsiModifier.ABSTRACT)) { + registerMethodError(method); + return; + } + } + } + } +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/classlayout/AbstractMethodOverridesConcreteMethodInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/classlayout/AbstractMethodOverridesConcreteMethodInspection.java new file mode 100644 index 000000000000..cf70ef9e76ba --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/classlayout/AbstractMethodOverridesConcreteMethodInspection.java @@ -0,0 +1,59 @@ +package com.siyeh.ig.classlayout; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.psi.*; +import com.intellij.psi.util.PsiSuperMethodUtil; +import com.siyeh.ig.BaseInspection; +import com.siyeh.ig.BaseInspectionVisitor; +import com.siyeh.ig.GroupNames; +import com.siyeh.ig.MethodInspection; + +public class AbstractMethodOverridesConcreteMethodInspection extends MethodInspection { + + public String getDisplayName() { + return "Abstract method overrides concrete method"; + } + + public String getGroupDisplayName() { + return GroupNames.CLASSLAYOUT_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "Abstract method '#ref' overrides concrete method #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new AbstractMethodOverridesConcreteMethodVisitor(this, inspectionManager, onTheFly); + } + + private static class AbstractMethodOverridesConcreteMethodVisitor extends BaseInspectionVisitor { + private AbstractMethodOverridesConcreteMethodVisitor(BaseInspection inspection, + InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitMethod(PsiMethod method) { + //no call to super, so we don't drill into anonymous classes + if (method.isConstructor()) { + return; + } + final PsiClass containingClass = method.getContainingClass(); + if (containingClass.isInterface() || containingClass.isAnnotationType()) { + return; + } + if (!method.hasModifierProperty(PsiModifier.ABSTRACT)) { + return; + } + final PsiMethod[] superMethods = PsiSuperMethodUtil.findSuperMethods(method); + for (int i = 0; i < superMethods.length; i++) { + final PsiMethod superMethod = superMethods[i]; + final PsiClass superClass = superMethod.getContainingClass(); + if (!superClass.isInterface() && + !superMethod.hasModifierProperty(PsiModifier.ABSTRACT)) { + registerMethodError(method); + return; + } + } + } + } +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/classlayout/AnonymousInnerClassInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/classlayout/AnonymousInnerClassInspection.java new file mode 100644 index 000000000000..584ddaacb73b --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/classlayout/AnonymousInnerClassInspection.java @@ -0,0 +1,43 @@ +package com.siyeh.ig.classlayout; + +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; + +public class AnonymousInnerClassInspection extends ClassInspection { + + public String getDisplayName() { + return "Anonymous inner class"; + } + + public String getGroupDisplayName() { + return GroupNames.CLASSLAYOUT_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "Anonymous inner class #ref #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new AnonymousInnerClassVisitor(this, inspectionManager, onTheFly); + } + + private static class AnonymousInnerClassVisitor extends BaseInspectionVisitor { + private AnonymousInnerClassVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitClass(PsiClass aClass) { + //no call to super here, to avoid double counting + } + + public void visitAnonymousClass(PsiAnonymousClass aClass) { + super.visitAnonymousClass(aClass); + final PsiJavaCodeReferenceElement classReference = aClass.getBaseClassReference(); + registerError(classReference); + } + } +} \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/classlayout/ClassInTopLevelPackageInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/classlayout/ClassInTopLevelPackageInspection.java new file mode 100644 index 000000000000..ca1b795149e0 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/classlayout/ClassInTopLevelPackageInspection.java @@ -0,0 +1,63 @@ +package com.siyeh.ig.classlayout; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.psi.PsiClass; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiFile; +import com.intellij.psi.PsiJavaFile; +import com.siyeh.ig.*; +import com.siyeh.ig.fixes.MoveClassFix; +import com.siyeh.ig.psiutils.ClassUtils; + +public class ClassInTopLevelPackageInspection extends ClassInspection { + private final MoveClassFix fix = new MoveClassFix(); + + public String getDisplayName() { + return "Class without package statement"; + } + + public String getGroupDisplayName() { + return GroupNames.CLASSLAYOUT_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "Class #ref lacks a package statement #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new ClassInTopLevelPackageVisitor(this, inspectionManager, onTheFly); + } + + protected InspectionGadgetsFix buildFix(PsiElement location) { + return fix; + } + + protected boolean buildQuickFixesOnlyForOnTheFlyErrors() { + return true; + } + + private static class ClassInTopLevelPackageVisitor extends BaseInspectionVisitor { + private ClassInTopLevelPackageVisitor(BaseInspection inspection, + InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitClass(PsiClass aClass) { + // no call to super, so that it doesn't drill down to inner classes + if (ClassUtils.isInnerClass(aClass)) { + return; + } + final PsiFile file = aClass.getContainingFile(); + + if (file == null || !(file instanceof PsiJavaFile)) { + return; + } + if (((PsiJavaFile) file).getPackageStatement() != null) { + return; + } + registerClassError(aClass); + } + + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/classlayout/ClassInitializerInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/classlayout/ClassInitializerInspection.java new file mode 100644 index 000000000000..46e62c9e6d5e --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/classlayout/ClassInitializerInspection.java @@ -0,0 +1,45 @@ +package com.siyeh.ig.classlayout; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.psi.*; +import com.siyeh.ig.*; + +public class ClassInitializerInspection extends ClassInspection { + + public String getDisplayName() { + return "Non-static initializer"; + } + + public String getGroupDisplayName() { + return GroupNames.CLASSLAYOUT_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "Non-static initializer #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new ClassInitializerVisitor(this, inspectionManager, onTheFly); + } + + private static class ClassInitializerVisitor extends BaseInspectionVisitor { + private ClassInitializerVisitor(BaseInspection inspection, + InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitClass(PsiClass aClass) { + // no call to super, so that it doesn't drill down to inner classes + final PsiClassInitializer[] initializers = aClass.getInitializers(); + for (int i = 0; i < initializers.length; i++) { + final PsiClassInitializer initializer = initializers[i]; + if (!initializer.hasModifierProperty(PsiModifier.STATIC)) { + final PsiCodeBlock body = initializer.getBody(); + final PsiJavaToken leftBrace = body.getLBrace(); + registerError(leftBrace); + } + } + } + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/classlayout/ClassMayBeInterfaceInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/classlayout/ClassMayBeInterfaceInspection.java new file mode 100644 index 000000000000..908613cf1b1a --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/classlayout/ClassMayBeInterfaceInspection.java @@ -0,0 +1,181 @@ +package com.siyeh.ig.classlayout; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.codeInspection.ProblemDescriptor; +import com.intellij.psi.*; +import com.intellij.psi.util.PsiTreeUtil; +import com.intellij.psi.search.PsiSearchHelper; +import com.intellij.psi.search.GlobalSearchScope; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.diagnostic.Logger; +import com.intellij.util.IncorrectOperationException; +import com.siyeh.ig.*; + +public class ClassMayBeInterfaceInspection extends ClassInspection { + private final ClassMayBeInterfaceFix fix = new ClassMayBeInterfaceFix(); + + public String getDisplayName() { + return "Class may be interface"; + } + + public String getGroupDisplayName() { + return GroupNames.CLASSLAYOUT_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "#ref may be interface #loc"; + } + + protected InspectionGadgetsFix buildFix(PsiElement location) { + return fix; + } + + private static class ClassMayBeInterfaceFix extends InspectionGadgetsFix { + public String getName() { + return "Convert class to interface"; + } + + public void applyFix(Project project, ProblemDescriptor problemDescriptor) { + final PsiIdentifier classNameIdentifier = (PsiIdentifier) problemDescriptor.getPsiElement(); + final PsiClass interfaceClass = (PsiClass) classNameIdentifier.getParent(); + try { + moveSubClassExtendsToImplements(interfaceClass); + changeClassToInterface(interfaceClass); + moveImplementsToExtends(interfaceClass); + } catch (IncorrectOperationException e) { + final Class aClass = getClass(); + final String className = aClass.getName(); + final Logger logger = Logger.getInstance(className); + logger.error(e); + } + } + + private static void changeClassToInterface(PsiClass aClass) + throws IncorrectOperationException { + final PsiIdentifier nameIdentifier = aClass.getNameIdentifier(); + final PsiKeyword classKeyword = (PsiKeyword)PsiTreeUtil.getPrevSiblingOfType(nameIdentifier, PsiKeyword.class); + final PsiManager manager = aClass.getManager(); + final PsiElementFactory factory = manager.getElementFactory(); + final PsiKeyword interfaceKeyword = factory.createKeyword("interface"); + classKeyword.replace(interfaceKeyword); + } + + private static void moveImplementsToExtends(PsiClass anInterface) + throws IncorrectOperationException { + final PsiReferenceList extendsList = anInterface.getExtendsList(); + final PsiReferenceList implementsList = anInterface.getImplementsList(); + final PsiJavaCodeReferenceElement[] referenceElements = implementsList.getReferenceElements(); + for (int i = 0; i < referenceElements.length; i++) { + final PsiJavaCodeReferenceElement referenceElement = referenceElements[i]; + final PsiElement elementCopy = referenceElement.copy(); + extendsList.add(elementCopy); + referenceElement.delete(); + } + } + + private static void moveSubClassExtendsToImplements(PsiClass oldClass) + throws IncorrectOperationException { + final PsiManager psiManager = oldClass.getManager(); + final PsiSearchHelper searchHelper = psiManager.getSearchHelper(); + final PsiElementFactory elementFactory = psiManager.getElementFactory(); + final PsiJavaCodeReferenceElement classReference = elementFactory.createClassReferenceElement(oldClass); + final GlobalSearchScope searchScope = oldClass.getUseScope(); + final PsiClass[] inheritors = searchHelper.findInheritors(oldClass, searchScope, false); + for (int i = 0; i < inheritors.length; i++) { + final PsiClass inheritor = inheritors[i]; + final PsiReferenceList extendsList = inheritor.getExtendsList(); + removeReference(extendsList, classReference); + final PsiReferenceList implementsList = inheritor.getImplementsList(); + implementsList.add(classReference); + } + } + + private static void removeReference(PsiReferenceList referenceList, + PsiJavaCodeReferenceElement reference) + throws IncorrectOperationException { + final PsiJavaCodeReferenceElement[] implementsReferences = referenceList.getReferenceElements(); + final String fqName = reference.getQualifiedName(); + for (int j = 0; j < implementsReferences.length; j++) { + final PsiJavaCodeReferenceElement implementsReference = implementsReferences[j]; + final String implementsReferenceFqName = implementsReference.getQualifiedName(); + if (fqName.equals(implementsReferenceFqName)) { + implementsReference.delete(); + } + } + } + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new ClassMayBeInterfaceVisitor(this, inspectionManager, onTheFly); + } + + private static class ClassMayBeInterfaceVisitor extends BaseInspectionVisitor { + private ClassMayBeInterfaceVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitClass(PsiClass aClass) { + // no call to super, so that it doesn't drill down to inner classes + if (aClass.isInterface() || aClass.isAnnotationType()) { + return; + } + if (aClass.isEnum() || aClass.isAnnotationType()) { + return; + } + if (!mayBeInterface(aClass)) { + return; + } + registerClassError(aClass); + } + + public static boolean mayBeInterface(PsiClass aClass) { + final PsiReferenceList extendsList = aClass.getExtendsList(); + + if (extendsList != null) { + final PsiJavaCodeReferenceElement[] extendsElements = extendsList.getReferenceElements(); + if (extendsElements != null && extendsElements.length > 0) { + return false; + } + } + final PsiClassInitializer[] initializers = aClass.getInitializers(); + if (initializers != null && initializers.length > 0) { + return false; + } + if (!allMethodsPublicAbstract(aClass)) { + return false; + } + + if (!allFieldsPublicStaticFinal(aClass)) { + return false; + } + return true; + } + + private static boolean allFieldsPublicStaticFinal(PsiClass aClass) { + boolean allFieldsStaticFinal = true; + final PsiField[] fields = aClass.getFields(); + for (int i = 0; i < fields.length; i++) { + final PsiField field = fields[i]; + if (!(field.hasModifierProperty(PsiModifier.STATIC) + && field.hasModifierProperty(PsiModifier.FINAL) + && field.hasModifierProperty(PsiModifier.PUBLIC))) { + allFieldsStaticFinal = false; + } + } + return allFieldsStaticFinal; + } + + private static boolean allMethodsPublicAbstract(PsiClass aClass) { + final PsiMethod[] methods = aClass.getMethods(); + for (int i = 0; i < methods.length; i++) { + final PsiMethod method = methods[i]; + if (!(method.hasModifierProperty(PsiModifier.ABSTRACT) && + method.hasModifierProperty(PsiModifier.PUBLIC))) { + return false; + } + } + return true; + } + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/classlayout/ClassNameDiffersFromFileNameInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/classlayout/ClassNameDiffersFromFileNameInspection.java new file mode 100644 index 000000000000..970dd5219f73 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/classlayout/ClassNameDiffersFromFileNameInspection.java @@ -0,0 +1,61 @@ +package com.siyeh.ig.classlayout; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.psi.PsiClass; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiJavaFile; +import com.siyeh.ig.BaseInspection; +import com.siyeh.ig.BaseInspectionVisitor; +import com.siyeh.ig.ClassInspection; +import com.siyeh.ig.GroupNames; + +public class ClassNameDiffersFromFileNameInspection extends ClassInspection { + + public String getDisplayName() { + return "Class name differs from file name"; + } + + public String getGroupDisplayName() { + return GroupNames.CLASSLAYOUT_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "Class name #ref differs from file name #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new classNameDiffersFromFileName(this, inspectionManager, onTheFly); + } + + private static class classNameDiffersFromFileName extends BaseInspectionVisitor { + + private classNameDiffersFromFileName(BaseInspection inspection, + InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitClass(PsiClass aClass) { + // no call to super, so that it doesn't drill down to inner classes + if (!(aClass.getParent() instanceof PsiJavaFile)) { + return; + } + final PsiJavaFile file = (PsiJavaFile) aClass.getParent(); + final String className = aClass.getName(); + if (className == null) { + return; + } + final String fileName = file.getName(); + if (fileName == null) { + return; + } + final int prefixIndex = fileName.indexOf((int) '.'); + final String filenameWithoutPrefix = fileName.substring(0, prefixIndex); + if (className.equals(filenameWithoutPrefix)) { + return; + } + registerClassError(aClass); + } + + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/classlayout/ClassWithoutConstructorInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/classlayout/ClassWithoutConstructorInspection.java new file mode 100644 index 000000000000..bde6e98de93f --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/classlayout/ClassWithoutConstructorInspection.java @@ -0,0 +1,90 @@ +package com.siyeh.ig.classlayout; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.codeInspection.ProblemDescriptor; +import com.intellij.psi.*; +import com.intellij.psi.codeStyle.CodeStyleManager; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.diagnostic.Logger; +import com.intellij.util.IncorrectOperationException; +import com.siyeh.ig.*; + +public class ClassWithoutConstructorInspection extends ClassInspection { + private final ClassWithoutConstructorFix fix = new ClassWithoutConstructorFix(); + + public String getDisplayName() { + return "Class without constructor"; + } + + public String getGroupDisplayName() { + return GroupNames.CLASSLAYOUT_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "#ref has no constructor #loc"; + } + + protected InspectionGadgetsFix buildFix(PsiElement location) { + return fix; + } + + private static class ClassWithoutConstructorFix extends InspectionGadgetsFix { + public String getName() { + return "Create empty constructor"; + } + + public void applyFix(Project project, ProblemDescriptor descriptor) { + try { + final PsiElement classIdentifier = descriptor.getPsiElement(); + final PsiClass psiClass = (PsiClass) classIdentifier.getParent(); + final PsiManager psiManager = PsiManager.getInstance(project); + final PsiElementFactory factory = psiManager.getElementFactory(); + final PsiMethod constructor = factory.createConstructor(); + psiClass.add(constructor); + final CodeStyleManager styleManager = psiManager.getCodeStyleManager(); + styleManager.reformat(constructor); + } catch (IncorrectOperationException e) { + final Class aClass = getClass(); + final String className = aClass.getName(); + final Logger logger = Logger.getInstance(className); + logger.error(e); + } + } + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new ClassWithoutConstructorVisitor(this, inspectionManager, onTheFly); + } + + private static class ClassWithoutConstructorVisitor extends BaseInspectionVisitor { + private ClassWithoutConstructorVisitor(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.isEnum() || aClass.isAnnotationType()) { + return; + } + if (aClass.getNameIdentifier() == null) { + return; //a very hacky test for anonymous classes + } + if (classHasConstructor(aClass)) { + return; + } + registerClassError(aClass); + } + + private static boolean classHasConstructor(PsiClass aClass) { + final PsiMethod[] methods = aClass.getMethods(); + for (int i = 0; i < methods.length; i++) { + final PsiMethod method = methods[i]; + if (method.isConstructor()) { + return true; + } + } + return false; + } + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/classlayout/ClassWithoutNoArgConstructorInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/classlayout/ClassWithoutNoArgConstructorInspection.java new file mode 100644 index 000000000000..7913cfd2ca62 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/classlayout/ClassWithoutNoArgConstructorInspection.java @@ -0,0 +1,65 @@ +package com.siyeh.ig.classlayout; + +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; + +public class ClassWithoutNoArgConstructorInspection extends ClassInspection { + + public String getDisplayName() { + return "Class without no-arg constructor"; + } + + public String getGroupDisplayName() { + return GroupNames.CLASSLAYOUT_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "#ref has no no-arg constructor #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new ClassWithoutNoArgConstructorVisitor(this, inspectionManager, onTheFly); + } + + private static class ClassWithoutNoArgConstructorVisitor extends BaseInspectionVisitor { + private ClassWithoutNoArgConstructorVisitor(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.isEnum() || aClass.isAnnotationType()) { + return; + } + if (aClass.getNameIdentifier() == null) { + return; //a very hacky test for anonymous classes + } + if (classHasNoArgConstructor(aClass)) { + return; + } + registerClassError(aClass); + } + + private static boolean classHasNoArgConstructor(PsiClass aClass) { + final PsiMethod[] methods = aClass.getMethods(); + for (int i = 0; i < methods.length; i++) { + final PsiMethod method = methods[i]; + if (method.isConstructor()) { + final PsiParameterList parameterList = method.getParameterList(); + if (parameterList != null) { + final PsiParameter[] parameters = parameterList.getParameters(); + if (parameters != null && parameters.length == 0) { + return true; + } + } + } + } + return false; + } + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/classlayout/ConstantDeclaredInAbstractClassInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/classlayout/ConstantDeclaredInAbstractClassInspection.java new file mode 100644 index 000000000000..6911f4bbbc01 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/classlayout/ConstantDeclaredInAbstractClassInspection.java @@ -0,0 +1,53 @@ +package com.siyeh.ig.classlayout; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.psi.*; +import com.siyeh.ig.BaseInspection; +import com.siyeh.ig.BaseInspectionVisitor; +import com.siyeh.ig.FieldInspection; +import com.siyeh.ig.GroupNames; + +public class ConstantDeclaredInAbstractClassInspection extends FieldInspection { + + public String getDisplayName() { + return "Constant declared in abstract class"; + } + + public String getGroupDisplayName() { + return GroupNames.CLASSLAYOUT_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "Constant '#ref' declared in abstract class #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new ConstantDeclaredInAbstractClassVisitor(this, inspectionManager, onTheFly); + } + + private static class ConstantDeclaredInAbstractClassVisitor extends BaseInspectionVisitor { + private ConstantDeclaredInAbstractClassVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitField(PsiField field) { + //no call to super, so we don't drill into anonymous classes + if (!field.hasModifierProperty(PsiModifier.STATIC) || + !field.hasModifierProperty(PsiModifier.PUBLIC) || + !field.hasModifierProperty(PsiModifier.FINAL)) { + return; + } + final PsiClass containingClass = field.getContainingClass(); + if (containingClass == null) { + return; + } + if (containingClass.isInterface() || containingClass.isAnnotationType()) { + return; + } + if (!containingClass.hasModifierProperty(PsiModifier.ABSTRACT)) { + return; + } + registerFieldError(field); + } + } +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/classlayout/ConstantDeclaredInInterfaceInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/classlayout/ConstantDeclaredInInterfaceInspection.java new file mode 100644 index 000000000000..dc6b33e4b5a9 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/classlayout/ConstantDeclaredInInterfaceInspection.java @@ -0,0 +1,47 @@ +package com.siyeh.ig.classlayout; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.psi.PsiClass; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiField; +import com.siyeh.ig.BaseInspection; +import com.siyeh.ig.BaseInspectionVisitor; +import com.siyeh.ig.FieldInspection; +import com.siyeh.ig.GroupNames; + +public class ConstantDeclaredInInterfaceInspection extends FieldInspection { + + public String getDisplayName() { + return "Constant declared in interface"; + } + + public String getGroupDisplayName() { + return GroupNames.CLASSLAYOUT_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "Constant '#ref' declared in interface #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new ConstantDeclaredInInterfaceVisitor(this, inspectionManager, onTheFly); + } + + private static class ConstantDeclaredInInterfaceVisitor extends BaseInspectionVisitor { + private ConstantDeclaredInInterfaceVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitField(PsiField field) { + //no call to super, so we don't drill into anonymous classes + final PsiClass containingClass = field.getContainingClass(); + if (containingClass == null) { + return; + } + if (!containingClass.isInterface() && !containingClass.isAnnotationType()) { + return; + } + registerFieldError(field); + } + } +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/classlayout/EmptyClassInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/classlayout/EmptyClassInspection.java new file mode 100644 index 000000000000..a8bff0a79754 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/classlayout/EmptyClassInspection.java @@ -0,0 +1,53 @@ +package com.siyeh.ig.classlayout; + +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; + +public class EmptyClassInspection extends ClassInspection { + + public String getDisplayName() { + return "Empty class"; + } + + public String getGroupDisplayName() { + return GroupNames.CLASSLAYOUT_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "Class #ref is empty #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new EmptyClassVisitor(this, inspectionManager, onTheFly); + } + + private static class EmptyClassVisitor extends BaseInspectionVisitor { + private EmptyClassVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitClass(PsiClass aClass) { + //don't call super, to prevent drilldown + if (aClass.isInterface() || aClass.isEnum() || aClass.isAnnotationType()) { + return; + } + final PsiMethod[] constructors = aClass.getConstructors(); + if (constructors != null && constructors.length > 0) { + return; + } + final PsiMethod[] methods = aClass.getMethods(); + if (methods != null && methods.length > 0) { + return; + } + final PsiField[] fields = aClass.getFields(); + if (fields != null && fields.length > 0) { + return; + } + registerClassError(aClass); + } + } +} \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/classlayout/FinalClassInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/classlayout/FinalClassInspection.java new file mode 100644 index 000000000000..d291a3368840 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/classlayout/FinalClassInspection.java @@ -0,0 +1,50 @@ +package com.siyeh.ig.classlayout; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.openapi.diagnostic.Logger; +import com.intellij.psi.PsiClass; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiModifier; +import com.siyeh.ig.*; +import com.siyeh.ig.fixes.RemoveModifierFix; + +public class FinalClassInspection extends MethodInspection { + private static final Logger s_logger = + Logger.getInstance("FinalClassInspection"); + + public String getDisplayName() { + return "'final' class"; + } + + public String getGroupDisplayName() { + return GroupNames.CLASSLAYOUT_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "Class declared '#ref' #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new FinalStaticMethodVisitor(this, inspectionManager, onTheFly); + } + + public InspectionGadgetsFix buildFix(PsiElement location) { + return new RemoveModifierFix(location); + } + + private static class FinalStaticMethodVisitor extends BaseInspectionVisitor { + private FinalStaticMethodVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitClass(PsiClass aClass) { + //no call to super, so we don't drill into inner classes + if (!aClass.hasModifierProperty(PsiModifier.FINAL)) { + return; + } + registerModifierError(PsiModifier.FINAL, aClass); + } + + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/classlayout/FinalMethodInFinalClassInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/classlayout/FinalMethodInFinalClassInspection.java new file mode 100644 index 000000000000..03f3352209a9 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/classlayout/FinalMethodInFinalClassInspection.java @@ -0,0 +1,55 @@ +package com.siyeh.ig.classlayout; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.psi.PsiClass; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiMethod; +import com.intellij.psi.PsiModifier; +import com.siyeh.ig.*; +import com.siyeh.ig.fixes.RemoveModifierFix; + +public class FinalMethodInFinalClassInspection extends MethodInspection { + public String getDisplayName() { + return "'final' method in 'final' class"; + } + + public String getGroupDisplayName() { + return GroupNames.CLASSLAYOUT_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "Method declared '#ref' in 'final' class #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new FinalMethodInFinalClassVisitor(this, inspectionManager, onTheFly); + } + + public InspectionGadgetsFix buildFix(PsiElement location) { + return new RemoveModifierFix(location); + } + + private static class FinalMethodInFinalClassVisitor extends BaseInspectionVisitor { + private FinalMethodInFinalClassVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitMethod(PsiMethod method) { + //no call to super, so we don't drill into anonymous classes + if (!method.hasModifierProperty(PsiModifier.FINAL)) { + return; + } + final PsiClass containingClass = method.getContainingClass(); + if (containingClass == null) { + return; + } + if (!containingClass.hasModifierProperty(PsiModifier.FINAL)) { + return; + } + registerModifierError(PsiModifier.FINAL, method); + + } + + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/classlayout/FinalMethodInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/classlayout/FinalMethodInspection.java new file mode 100644 index 000000000000..ed39e3825668 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/classlayout/FinalMethodInspection.java @@ -0,0 +1,50 @@ +package com.siyeh.ig.classlayout; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.openapi.diagnostic.Logger; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiMethod; +import com.intellij.psi.PsiModifier; +import com.siyeh.ig.*; +import com.siyeh.ig.fixes.RemoveModifierFix; + +public class FinalMethodInspection extends MethodInspection { + private static final Logger s_logger = + Logger.getInstance("FinalMethodnspection"); + + public String getDisplayName() { + return "'final' method"; + } + + public String getGroupDisplayName() { + return GroupNames.CLASSLAYOUT_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "Method declared '#ref' #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new FinalMethodVisitor(this, inspectionManager, onTheFly); + } + + public InspectionGadgetsFix buildFix(PsiElement location) { + return new RemoveModifierFix(location); + } + + private static class FinalMethodVisitor extends BaseInspectionVisitor { + private FinalMethodVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitMethod(PsiMethod method) { + //no call to super, so we don't drill into anonymous classes + if (!method.hasModifierProperty(PsiModifier.FINAL)) { + return; + } + registerModifierError(PsiModifier.FINAL, method); + } + + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/classlayout/FinalPrivateMethodInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/classlayout/FinalPrivateMethodInspection.java new file mode 100644 index 000000000000..c5401b553c23 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/classlayout/FinalPrivateMethodInspection.java @@ -0,0 +1,48 @@ +package com.siyeh.ig.classlayout; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiMethod; +import com.intellij.psi.PsiModifier; +import com.siyeh.ig.*; +import com.siyeh.ig.fixes.RemoveModifierFix; + +public class FinalPrivateMethodInspection extends MethodInspection { + public String getDisplayName() { + return "'private' method declared 'final'"; + } + + public String getGroupDisplayName() { + return GroupNames.CLASSLAYOUT_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "'private' method declared '#ref' #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new FinalStaticMethodVisitor(this, inspectionManager, onTheFly); + } + + public InspectionGadgetsFix buildFix(PsiElement location) { + return new RemoveModifierFix(location); + } + + private static class FinalStaticMethodVisitor extends BaseInspectionVisitor { + private FinalStaticMethodVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitMethod(PsiMethod method) { + //no call to super, so we don't drill into anonymous classes + if (!method.hasModifierProperty(PsiModifier.FINAL) + || !method.hasModifierProperty(PsiModifier.PRIVATE)) { + return; + } + registerModifierError(PsiModifier.FINAL, method); + + } + + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/classlayout/FinalStaticMethodInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/classlayout/FinalStaticMethodInspection.java new file mode 100644 index 000000000000..4bd40c1c3c52 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/classlayout/FinalStaticMethodInspection.java @@ -0,0 +1,47 @@ +package com.siyeh.ig.classlayout; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiMethod; +import com.intellij.psi.PsiModifier; +import com.siyeh.ig.*; +import com.siyeh.ig.fixes.RemoveModifierFix; + +public class FinalStaticMethodInspection extends MethodInspection { + public String getDisplayName() { + return "'static' method declared 'final'"; + } + + public String getGroupDisplayName() { + return GroupNames.CLASSLAYOUT_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "'static' method declared '#ref' #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new FinalStaticMethodVisitor(this, inspectionManager, onTheFly); + } + + public InspectionGadgetsFix buildFix(PsiElement location) { + return new RemoveModifierFix(location); + } + + private static class FinalStaticMethodVisitor extends BaseInspectionVisitor { + private FinalStaticMethodVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitMethod(PsiMethod method) { + //no call to super, so we don't drill into anonymous classes + if (!method.hasModifierProperty(PsiModifier.FINAL) + || !method.hasModifierProperty(PsiModifier.STATIC)) { + return; + } + registerModifierError(PsiModifier.FINAL, method); + } + + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/classlayout/InnerClassOnInterfaceInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/classlayout/InnerClassOnInterfaceInspection.java new file mode 100644 index 000000000000..67c58375d719 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/classlayout/InnerClassOnInterfaceInspection.java @@ -0,0 +1,61 @@ +package com.siyeh.ig.classlayout; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.psi.PsiClass; +import com.intellij.psi.PsiElement; +import com.siyeh.ig.*; +import com.siyeh.ig.fixes.MoveClassFix; +import com.siyeh.ig.psiutils.ClassUtils; + +public class InnerClassOnInterfaceInspection extends ClassInspection { + private final MoveClassFix fix = new MoveClassFix(); + + public String getDisplayName() { + return "Inner class of interface"; + } + + public String getGroupDisplayName() { + return GroupNames.CLASSLAYOUT_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + final PsiClass innerClass = (PsiClass) location.getParent(); + final PsiClass parentInterface = + ClassUtils.getContainingClass(innerClass); + final String interfaceName = parentInterface.getName(); + return "Interface " + interfaceName + " has inner class #ref #loc"; + } + + protected InspectionGadgetsFix buildFix(PsiElement location) { + return fix; + } + + protected boolean buildQuickFixesOnlyForOnTheFlyErrors() { + return true; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new InnerClassOnInterfaceVisitor(this, inspectionManager, onTheFly); + } + + private static class InnerClassOnInterfaceVisitor extends BaseInspectionVisitor { + private InnerClassOnInterfaceVisitor(BaseInspection inspection, + InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitClass(PsiClass aClass) { + // no call to super, so that it doesn't drill down to inner classes + if (!aClass.isInterface()||aClass.isAnnotationType()) { + return; + } + final PsiClass[] innerClasses = aClass.getInnerClasses(); + for (int i = 0; i < innerClasses.length; i++) { + registerClassError(innerClasses[i]); + } + } + + + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/classlayout/LimitedScopeInnerClassInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/classlayout/LimitedScopeInnerClassInspection.java new file mode 100644 index 000000000000..6529ee2c13be --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/classlayout/LimitedScopeInnerClassInspection.java @@ -0,0 +1,39 @@ +package com.siyeh.ig.classlayout; + +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; + +public class LimitedScopeInnerClassInspection extends ClassInspection { + + public String getDisplayName() { + return "Limited-scope class"; + } + + public String getGroupDisplayName() { + return GroupNames.CLASSLAYOUT_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "Limited-scope inner class #ref #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new LimitedScopeInnerClassVisitor(this, inspectionManager, onTheFly); + } + + private static class LimitedScopeInnerClassVisitor extends BaseInspectionVisitor { + private LimitedScopeInnerClassVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitClass(PsiClass aClass) { + if (aClass.getParent() instanceof PsiDeclarationStatement) { + registerClassError(aClass); + } + } + } +} \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/classlayout/MarkerInterfaceInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/classlayout/MarkerInterfaceInspection.java new file mode 100644 index 000000000000..bb46c2f9997b --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/classlayout/MarkerInterfaceInspection.java @@ -0,0 +1,53 @@ +package com.siyeh.ig.classlayout; + +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; + +public class MarkerInterfaceInspection extends ClassInspection { + + public String getDisplayName() { + return "Marker interface"; + } + + public String getGroupDisplayName() { + return GroupNames.CLASSLAYOUT_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "Marker interface #ref #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new MarkerInterfaceVisitor(this, inspectionManager, onTheFly); + } + + private static class MarkerInterfaceVisitor extends BaseInspectionVisitor { + private MarkerInterfaceVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitClass(PsiClass aClass) { + // no call to super, so that it doesn't drill down to inner classes + if (!aClass.isInterface() || aClass.isAnnotationType()) { + return; + } + final PsiField[] fields = aClass.getFields(); + if (fields.length != 0) { + return; + } + final PsiMethod[] methods = aClass.getMethods(); + if (methods.length != 0) { + return; + } + final PsiClassType[] extendsList = aClass.getExtendsListTypes(); + if (extendsList.length > 1) { + return; + } + registerClassError(aClass); + } + } +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/classlayout/MultipleTopLevelClassesInFileInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/classlayout/MultipleTopLevelClassesInFileInspection.java new file mode 100644 index 000000000000..ff5f7ee01372 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/classlayout/MultipleTopLevelClassesInFileInspection.java @@ -0,0 +1,66 @@ +package com.siyeh.ig.classlayout; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.psi.PsiClass; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiJavaFile; +import com.siyeh.ig.*; +import com.siyeh.ig.fixes.MoveClassFix; + +public class MultipleTopLevelClassesInFileInspection extends ClassInspection { + private final MoveClassFix fix = new MoveClassFix(); + + public String getDisplayName() { + return "Multiple top level classes in single file"; + } + + public String getGroupDisplayName() { + return GroupNames.CLASSLAYOUT_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "Multiple top level classes in file"; + } + + protected InspectionGadgetsFix buildFix(PsiElement location) { + return fix; + } + + protected boolean buildQuickFixesOnlyForOnTheFlyErrors() { + return true; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new MultipleTopLevelClassesInFileVisitor(this, inspectionManager, onTheFly); + } + + private static class MultipleTopLevelClassesInFileVisitor extends BaseInspectionVisitor { + + private MultipleTopLevelClassesInFileVisitor(BaseInspection inspection, + InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitClass(PsiClass aClass) { + // no call to super, so that it doesn't drill down to inner classes + if (!(aClass.getParent() instanceof PsiJavaFile)) { + return; + } + int numClasses = 0; + final PsiJavaFile file = (PsiJavaFile) aClass.getParent(); + final PsiElement[] children = file.getChildren(); + for (int i = 0; i < children.length; i++) { + final PsiElement child = children[i]; + if (child instanceof PsiClass) { + numClasses++; + } + } + if (numClasses <= 1) { + return; + } + registerClassError(aClass); + } + + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/classlayout/NonProtectedConstructorInAbstractClassInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/classlayout/NonProtectedConstructorInAbstractClassInspection.java new file mode 100644 index 000000000000..14ff948a4c5a --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/classlayout/NonProtectedConstructorInAbstractClassInspection.java @@ -0,0 +1,98 @@ +package com.siyeh.ig.classlayout; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.codeInspection.ProblemDescriptor; +import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.project.Project; +import com.intellij.psi.*; +import com.intellij.util.IncorrectOperationException; +import com.siyeh.ig.*; +import com.siyeh.ig.ui.SingleCheckboxOptionsPanel; + +import javax.swing.*; + +public class NonProtectedConstructorInAbstractClassInspection extends MethodInspection { + public boolean m_ignoreNonPublicClasses = false; + private static final Logger s_logger = + Logger.getInstance("NonProtectedConstructorInAbstractClassInspection"); + private final MakeProtectedFix fix = new MakeProtectedFix(); + + public String getDisplayName() { + return "Constructor not 'protected' in 'abstract' class"; + } + + public String getGroupDisplayName() { + return GroupNames.CLASSLAYOUT_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "Constructor '#ref' is not declared 'protected' in 'abstract' class #loc"; + } + + public JComponent createOptionsPanel() { + return new SingleCheckboxOptionsPanel("Ignore for non-public classes", + this, "m_ignoreNonPublicClasses"); + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new NonProtectedConstructorInAbstractClassVisitor(this, inspectionManager, onTheFly); + } + + public InspectionGadgetsFix buildFix(PsiElement location) { + return fix; + } + + private static class MakeProtectedFix extends InspectionGadgetsFix { + public String getName() { + return "Make 'protected'"; + } + + public void applyFix(Project project, ProblemDescriptor descriptor) { + final PsiElement constructorIdentifier = descriptor.getPsiElement(); + try { + final PsiMethod constructor = (PsiMethod) constructorIdentifier.getParent(); + final PsiModifierList modifiers = constructor.getModifierList(); + modifiers.setModifierProperty(PsiModifier.PUBLIC, false); + modifiers.setModifierProperty(PsiModifier.PRIVATE, false); + modifiers.setModifierProperty(PsiModifier.PROTECTED, true); + } catch (IncorrectOperationException e) { + s_logger.error(e); + } + } + } + + private class NonProtectedConstructorInAbstractClassVisitor extends BaseInspectionVisitor { + private NonProtectedConstructorInAbstractClassVisitor(BaseInspection inspection, + InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitMethod(PsiMethod method) { + //no call to super, so we don't drill into anonymous classes + if (!method.isConstructor()) { + return; + } + if (method.hasModifierProperty(PsiModifier.PROTECTED) + || method.hasModifierProperty(PsiModifier.PRIVATE)) { + return; + } + final PsiClass containingClass = method.getContainingClass(); + if (containingClass == null) { + return; + } + if (m_ignoreNonPublicClasses && !containingClass.hasModifierProperty(PsiModifier.PUBLIC)) { + return; + } + if (!containingClass.hasModifierProperty(PsiModifier.ABSTRACT)) { + return; + } + if (containingClass.isEnum()) { + return; + } + registerMethodError(method); + } + + } + + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/classlayout/NoopMethodInAbstractClassInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/classlayout/NoopMethodInAbstractClassInspection.java new file mode 100644 index 000000000000..d18690b3f51b --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/classlayout/NoopMethodInAbstractClassInspection.java @@ -0,0 +1,63 @@ +package com.siyeh.ig.classlayout; + +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.MethodInspection; + +public class NoopMethodInAbstractClassInspection extends MethodInspection { + + public String getDisplayName() { + return "No-op method in abstract class"; + } + + public String getGroupDisplayName() { + return GroupNames.CLASSLAYOUT_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "No-op Method '#ref' should be made abstract #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new NoopMethodInAbstractClassVisitor(this, inspectionManager, onTheFly); + } + + private static class NoopMethodInAbstractClassVisitor extends BaseInspectionVisitor { + private NoopMethodInAbstractClassVisitor(BaseInspection inspection, + InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitMethod(PsiMethod method) { + //no call to super, so we don't drill into anonymous classes + if (method.isConstructor()) { + return; + } + final PsiClass containingClass = method.getContainingClass(); + if (containingClass.isInterface() || containingClass.isAnnotationType()) { + return; + } + if (!containingClass.hasModifierProperty(PsiModifier.ABSTRACT)) { + return; + } + if (method.hasModifierProperty(PsiModifier.ABSTRACT)) { + return; + } + final PsiCodeBlock body = method.getBody(); + if (body == null) { + return; + } + final PsiStatement[] statements = body.getStatements(); + if (statements == null) { + return; + } + if (statements.length > 0) { + return; + } + registerMethodError(method); + } + } +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/classlayout/ProtectedMemberInFinalClassInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/classlayout/ProtectedMemberInFinalClassInspection.java new file mode 100644 index 000000000000..3c9ae80a6615 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/classlayout/ProtectedMemberInFinalClassInspection.java @@ -0,0 +1,77 @@ +package com.siyeh.ig.classlayout; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.psi.*; +import com.intellij.psi.util.PsiSuperMethodUtil; +import com.siyeh.ig.*; +import com.siyeh.ig.fixes.RemoveModifierFix; + +public class ProtectedMemberInFinalClassInspection extends MethodInspection { + + public String getDisplayName() { + return "'protected' member in 'final' class"; + } + + public String getGroupDisplayName() { + return GroupNames.CLASSLAYOUT_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "Class member declared '#ref' in 'final' class #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new ProtectedMemberInFinalClassVisitor(this, inspectionManager, onTheFly); + } + + public InspectionGadgetsFix buildFix(PsiElement location) { + return new RemoveModifierFix(location); + } + + private static class ProtectedMemberInFinalClassVisitor extends BaseInspectionVisitor { + private ProtectedMemberInFinalClassVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitMethod(PsiMethod method) { + //no call to super, so we don't drill into anonymous classes + if (!method.hasModifierProperty(PsiModifier.PROTECTED)) { + return; + } + final PsiClass containingClass = method.getContainingClass(); + if (containingClass == null) { + return; + } + if (!containingClass.hasModifierProperty(PsiModifier.FINAL)) { + return; + } + if (methodOverrides(method)) { + return; + } + registerModifierError(PsiModifier.PROTECTED, method); + + } + + + private static boolean methodOverrides(PsiMethod meth) { + final PsiMethod[] superMethods = PsiSuperMethodUtil.findSuperMethods(meth); + return superMethods != null && superMethods.length != 0; + } + + public void visitField(PsiField field) { + //no call to super, so we don't drill into anonymous classes + if (!field.hasModifierProperty(PsiModifier.PROTECTED)) { + return; + } + final PsiClass containingClass = field.getContainingClass(); + if (containingClass == null) { + return; + } + if (!containingClass.hasModifierProperty(PsiModifier.FINAL)) { + return; + } + registerModifierError(PsiModifier.PROTECTED, field); + } + + } +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/classlayout/PublicConstructorInNonPublicClassInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/classlayout/PublicConstructorInNonPublicClassInspection.java new file mode 100644 index 000000000000..adad25d80282 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/classlayout/PublicConstructorInNonPublicClassInspection.java @@ -0,0 +1,59 @@ +package com.siyeh.ig.classlayout; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.psi.*; +import com.siyeh.ig.*; +import com.siyeh.ig.fixes.RemoveModifierFix; + +public class PublicConstructorInNonPublicClassInspection extends MethodInspection { + public String getDisplayName() { + return "'public' constructor in non-'public' class"; + } + + public String getGroupDisplayName() { + return GroupNames.CLASSLAYOUT_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + final PsiModifierList modifiers = (PsiModifierList) location.getParent(); + final PsiMethod meth = (PsiMethod) modifiers.getParent(); + return "Constructor is declared '#ref' in non-'public' class " + meth.getName() + " #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new PublicConstructorInNonPublicClassVisitor(this, inspectionManager, onTheFly); + } + + public InspectionGadgetsFix buildFix(PsiElement location) { + return new RemoveModifierFix(location); + } + + + private static class PublicConstructorInNonPublicClassVisitor extends BaseInspectionVisitor { + private PublicConstructorInNonPublicClassVisitor(BaseInspection inspection, + InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitMethod(PsiMethod method) { + //no call to super, so we don't drill into anonymous classes + if (!method.isConstructor()) { + return; + } + if (!method.hasModifierProperty(PsiModifier.PUBLIC)) { + return; + } + final PsiClass containingClass = method.getContainingClass(); + if (containingClass == null) { + return; + } + if (containingClass.hasModifierProperty(PsiModifier.PUBLIC)) { + return; + } + registerModifierError(PsiModifier.PUBLIC, method); + + } + + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/classlayout/SingletonInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/classlayout/SingletonInspection.java new file mode 100644 index 000000000000..303e6f397453 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/classlayout/SingletonInspection.java @@ -0,0 +1,44 @@ +package com.siyeh.ig.classlayout; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.psi.PsiClass; +import com.intellij.psi.PsiElement; +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.SingletonUtil; + +public class SingletonInspection extends ClassInspection { + + public String getDisplayName() { + return "Singleton"; + } + + public String getGroupDisplayName() { + return GroupNames.CLASSLAYOUT_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "Class #ref is a singleton #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new SingletonVisitor(this, inspectionManager, onTheFly); + } + + private static class SingletonVisitor extends BaseInspectionVisitor { + private SingletonVisitor(BaseInspection inspection, + InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitClass(PsiClass aClass) { + // no call to super, so that it doesn't drill down to inner classes + if (!SingletonUtil.isSingleton(aClass)) { + return; + } + registerClassError(aClass); + } + } +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/classlayout/StaticInheritanceInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/classlayout/StaticInheritanceInspection.java new file mode 100644 index 000000000000..25ce664f974a --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/classlayout/StaticInheritanceInspection.java @@ -0,0 +1,73 @@ +package com.siyeh.ig.classlayout; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.psi.PsiClass; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiJavaCodeReferenceElement; +import com.intellij.psi.PsiReferenceList; +import com.siyeh.ig.BaseInspection; +import com.siyeh.ig.BaseInspectionVisitor; +import com.siyeh.ig.ClassInspection; +import com.siyeh.ig.GroupNames; + +public class StaticInheritanceInspection extends ClassInspection { + + public String getDisplayName() { + return "Static inheritance"; + } + + public String getGroupDisplayName() { + return GroupNames.CLASSLAYOUT_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "Interface #ref is implemented only for it's static constants #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new StaticInheritanceVisitor(this, inspectionManager, onTheFly); + } + + private static class StaticInheritanceVisitor extends BaseInspectionVisitor { + private StaticInheritanceVisitor(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 + final PsiReferenceList implementsList = aClass.getImplementsList(); + if (implementsList == null) { + return; + } + final PsiJavaCodeReferenceElement[] refs = implementsList.getReferenceElements(); + for (int i = 0; i < refs.length; i++) { + final PsiJavaCodeReferenceElement ref = refs[i]; + final PsiClass iface = (PsiClass) ref.resolve(); + if (iface != null) { + if (interfaceContainsOnlyConstants(iface)) { + registerError(ref); + } + } + } + } + + private boolean interfaceContainsOnlyConstants(PsiClass iface) { + if (iface.getAllFields().length == 0) { + // ignore it, it's either a true interface or just a marker + return false; + } + if (iface.getMethods().length != 0) { + return false; + } + final PsiClass[] parentInterfaces = iface.getInterfaces(); + for (int i = 0; i < parentInterfaces.length; i++) { + final PsiClass parentInterface = parentInterfaces[i]; + if (!interfaceContainsOnlyConstants(parentInterface)) { + return false; + } + } + return true; + } + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/classlayout/StaticNonFinalFieldInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/classlayout/StaticNonFinalFieldInspection.java new file mode 100644 index 000000000000..2fbc44c407d6 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/classlayout/StaticNonFinalFieldInspection.java @@ -0,0 +1,44 @@ +package com.siyeh.ig.classlayout; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiField; +import com.intellij.psi.PsiModifier; +import com.siyeh.ig.BaseInspection; +import com.siyeh.ig.BaseInspectionVisitor; +import com.siyeh.ig.FieldInspection; +import com.siyeh.ig.GroupNames; + +public class StaticNonFinalFieldInspection extends FieldInspection { + + public String getDisplayName() { + return "'static', non-'final' field"; + } + + public String getGroupDisplayName() { + return GroupNames.CLASSLAYOUT_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "Static non-final field #ref #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new StaticNonFinalFieldVisitor(this, inspectionManager, onTheFly); + } + + private static class StaticNonFinalFieldVisitor extends BaseInspectionVisitor { + private StaticNonFinalFieldVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitField(PsiField field) { + if (!field.hasModifierProperty(PsiModifier.STATIC) || + field.hasModifierProperty(PsiModifier.FINAL)) { + return; + } + registerFieldError(field); + } + + } +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/classlayout/UtilityClassInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/classlayout/UtilityClassInspection.java new file mode 100644 index 000000000000..8f908a4c986c --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/classlayout/UtilityClassInspection.java @@ -0,0 +1,44 @@ +package com.siyeh.ig.classlayout; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.psi.PsiClass; +import com.intellij.psi.PsiElement; +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.UtilityClassUtil; + +public class UtilityClassInspection extends ClassInspection { + + public String getDisplayName() { + return "Utility class"; + } + + public String getGroupDisplayName() { + return GroupNames.CLASSLAYOUT_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "Class #ref has only 'static' members, indicating procedural construction #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new UtilityClassVisitor(this, inspectionManager, onTheFly); + } + + private static class UtilityClassVisitor extends BaseInspectionVisitor { + private UtilityClassVisitor(BaseInspection inspection, + InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitClass(PsiClass aClass) { + // no call to super, so that it doesn't drill down to inner classes + if (!UtilityClassUtil.isUtilityClass(aClass)) { + return; + } + registerClassError(aClass); + } + } +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/classlayout/UtilityClassWithPublicConstructorInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/classlayout/UtilityClassWithPublicConstructorInspection.java new file mode 100644 index 000000000000..a01fb4f4a793 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/classlayout/UtilityClassWithPublicConstructorInspection.java @@ -0,0 +1,102 @@ +package com.siyeh.ig.classlayout; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.codeInspection.ProblemDescriptor; +import com.intellij.psi.*; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.diagnostic.Logger; +import com.intellij.util.IncorrectOperationException; +import com.siyeh.ig.*; +import com.siyeh.ig.psiutils.UtilityClassUtil; + +public class UtilityClassWithPublicConstructorInspection extends ClassInspection { + + public String getDisplayName() { + return "Utility class with public constructor"; + } + + public String getGroupDisplayName() { + return GroupNames.CLASSLAYOUT_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "Class #ref has only static members, and a public constructor #loc"; + } + + protected InspectionGadgetsFix buildFix(PsiElement location) { + final PsiClass psiClass = (PsiClass) location.getParent(); + if (psiClass.getConstructors().length > 1) { + return new UtilityClassWithPublicConstructorFix(true); + } else { + return new UtilityClassWithPublicConstructorFix(false); + } + } + + private static class UtilityClassWithPublicConstructorFix extends InspectionGadgetsFix { + private final boolean m_multipleConstructors; + + UtilityClassWithPublicConstructorFix(boolean multipleConstructors) { + super(); + m_multipleConstructors = multipleConstructors; + } + + public String getName() { + if (m_multipleConstructors) { + return "Make constructors private"; + } else { + return "Make constructor private"; + } + } + + public void applyFix(Project project, ProblemDescriptor descriptor) { + try { + final PsiElement classNameIdentifer = descriptor.getPsiElement(); + final PsiClass psiClass = (PsiClass) classNameIdentifer.getParent(); + final PsiMethod[] constructors = psiClass.getConstructors(); + for (int i = 0; i < constructors.length; i++) { + final PsiModifierList modifierList = constructors[i].getModifierList(); + modifierList.setModifierProperty(PsiModifier.PRIVATE, true); + } + } catch (IncorrectOperationException e) { + final Class aClass = getClass(); + final String className = aClass.getName(); + final Logger logger = Logger.getInstance(className); + logger.error(e); + } + } + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new StaticClassWithPublicConstructorVisitor(this, inspectionManager, onTheFly); + } + + private static class StaticClassWithPublicConstructorVisitor extends BaseInspectionVisitor { + private StaticClassWithPublicConstructorVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitClass(PsiClass aClass) { + // no call to super, so that it doesn't drill down to inner classes + if (!UtilityClassUtil.isUtilityClass(aClass)) { + return; + } + + if (!hasPublicConstructor(aClass)) { + return; + } + registerClassError(aClass); + } + + } + + private static boolean hasPublicConstructor(PsiClass aClass) { + final PsiMethod[] methods = aClass.getMethods(); + for (int i = 0; i < methods.length; i++) { + final PsiMethod method = methods[i]; + if (method.isConstructor() && method.hasModifierProperty(PsiModifier.PUBLIC)) { + return true; + } + } + return false; + } +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/classlayout/UtilityClassWithoutPrivateConstructorInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/classlayout/UtilityClassWithoutPrivateConstructorInspection.java new file mode 100644 index 000000000000..de609c31e0e5 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/classlayout/UtilityClassWithoutPrivateConstructorInspection.java @@ -0,0 +1,92 @@ +package com.siyeh.ig.classlayout; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.codeInspection.ProblemDescriptor; +import com.intellij.psi.*; +import com.intellij.psi.codeStyle.CodeStyleManager; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.diagnostic.Logger; +import com.intellij.util.IncorrectOperationException; +import com.siyeh.ig.*; +import com.siyeh.ig.psiutils.UtilityClassUtil; + +public class UtilityClassWithoutPrivateConstructorInspection extends ClassInspection { + private final UtilityClassWithoutPrivateConstructorFix fix = new UtilityClassWithoutPrivateConstructorFix(); + + public String getDisplayName() { + return "Utility class without private constructor"; + } + + public String getGroupDisplayName() { + return GroupNames.CLASSLAYOUT_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "Class #ref has only 'static' members, and lacks a 'private' constructor #loc"; + } + + protected InspectionGadgetsFix buildFix(PsiElement location) { + return fix; + } + + private static class UtilityClassWithoutPrivateConstructorFix extends InspectionGadgetsFix { + public String getName() { + return "Create empty private constructor"; + } + + public void applyFix(Project project, ProblemDescriptor descriptor) { + try { + final PsiElement classNameIdentifier = descriptor.getPsiElement(); + final PsiClass psiClass = (PsiClass) classNameIdentifier.getParent(); + final PsiManager psiManager = PsiManager.getInstance(project); + final PsiElementFactory factory = psiManager.getElementFactory(); + final PsiMethod constructor = factory.createConstructor(); + final PsiModifierList modifierList = constructor.getModifierList(); + modifierList.setModifierProperty(PsiModifier.PRIVATE, true); + psiClass.add(constructor); + final CodeStyleManager styleManager = psiManager.getCodeStyleManager(); + styleManager.reformat(constructor); + } catch (IncorrectOperationException e) { + final Class aClass = getClass(); + final String className = aClass.getName(); + final Logger logger = Logger.getInstance(className); + logger.error(e); + } + } + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new StaticClassWithoutPrivateConstructorVisitor(this, inspectionManager, onTheFly); + } + + private static class StaticClassWithoutPrivateConstructorVisitor extends BaseInspectionVisitor { + private StaticClassWithoutPrivateConstructorVisitor(BaseInspection inspection, + InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitClass(PsiClass aClass) { + // no call to super, so that it doesn't drill down to inner classes + if (!UtilityClassUtil.isUtilityClass(aClass)) { + return; + } + + if (hasPrivateConstructor(aClass)) { + return; + } + registerClassError(aClass); + } + } + + private static boolean hasPrivateConstructor(PsiClass aClass) { + final PsiMethod[] methods = aClass.getMethods(); + for (int i = 0; i < methods.length; i++) { + final PsiMethod method = methods[i]; + if (method.isConstructor() && method.hasModifierProperty(PsiModifier.PRIVATE)) { + return true; + } + } + return false; + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/classmetrics/AnonymousClassComplexityInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/classmetrics/AnonymousClassComplexityInspection.java new file mode 100644 index 000000000000..b6b658a6b751 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/classmetrics/AnonymousClassComplexityInspection.java @@ -0,0 +1,101 @@ +package com.siyeh.ig.classmetrics; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.psi.*; +import com.siyeh.ig.*; +import com.siyeh.ig.fixes.MoveAnonymousToInnerClassFix; + +public class AnonymousClassComplexityInspection + extends ClassMetricInspection { + private static final int DEFAULT_COMPLEXITY_LIMIT = 3; + private final MoveAnonymousToInnerClassFix fix = new MoveAnonymousToInnerClassFix(); + + public String getDisplayName() { + return "Overly complex anonymous inner class"; + } + + public String getGroupDisplayName() { + return GroupNames.CLASSMETRICS_GROUP_NAME; + } + + protected int getDefaultLimit() { + return DEFAULT_COMPLEXITY_LIMIT; + } + + protected String getConfigurationLabel() { + return "Cyclomatic complexity limit:"; + } + + protected InspectionGadgetsFix buildFix(PsiElement location) { + return fix; + } + + protected boolean buildQuickFixesOnlyForOnTheFlyErrors() { + return true; + } + + public String buildErrorString(PsiElement location) { + final PsiClass aClass = (PsiClass) location.getParent(); + final int totalComplexity = calculateTotalComplexity(aClass); + return "Overly complex anonymous inner class(cyclomatic complexity = " + totalComplexity + ") #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new ClassComplexityVisitor(this, inspectionManager, onTheFly); + } + + private class ClassComplexityVisitor extends BaseInspectionVisitor { + private ClassComplexityVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitClass(PsiClass psiClass) { + // no call to super, to prevent double counting + } + + public void visitAnonymousClass(PsiAnonymousClass aClass) { + final int totalComplexity = calculateTotalComplexity(aClass); + if (totalComplexity <= getLimit()) { + return; + } + final PsiJavaCodeReferenceElement classNameIdentifier = + aClass.getBaseClassReference(); + registerError(classNameIdentifier); + } + + + } + + private static int calculateTotalComplexity(PsiClass aClass) { + final PsiMethod[] methods = aClass.getMethods(); + int totalComplexity = calculateComplexityForMethods(methods); + totalComplexity += calculateInitializerComplexity(aClass); + return totalComplexity; + } + + private static int calculateInitializerComplexity(PsiClass aClass) { + final ComplexityVisitor visitor = new ComplexityVisitor(); + int complexity = 0; + final PsiClassInitializer[] initializers = aClass.getInitializers(); + for (int i = 0; i < initializers.length; i++) { + final PsiClassInitializer initializer = initializers[i]; + visitor.reset(); + initializer.accept(visitor); + complexity += visitor.getComplexity(); + } + return complexity; + } + + private static int calculateComplexityForMethods(PsiMethod[] methods) { + final ComplexityVisitor visitor = new ComplexityVisitor(); + int complexity = 0; + for (int i = 0; i < methods.length; i++) { + final PsiMethod method = methods[i]; + visitor.reset(); + method.accept(visitor); + complexity += visitor.getComplexity(); + } + return complexity; + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/classmetrics/AnonymousClassMethodCountInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/classmetrics/AnonymousClassMethodCountInspection.java new file mode 100644 index 000000000000..dff0cd7ce630 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/classmetrics/AnonymousClassMethodCountInspection.java @@ -0,0 +1,81 @@ +package com.siyeh.ig.classmetrics; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.psi.*; +import com.siyeh.ig.*; +import com.siyeh.ig.fixes.MoveAnonymousToInnerClassFix; + +public class AnonymousClassMethodCountInspection + extends ClassMetricInspection { + private static final int DEFAULT_METHOD_COUNT_LIMIT = 1; + private final MoveAnonymousToInnerClassFix fix = new MoveAnonymousToInnerClassFix(); + + public String getDisplayName() { + return "Anonymous inner class with too many methods"; + } + + public String getGroupDisplayName() { + return GroupNames.CLASSMETRICS_GROUP_NAME; + } + + protected int getDefaultLimit() { + return DEFAULT_METHOD_COUNT_LIMIT; + } + + protected String getConfigurationLabel() { + return "Method count limit:"; + } + + protected InspectionGadgetsFix buildFix(PsiElement location) { + return fix; + } + + protected boolean buildQuickFixesOnlyForOnTheFlyErrors() { + return true; + } + + public String buildErrorString(PsiElement location) { + final PsiClass aClass = (PsiClass) location.getParent(); + final int count = calculateTotalMethodCount(aClass); + return "Anonymous inner class with too many methods (method count = " + count + ") #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new MethodCountVisitor(this, inspectionManager, onTheFly); + } + + private class MethodCountVisitor extends BaseInspectionVisitor { + private MethodCountVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitClass(PsiClass psiClass) { + // no call to super, to prevent double counting + } + + public void visitAnonymousClass(PsiAnonymousClass aClass) { + final int totalMethodCount = calculateTotalMethodCount(aClass); + if (totalMethodCount <= getLimit()) { + return; + } + final PsiJavaCodeReferenceElement classNameIdentifier = + aClass.getBaseClassReference(); + registerError(classNameIdentifier); + } + + + } + + private static int calculateTotalMethodCount(PsiClass aClass) { + final PsiMethod[] methods = aClass.getMethods(); + int totalCount = 0; + for (int i = 0; i < methods.length; i++) { + final PsiMethod method = methods[i]; + if (!method.isConstructor()) { + totalCount++; + } + } + return totalCount; + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/classmetrics/ClassComplexityInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/classmetrics/ClassComplexityInspection.java new file mode 100644 index 000000000000..09271188821f --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/classmetrics/ClassComplexityInspection.java @@ -0,0 +1,87 @@ +package com.siyeh.ig.classmetrics; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.psi.*; +import com.siyeh.ig.BaseInspection; +import com.siyeh.ig.BaseInspectionVisitor; +import com.siyeh.ig.GroupNames; + +public class ClassComplexityInspection + extends ClassMetricInspection { + private static final int DEFAULT_COMPLEXITY_LIMIT = 80; + + public String getDisplayName() { + return "Overly complex class"; + } + + public String getGroupDisplayName() { + return GroupNames.CLASSMETRICS_GROUP_NAME; + } + + protected int getDefaultLimit() { + return DEFAULT_COMPLEXITY_LIMIT; + } + + protected String getConfigurationLabel() { + return "Cyclomatic complexity limit:"; + } + + public String buildErrorString(PsiElement location) { + final PsiClass aClass = (PsiClass) location.getParent(); + final int totalComplexity = calculateTotalComplexity(aClass); + return "#ref is overly complex (cyclomatic complexity = " + totalComplexity + ") #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new ClassComplexityVisitor(this, inspectionManager, onTheFly); + } + + private class ClassComplexityVisitor extends BaseInspectionVisitor { + private ClassComplexityVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitClass(PsiClass aClass) { + // note: no call to super + final int totalComplexity = calculateTotalComplexity(aClass); + if (totalComplexity <= getLimit()) { + return; + } + registerClassError(aClass); + } + + } + + private static int calculateTotalComplexity(PsiClass aClass) { + final PsiMethod[] methods = aClass.getMethods(); + int totalComplexity = calculateComplexityForMethods(methods); + totalComplexity += calculateInitializerComplexity(aClass); + return totalComplexity; + } + + private static int calculateInitializerComplexity(PsiClass aClass) { + final ComplexityVisitor visitor = new ComplexityVisitor(); + int complexity = 0; + final PsiClassInitializer[] initializers = aClass.getInitializers(); + for (int i = 0; i < initializers.length; i++) { + final PsiClassInitializer initializer = initializers[i]; + visitor.reset(); + initializer.accept(visitor); + complexity += visitor.getComplexity(); + } + return complexity; + } + + private static int calculateComplexityForMethods(PsiMethod[] methods) { + final ComplexityVisitor visitor = new ComplexityVisitor(); + int complexity = 0; + for (int i = 0; i < methods.length; i++) { + final PsiMethod method = methods[i]; + visitor.reset(); + method.accept(visitor); + complexity += visitor.getComplexity(); + } + return complexity; + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/classmetrics/ClassCouplingInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/classmetrics/ClassCouplingInspection.java new file mode 100644 index 000000000000..958dbd354bd8 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/classmetrics/ClassCouplingInspection.java @@ -0,0 +1,144 @@ +package com.siyeh.ig.classmetrics; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.psi.PsiClass; +import com.intellij.psi.PsiElement; +import com.siyeh.ig.BaseInspection; +import com.siyeh.ig.BaseInspectionVisitor; +import com.siyeh.ig.GroupNames; + +import javax.swing.*; +import javax.swing.event.ChangeEvent; +import javax.swing.event.ChangeListener; +import javax.swing.event.DocumentEvent; +import javax.swing.event.DocumentListener; +import javax.swing.text.Document; +import java.awt.*; +import java.text.NumberFormat; + +public class ClassCouplingInspection + extends ClassMetricInspection { + private static final int DEFAULT_COUPLING_LIMIT = 15; + public boolean m_includeJavaClasses = false; + public boolean m_includeLibraryClasses = true; + + public String getDisplayName() { + return "Overly coupled class"; + } + + public String getGroupDisplayName() { + return GroupNames.CLASSMETRICS_GROUP_NAME; + } + + protected int getDefaultLimit() { + return DEFAULT_COUPLING_LIMIT; + } + + protected String getConfigurationLabel() { + return "Class coupling limit:"; + } + + + public JComponent createOptionsPanel() { + final JPanel panel = new JPanel(new GridBagLayout()); + final String configurationLabel = getConfigurationLabel(); + final JLabel label = new JLabel(configurationLabel); + final NumberFormat formatter = NumberFormat.getIntegerInstance(); + formatter.setParseIntegerOnly(true); + final JFormattedTextField valueField = new JFormattedTextField(formatter); + valueField.setValue(new Integer(m_limit)); + valueField.setColumns(4); + final Document document = valueField.getDocument(); + document.addDocumentListener(new DocumentListener() { + public void changedUpdate(DocumentEvent e) { + textChanged(); + } + + public void insertUpdate(DocumentEvent e) { + textChanged(); + } + + public void removeUpdate(DocumentEvent e) { + textChanged(); + } + + private void textChanged() { + m_limit = ((Number) valueField.getValue()).intValue(); + } + }); + + final GridBagConstraints constraints = new GridBagConstraints(); + constraints.gridx = 0; + constraints.gridy = 0; + constraints.weightx = 1.0; + constraints.anchor = GridBagConstraints.WEST; + constraints.fill = GridBagConstraints.NONE; + panel.add(label, constraints); + constraints.gridx = 1; + constraints.gridy = 0; + constraints.weightx = 1.0; + constraints.anchor = GridBagConstraints.WEST; + constraints.fill = GridBagConstraints.NONE; + panel.add(valueField, constraints); + + final JCheckBox arrayCheckBox = new JCheckBox("Include couplings to java system classes", m_includeJavaClasses); + final ButtonModel arrayModel = arrayCheckBox.getModel(); + arrayModel.addChangeListener(new ChangeListener() { + + public void stateChanged(ChangeEvent e) { + m_includeJavaClasses = arrayModel.isSelected(); + } + }); + final JCheckBox objectCheckBox = new JCheckBox("Include couplings to library classes", m_includeLibraryClasses); + final ButtonModel model = objectCheckBox.getModel(); + model.addChangeListener(new ChangeListener() { + + public void stateChanged(ChangeEvent e) { + m_includeLibraryClasses = model.isSelected(); + } + }); + constraints.gridx = 0; + constraints.gridy = 1; + constraints.gridwidth = 2; + constraints.fill = GridBagConstraints.HORIZONTAL; + panel.add(arrayCheckBox, constraints); + + constraints.gridx = 0; + constraints.gridy = 2; + constraints.gridwidth = 2; + panel.add(objectCheckBox, constraints); + return panel; + } + + public String buildErrorString(PsiElement location) { + final PsiClass aClass = (PsiClass) location.getParent(); + final int totalDependencies = calculateTotalDependencies(aClass); + return "#ref is overly coupled (dependencies = " + totalDependencies + ") #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new ClassCouplingVisitor(this, inspectionManager, onTheFly); + } + + private class ClassCouplingVisitor extends BaseInspectionVisitor { + private ClassCouplingVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitClass(PsiClass aClass) { + // note: no call to super + final int totalDependencies = calculateTotalDependencies(aClass); + if (totalDependencies <= getLimit()) { + return; + } + registerClassError(aClass); + } + } + + private int calculateTotalDependencies(PsiClass aClass) { + final CouplingVisitor visitor = new CouplingVisitor(aClass, m_includeJavaClasses, m_includeLibraryClasses); + aClass.accept(visitor); + return visitor.getNumDependencies(); + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/classmetrics/ClassInheritanceDepthInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/classmetrics/ClassInheritanceDepthInspection.java new file mode 100644 index 000000000000..4160e43eb707 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/classmetrics/ClassInheritanceDepthInspection.java @@ -0,0 +1,83 @@ +package com.siyeh.ig.classmetrics; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.psi.PsiClass; +import com.intellij.psi.PsiElement; +import com.siyeh.ig.BaseInspection; +import com.siyeh.ig.BaseInspectionVisitor; +import com.siyeh.ig.GroupNames; + +import java.util.HashSet; +import java.util.Set; + +public class ClassInheritanceDepthInspection + extends ClassMetricInspection { + private static final int CLASS_INHERITANCE_LIMIT = 2; + + public String getDisplayName() { + return "Class too deep in inheritance tree"; + } + + public String getGroupDisplayName() { + return GroupNames.CLASSMETRICS_GROUP_NAME; + } + + protected int getDefaultLimit() { + return CLASS_INHERITANCE_LIMIT; + } + + protected String getConfigurationLabel() { + return "Inheritance depth limit:"; + } + + public String buildErrorString(PsiElement location) { + final PsiClass aClass = (PsiClass) location.getParent(); + final int count = getInheritanceDepth(aClass, new HashSet()); + return "#ref is too deep in inheritance tree (inheritance depth = " + count + ") #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new ClassNestingLevel(this, inspectionManager, onTheFly); + } + + private class ClassNestingLevel extends BaseInspectionVisitor { + private ClassNestingLevel(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitClass(PsiClass aClass) { + if (aClass.isEnum()) { + return; + } + + // note: no call to super + + final int inheritanceDepth = getInheritanceDepth(aClass, new HashSet()); + if (inheritanceDepth <= getLimit()) { + return; + } + registerClassError(aClass); + } + } + + private int getInheritanceDepth(PsiClass aClass, Set visited) { + if (visited.contains(aClass)) { + return 0; + } + visited.add(aClass); + final PsiClass[] supers = aClass.getSupers(); + if (supers == null || supers.length == 0) { + return 0; + } + int maxAncestorDepth = 0; + for (int i = 0; i < supers.length; i++) { + final int ancestorDepth = getInheritanceDepth(supers[i], visited); + if (ancestorDepth > maxAncestorDepth) { + maxAncestorDepth = ancestorDepth; + } + } + final int depth = maxAncestorDepth + 1; + return depth; + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/classmetrics/ClassMetricInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/classmetrics/ClassMetricInspection.java new file mode 100644 index 000000000000..fdd083ea466b --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/classmetrics/ClassMetricInspection.java @@ -0,0 +1,24 @@ +package com.siyeh.ig.classmetrics; + +import com.siyeh.ig.ClassInspection; +import com.siyeh.ig.ui.SingleIntegerFieldOptionsPanel; + +import javax.swing.*; + +public abstract class ClassMetricInspection extends ClassInspection { + public int m_limit = getDefaultLimit(); //this is public for the DefaultJDOMSericalization thingy + + protected abstract int getDefaultLimit(); + + protected abstract String getConfigurationLabel(); + + protected int getLimit() { + return m_limit; + } + + public JComponent createOptionsPanel() { + return new SingleIntegerFieldOptionsPanel(getConfigurationLabel(), + this, "m_limit"); + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/classmetrics/ClassNestingDepthInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/classmetrics/ClassNestingDepthInspection.java new file mode 100644 index 000000000000..2f34d9d1d193 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/classmetrics/ClassNestingDepthInspection.java @@ -0,0 +1,69 @@ +package com.siyeh.ig.classmetrics; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.psi.PsiClass; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiIdentifier; +import com.siyeh.ig.BaseInspection; +import com.siyeh.ig.BaseInspectionVisitor; +import com.siyeh.ig.GroupNames; + +public class ClassNestingDepthInspection + extends ClassMetricInspection { + private static final int CLASS_NESTING_LIMIT = 1; + + public String getDisplayName() { + return "Inner class too deeply nested"; + } + + public String getGroupDisplayName() { + return GroupNames.CLASSMETRICS_GROUP_NAME; + } + + protected int getDefaultLimit() { + return CLASS_NESTING_LIMIT; + } + + protected String getConfigurationLabel() { + return "Nesting limit:"; + } + + public String buildErrorString(PsiElement location) { + final PsiClass aClass = (PsiClass) location.getParent(); + final int count = getNestingLevel(aClass); + return "#ref is too deeply nested (nesting level = " + count + ") #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new ClassNestingLevel(this, inspectionManager, onTheFly); + } + + private class ClassNestingLevel extends BaseInspectionVisitor { + private ClassNestingLevel(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitClass(PsiClass aClass) { + // note: no call to super + + final int nestingLevel = getNestingLevel(aClass); + if (nestingLevel <= getLimit()) { + return; + } + registerClassError(aClass); + } + } + + private static int getNestingLevel(PsiClass aClass) { + PsiElement ancestor = aClass.getParent(); + int nestingLevel = 0; + while (ancestor != null) { + if (ancestor instanceof PsiClass) { + nestingLevel++; + } + ancestor = ancestor.getParent(); + } + return nestingLevel; + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/classmetrics/ComplexityVisitor.java b/plugins/InspectionGadgets/src/com/siyeh/ig/classmetrics/ComplexityVisitor.java new file mode 100644 index 000000000000..d78bc127a140 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/classmetrics/ComplexityVisitor.java @@ -0,0 +1,82 @@ +package com.siyeh.ig.classmetrics; + +import com.intellij.psi.*; + +class ComplexityVisitor extends PsiRecursiveElementVisitor { + private int m_complexity = 1; + + public void visitReferenceExpression(PsiReferenceExpression expression) { + final PsiExpression qualifier = expression.getQualifierExpression(); + if(qualifier!=null){ + qualifier.accept(this); + } + final PsiReferenceParameterList typeParameters = expression.getParameterList(); + if (typeParameters != null) { + typeParameters.accept(this); + } + } + + public void visitAnonymousClass(PsiAnonymousClass aClass) { + // to call to super, to keep this from drilling down + } + + public void visitForStatement(PsiForStatement statement) { + super.visitForStatement(statement); + m_complexity++; + } + + public void visitForeachStatement(PsiForeachStatement statement) { + super.visitForeachStatement(statement); + m_complexity++; + } + + public void visitIfStatement(PsiIfStatement statement) { + super.visitIfStatement(statement); + m_complexity++; + } + + public void visitDoWhileStatement(PsiDoWhileStatement statement) { + super.visitDoWhileStatement(statement); + m_complexity++; + } + + public void visitConditionalExpression(PsiConditionalExpression expression) { + super.visitConditionalExpression(expression); + m_complexity++; + } + + public void visitSwitchStatement(PsiSwitchStatement statement) { + super.visitSwitchStatement(statement); + final PsiCodeBlock body = statement.getBody(); + if (body == null) { + return; + } + final PsiStatement[] statements = body.getStatements(); + boolean pendingLabel = false; + for (int i = 0; i < statements.length; i++) { + final PsiStatement child = statements[i]; + if (child instanceof PsiSwitchLabelStatement) { + if (!pendingLabel) { + m_complexity++; + } + pendingLabel = true; + } else { + pendingLabel = false; + } + } + } + + public void visitWhileStatement(PsiWhileStatement statement) { + super.visitWhileStatement(statement); + m_complexity++; + } + + public int getComplexity() { + return m_complexity; + } + + public void reset() { + m_complexity = 1; + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/classmetrics/ConstructorCountInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/classmetrics/ConstructorCountInspection.java new file mode 100644 index 000000000000..c3332809f415 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/classmetrics/ConstructorCountInspection.java @@ -0,0 +1,68 @@ +package com.siyeh.ig.classmetrics; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.psi.PsiClass; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiMethod; +import com.siyeh.ig.BaseInspection; +import com.siyeh.ig.BaseInspectionVisitor; +import com.siyeh.ig.GroupNames; + +public class ConstructorCountInspection + extends ClassMetricInspection { + private static final int CONSTRUCTOR_COUNT_LIMIT = 5; + + public String getDisplayName() { + return "Class with too many constructors"; + } + + public String getGroupDisplayName() { + return GroupNames.CLASSMETRICS_GROUP_NAME; + } + + protected int getDefaultLimit() { + return CONSTRUCTOR_COUNT_LIMIT; + } + + protected String getConfigurationLabel() { + return "Constructor count limit:"; + } + + public String buildErrorString(PsiElement location) { + final PsiClass aClass = (PsiClass) location.getParent(); + final int count = calculateTotalConstructorCount(aClass); + return "#ref has too many constructors (constructor count = " + count + ") #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new MethodCountVisitor(this, inspectionManager, onTheFly); + } + + private class MethodCountVisitor extends BaseInspectionVisitor { + private MethodCountVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitClass(PsiClass aClass) { + // note: no call to super + final int totalComplexity = calculateTotalConstructorCount(aClass); + if (totalComplexity <= getLimit()) { + return; + } + registerClassError(aClass); + } + } + + private static int calculateTotalConstructorCount(PsiClass aClass) { + final PsiMethod[] methods = aClass.getMethods(); + int totalCount = 0; + for (int i = 0; i < methods.length; i++) { + final PsiMethod method = methods[i]; + if (method.isConstructor()) { + totalCount++; + } + } + return totalCount; + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/classmetrics/CouplingVisitor.java b/plugins/InspectionGadgets/src/com/siyeh/ig/classmetrics/CouplingVisitor.java new file mode 100644 index 000000000000..c8ab5edde582 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/classmetrics/CouplingVisitor.java @@ -0,0 +1,194 @@ +package com.siyeh.ig.classmetrics; + +import com.intellij.psi.*; +import com.intellij.psi.search.GlobalSearchScope; +import com.intellij.openapi.project.Project; +import com.siyeh.ig.psiutils.LibraryUtil; + +import java.util.HashSet; +import java.util.Set; + +class CouplingVisitor extends PsiRecursiveElementVisitor { + private static final Set s_primitiveTypes = new HashSet(8); + private boolean m_inClass = false; + + static { + s_primitiveTypes.add("boolean"); + s_primitiveTypes.add("byte"); + s_primitiveTypes.add("char"); + s_primitiveTypes.add("short"); + s_primitiveTypes.add("int"); + s_primitiveTypes.add("long"); + s_primitiveTypes.add("float"); + s_primitiveTypes.add("double"); + } + + private static boolean isPrimitiveType(String typeName) { + return s_primitiveTypes.contains(typeName); + } + + private final PsiClass m_class; + private final boolean m_includeJavaClasses; + private final boolean m_includeLibraryClasses; + private final Set m_dependencies = new HashSet(10); + + CouplingVisitor(PsiClass aClass, boolean includeJavaClasses, + boolean includeLibraryClasses) { + super(); + m_class = aClass; + m_includeJavaClasses = includeJavaClasses; + m_includeLibraryClasses = includeLibraryClasses; + } + + public void visitField(PsiField field) { + super.visitField(field); + final PsiType type = field.getType(); + addDependency(type); + } + + public void visitLocalVariable(PsiLocalVariable var) { + super.visitLocalVariable(var); + final PsiType type = var.getType(); + addDependency(type); + } + + public void visitMethod(PsiMethod method) { + super.visitMethod(method); + final PsiType returnType = method.getReturnType(); + addDependency(returnType); + addDependenciesForParameters(method); + addDependenciesForThrowsList(method); + } + + private void addDependenciesForThrowsList(PsiMethod method) { + final PsiReferenceList throwsList = method.getThrowsList(); + if (throwsList == null) { + return; + } + final PsiClassType[] throwsTypes = throwsList.getReferencedTypes(); + for (int i = 0; i < throwsTypes.length; i++) { + addDependency(throwsTypes[i]); + } + } + + private void addDependenciesForParameters(PsiMethod method) { + final PsiParameterList parameterList = method.getParameterList(); + final PsiParameter[] parameters = parameterList.getParameters(); + for (int i = 0; i < parameters.length; i++) { + final PsiType paramType = parameters[i].getType(); + addDependency(paramType); + } + } + + public void visitNewExpression(PsiNewExpression exp) { + super.visitNewExpression(exp); + final PsiType classType = exp.getType(); + addDependency(classType); + } + + public void visitClassObjectAccessExpression(PsiClassObjectAccessExpression exp) { + super.visitClassObjectAccessExpression(exp); + final PsiTypeElement operand = exp.getOperand(); + if (operand == null) { + return; + } + final PsiType classType = operand.getType(); + addDependency(classType); + } + + public void visitClass(PsiClass aClass) { + final boolean wasInClass = m_inClass; + if (!m_inClass) { + + m_inClass = true; + super.visitClass(aClass); + } + m_inClass = wasInClass; + final PsiType[] superTypes = aClass.getSuperTypes(); + for (int i = 0; i < superTypes.length; i++) { + addDependency(superTypes[i]); + } + } + + 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 visitTryStatement(PsiTryStatement statement) { + super.visitTryStatement(statement); + final PsiParameter[] catchBlockParameters = statement.getCatchBlockParameters(); + for (int i = 0; i < catchBlockParameters.length; i++) { + final PsiType catchType = catchBlockParameters[i].getType(); + addDependency(catchType); + } + } + + public void visitInstanceOfExpression(PsiInstanceOfExpression exp) { + super.visitInstanceOfExpression(exp); + final PsiTypeElement checkType = exp.getCheckType(); + if (checkType == null) { + return; + } + final PsiType classType = checkType.getType(); + addDependency(classType); + } + + public void visitTypeCastExpression(PsiTypeCastExpression exp) { + super.visitTypeCastExpression(exp); + final PsiTypeElement castType = exp.getCastType(); + if (castType == null) { + return; + } + final PsiType classType = castType.getType(); + addDependency(classType); + } + + private void addDependency(PsiType type) { + if (type == null) { + return; + } + final PsiType baseType = type.getDeepComponentType(); + final String baseTypeName = baseType.getCanonicalText(); + if (isPrimitiveType(baseTypeName)) { + return; + } + final String qualifiedName = m_class.getQualifiedName(); + if (baseTypeName.equals(qualifiedName)) { + return; + } + if (baseTypeName.startsWith(qualifiedName + '.')) { + return; + } + if (!m_includeJavaClasses && + (baseTypeName.startsWith("java.") || + baseTypeName.startsWith("javax."))) { + return; + } + if (!m_includeLibraryClasses) { + final PsiManager manager = m_class.getManager(); + final Project project = manager.getProject(); + final GlobalSearchScope searchScope = + GlobalSearchScope.allScope(project); + final PsiClass aClass = manager.findClass(baseTypeName, searchScope); + if (aClass == null) { + return; + } + if (LibraryUtil.classIsInLibrary(aClass)) { + return; + } + } + m_dependencies.add(baseTypeName); + } + + public int getNumDependencies() { + return m_dependencies.size(); + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/classmetrics/FieldCountInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/classmetrics/FieldCountInspection.java new file mode 100644 index 000000000000..b919a6564ca1 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/classmetrics/FieldCountInspection.java @@ -0,0 +1,155 @@ +package com.siyeh.ig.classmetrics; + +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.psiutils.ClassUtils; + +import javax.swing.*; +import javax.swing.event.ChangeEvent; +import javax.swing.event.ChangeListener; +import javax.swing.event.DocumentEvent; +import javax.swing.event.DocumentListener; +import javax.swing.text.Document; +import java.awt.*; +import java.text.NumberFormat; + +public class FieldCountInspection + extends ClassMetricInspection { + private static final int FIELD_COUNT_LIMIT = 10; + private boolean m_countConstantFields = true; + + public String getDisplayName() { + return "Class with too many fields"; + } + + public String getGroupDisplayName() { + return GroupNames.CLASSMETRICS_GROUP_NAME; + } + + protected int getDefaultLimit() { + return FIELD_COUNT_LIMIT; + } + + protected String getConfigurationLabel() { + return "Field count limit:"; + } + + public JComponent createOptionsPanel() { + final JPanel panel = new JPanel(new GridBagLayout()); + final String configurationLabel = getConfigurationLabel(); + final JLabel label = new JLabel(configurationLabel); + final NumberFormat formatter = NumberFormat.getIntegerInstance(); + formatter.setParseIntegerOnly(true); + final JFormattedTextField valueField = new JFormattedTextField(formatter); + valueField.setValue(new Integer(m_limit)); + valueField.setColumns(4); + final Document document = valueField.getDocument(); + document.addDocumentListener(new DocumentListener() { + public void changedUpdate(DocumentEvent e) { + textChanged(); + } + + public void insertUpdate(DocumentEvent e) { + textChanged(); + } + + public void removeUpdate(DocumentEvent e) { + textChanged(); + } + + private void textChanged() { + m_limit = ((Number) valueField.getValue()).intValue(); + } + }); + + final JCheckBox checkBox = new JCheckBox("Include constant fields", m_countConstantFields); + final ButtonModel model = checkBox.getModel(); + model.addChangeListener(new ChangeListener() { + + public void stateChanged(ChangeEvent e) { + m_countConstantFields = model.isSelected(); + } + }); + final GridBagConstraints constraints = new GridBagConstraints(); + constraints.gridx = 0; + constraints.gridy = 0; + constraints.weightx = 1.0; + constraints.anchor = GridBagConstraints.WEST; + constraints.fill = GridBagConstraints.NONE; + panel.add(label, constraints); + constraints.gridx = 1; + constraints.gridy = 0; + constraints.gridwidth = 3; + constraints.weightx = 1.0; + constraints.anchor = GridBagConstraints.WEST; + constraints.fill = GridBagConstraints.NONE; + panel.add(valueField, constraints); + constraints.gridx = 0; + constraints.gridy = 1; + constraints.gridwidth = 4; + constraints.weightx = 1.0; + constraints.anchor = GridBagConstraints.WEST; + constraints.fill = GridBagConstraints.NONE; + panel.add(checkBox, constraints); + return panel; + } + + public String buildErrorString(PsiElement location) { + final PsiClass aClass = (PsiClass) location.getParent(); + final int count = countFields(aClass); + return "#ref has too many fields (field count = " + count + ") #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new FieldCountVisitor(this, inspectionManager, onTheFly); + } + + private class FieldCountVisitor extends BaseInspectionVisitor { + private FieldCountVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitClass(PsiClass aClass) { + // note: no call to super + final int totalFields = countFields(aClass); + if (totalFields <= getLimit()) { + return; + } + registerClassError(aClass); + } + } + + private int countFields(PsiClass aClass) { + int totalFields = 0; + final PsiField[] fields = aClass.getFields(); + for (int i = 0; i < fields.length; i++) { + final PsiField field = fields[i]; + if (m_countConstantFields) { + totalFields++; + } else { + if (!fieldIsConstant(field)) { + totalFields++; + } + } + } + return totalFields; + } + + private static boolean fieldIsConstant(PsiField field) { + if (!field.hasModifierProperty(PsiModifier.STATIC)) { + return false; + } + if (!field.hasModifierProperty(PsiModifier.FINAL)) { + return false; + } + final PsiType type = field.getType(); + if (!ClassUtils.isImmutable(type)) { + return false; + } + return true; + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/classmetrics/MethodCountInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/classmetrics/MethodCountInspection.java new file mode 100644 index 000000000000..131007a5ca9b --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/classmetrics/MethodCountInspection.java @@ -0,0 +1,69 @@ +package com.siyeh.ig.classmetrics; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.psi.PsiClass; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiMethod; +import com.siyeh.ig.BaseInspection; +import com.siyeh.ig.BaseInspectionVisitor; +import com.siyeh.ig.GroupNames; + +public class MethodCountInspection + extends ClassMetricInspection { + private static final int DEFAULT_METHOD_COUNT_LIMIT = 20; + + public String getDisplayName() { + return "Class with too many methods"; + } + + public String getGroupDisplayName() { + return GroupNames.CLASSMETRICS_GROUP_NAME; + } + + protected int getDefaultLimit() { + return DEFAULT_METHOD_COUNT_LIMIT; + } + + protected String getConfigurationLabel() { + return "Method count limit:"; + } + + public String buildErrorString(PsiElement location) { + final PsiClass aClass = (PsiClass) location.getParent(); + final int count = calculateTotalMethodCount(aClass); + return "#ref has too many methods (method count = " + count + ") #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new MethodCountVisitor(this, inspectionManager, onTheFly); + } + + private class MethodCountVisitor extends BaseInspectionVisitor { + private MethodCountVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitClass(PsiClass aClass) { + // note: no call to super + final int totalComplexity = calculateTotalMethodCount(aClass); + if (totalComplexity <= getLimit()) { + return; + } + registerClassError(aClass); + } + + } + + private static int calculateTotalMethodCount(PsiClass aClass) { + final PsiMethod[] methods = aClass.getMethods(); + int totalCount = 0; + for (int i = 0; i < methods.length; i++) { + final PsiMethod method = methods[i]; + if (!method.isConstructor()) { + totalCount++; + } + } + return totalCount; + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/cloneable/CallToSuperCloneVisitor.java b/plugins/InspectionGadgets/src/com/siyeh/ig/cloneable/CallToSuperCloneVisitor.java new file mode 100644 index 000000000000..5a6ce9f96227 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/cloneable/CallToSuperCloneVisitor.java @@ -0,0 +1,42 @@ +package com.siyeh.ig.cloneable; + +import com.intellij.psi.*; + +class CallToSuperCloneVisitor extends PsiRecursiveElementVisitor { + private boolean m_callToSuperCloneFound = false; + + public void visitMethodCallExpression(PsiMethodCallExpression expression) { + super.visitMethodCallExpression(expression); + final PsiReferenceExpression methodExpression = expression.getMethodExpression(); + if (methodExpression == null) { + return; + } + final PsiExpression target = methodExpression.getQualifierExpression(); + if (target == null) { + return; + } + if (!(target instanceof PsiSuperExpression)) { + return; + } + final String methodName = methodExpression.getReferenceName(); + if (!"clone".equals(methodName)) { + return; + } + m_callToSuperCloneFound = true; + } + + public void visitReferenceExpression(PsiReferenceExpression expression) { + final PsiExpression qualifier = expression.getQualifierExpression(); + if (qualifier != null) { + qualifier.accept(this); + } + final PsiReferenceParameterList typeParameters = expression.getParameterList(); + if (typeParameters != null) { + typeParameters.accept(this); + } + } + + public boolean isCallToSuperCloneFound() { + return m_callToSuperCloneFound; + } +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/cloneable/CloneCallsConstructorsInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/cloneable/CloneCallsConstructorsInspection.java new file mode 100644 index 000000000000..af6c61c4a5fb --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/cloneable/CloneCallsConstructorsInspection.java @@ -0,0 +1,82 @@ +package com.siyeh.ig.cloneable; + +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 CloneCallsConstructorsInspection extends ExpressionInspection { + + public String getDisplayName() { + return "clone() instantiates objects with constructor"; + } + + public String getGroupDisplayName() { + return GroupNames.CLONEABLE_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "clone() instantiates objects with constructor new #ref() #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new CloneCallsConstructorVisitor(this, inspectionManager, onTheFly); + } + + private static class CloneCallsConstructorVisitor extends BaseInspectionVisitor { + private boolean m_inClone = false; + + private CloneCallsConstructorVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitMethod(PsiMethod method) { + boolean wasInClone = m_inClone; + final String methodName = method.getName(); + final PsiParameterList parameterList = method.getParameterList(); + final boolean isClone = "clone".equals(methodName) && + parameterList.getParameters().length == 0; + if (isClone) { + wasInClone = m_inClone; + m_inClone = true; + } + super.visitMethod(method); + if (isClone) { + m_inClone = wasInClone; + } + } + + public void visitNewExpression(PsiNewExpression newExpression) { + super.visitNewExpression(newExpression); + if (!m_inClone) { + return; + } + + final PsiExpression[] arrayDimensions = newExpression.getArrayDimensions(); + if (arrayDimensions != null && arrayDimensions.length != 0) { + return; + } + if (newExpression.getArrayInitializer() != null) { + return; + } + if (newExpression.getAnonymousClass() != null) { + return; + } + if (isPartOfThrowStatement(newExpression)) { + return; + } + + final PsiJavaCodeReferenceElement classReference = newExpression.getClassReference(); + registerError(classReference); + } + + private static boolean isPartOfThrowStatement(PsiElement element) { + return PsiTreeUtil.getParentOfType(element, PsiThrowStatement.class) != null; + } + + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/cloneable/CloneCallsSuperCloneInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/cloneable/CloneCallsSuperCloneInspection.java new file mode 100644 index 000000000000..1f92415c7f2c --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/cloneable/CloneCallsSuperCloneInspection.java @@ -0,0 +1,57 @@ +package com.siyeh.ig.cloneable; + +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.MethodInspection; + +public class CloneCallsSuperCloneInspection extends MethodInspection { + + public String getDisplayName() { + return "clone() doesn't call super.clone()"; + } + + public String getGroupDisplayName() { + return GroupNames.CLONEABLE_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "#ref() doesn't call super.clone()"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new NoExplicitCloneCallsVisitor(this, inspectionManager, onTheFly); + } + + private static class NoExplicitCloneCallsVisitor extends BaseInspectionVisitor { + private NoExplicitCloneCallsVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitMethod(PsiMethod method) { + //note: no call to super; + final String methodName = method.getName(); + if (!"clone".equals(methodName)) { + return; + } + final PsiParameterList parameterList = method.getParameterList(); + if (parameterList.getParameters().length != 0) { + return; + } + final PsiClass containingClass = method.getContainingClass(); + if (containingClass.isInterface() || containingClass.isAnnotationType()) { + return; + } + final CallToSuperCloneVisitor visitor = new CallToSuperCloneVisitor(); + method.accept(visitor); + if (visitor.isCallToSuperCloneFound()) { + return; + } + registerMethodError(method); + } + + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/cloneable/CloneDeclaresCloneNotSupportedInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/cloneable/CloneDeclaresCloneNotSupportedInspection.java new file mode 100644 index 000000000000..8e120b9db404 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/cloneable/CloneDeclaresCloneNotSupportedInspection.java @@ -0,0 +1,98 @@ +package com.siyeh.ig.cloneable; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.codeInspection.ProblemDescriptor; +import com.intellij.psi.*; +import com.intellij.psi.util.PsiUtil; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.diagnostic.Logger; +import com.intellij.util.IncorrectOperationException; +import com.siyeh.ig.*; + +public class CloneDeclaresCloneNotSupportedInspection extends MethodInspection { + private final CloneDeclaresCloneNotSupportedInspectionFix fix = new CloneDeclaresCloneNotSupportedInspectionFix(); + + public String getDisplayName() { + return "clone() doesn't declare CloneNotSupportedException"; + } + + public String getGroupDisplayName() { + return GroupNames.CLONEABLE_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "#ref() doesn't declare CloneNotSupportedException #loc"; + } + + public InspectionGadgetsFix buildFix(PsiElement location) { + return fix; + } + + private static class CloneDeclaresCloneNotSupportedInspectionFix extends InspectionGadgetsFix { + public String getName() { + return "Declare CloneNotSupportedException"; + } + + public void applyFix(Project project, ProblemDescriptor descriptor) { + try { + final PsiElement methodNameIdentifier = descriptor.getPsiElement(); + final PsiMethod method = (PsiMethod) methodNameIdentifier.getParent(); + PsiUtil.addException(method, "java.lang.CloneNotSupportedException"); + } catch (IncorrectOperationException e) { + final Class thisClass = getClass(); + final String className = thisClass.getName(); + final Logger logger = Logger.getInstance(className); + logger.error(e); + } + } + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new CloneDeclaresCloneNotSupportedExceptionVisitor(this, inspectionManager, onTheFly); + } + + private static class CloneDeclaresCloneNotSupportedExceptionVisitor extends BaseInspectionVisitor { + private CloneDeclaresCloneNotSupportedExceptionVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitMethod(PsiMethod method) { + //note: no call to super; + final String methodName = method.getName(); + if (!"clone".equals(methodName)) { + return; + } + if (method.getParameterList().getParameters().length != 0) { + return; + } + if (method.hasModifierProperty(PsiModifier.FINAL)) { + return; + } + final PsiClass containingClass = method.getContainingClass(); + if (containingClass.hasModifierProperty(PsiModifier.FINAL)) { + return; + } + final PsiReferenceList throwsList = method.getThrowsList(); + if (throwsList == null) { + registerMethodError(method); + return; + } + final PsiJavaCodeReferenceElement[] referenceElements = throwsList.getReferenceElements(); + for (int i = 0; i < referenceElements.length; i++) { + final PsiJavaCodeReferenceElement referenceElement = referenceElements[i]; + final PsiElement referencedElement = referenceElement.resolve(); + if (referencedElement != null && referencedElement instanceof PsiClass) { + final PsiClass aClass = (PsiClass) referencedElement; + final String className = aClass.getQualifiedName(); + if ("java.lang.CloneNotSupportedException".equals(className)) { + return; + } + } + } + + registerMethodError(method); + } + + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/cloneable/CloneableImplementsCloneInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/cloneable/CloneableImplementsCloneInspection.java new file mode 100644 index 000000000000..e8d41f4f0550 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/cloneable/CloneableImplementsCloneInspection.java @@ -0,0 +1,71 @@ +package com.siyeh.ig.cloneable; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.psi.PsiClass; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiMethod; +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.CloneUtils; +import com.siyeh.ig.ui.SingleCheckboxOptionsPanel; + +import javax.swing.*; + +public class CloneableImplementsCloneInspection extends ClassInspection { + public boolean m_ignoreCloneableDueToInheritance = false; + + public String getDisplayName() { + return "Cloneable class without 'clone()'"; + } + + public String getGroupDisplayName() { + return GroupNames.CLONEABLE_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "#ref doesn't define clone() #loc"; + } + + public JComponent createOptionsPanel() { + return new SingleCheckboxOptionsPanel("Ignore classes cloneable due to inheritance", + this, "m_ignoreCloneableDueToInheritance"); + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new CloneableDefinesCloneVisitor(this, inspectionManager, onTheFly); + } + + private class CloneableDefinesCloneVisitor extends BaseInspectionVisitor { + private CloneableDefinesCloneVisitor(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 (m_ignoreCloneableDueToInheritance) { + if (!CloneUtils.isDirectlyCloneable(aClass)) { + return; + } + } else { + if (!CloneUtils.isCloneable(aClass)) { + return; + } + } + final PsiMethod[] methods = aClass.getMethods(); + for (int i = 0; i < methods.length; i++) { + final PsiMethod method = methods[i]; + if (CloneUtils.isClone(method)) { + return; + } + } + registerClassError(aClass); + } + + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/confusing/AssignmentToCatchBlockParameterInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/confusing/AssignmentToCatchBlockParameterInspection.java new file mode 100644 index 000000000000..05639d28d87e --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/confusing/AssignmentToCatchBlockParameterInspection.java @@ -0,0 +1,54 @@ +package com.siyeh.ig.confusing; + +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 AssignmentToCatchBlockParameterInspection extends ExpressionInspection { + + public String getDisplayName() { + return "Assignment to catch block parameter"; + } + + public String getGroupDisplayName() { + return GroupNames.CONFUSING_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "Assignment to catch block parameter #ref #loc "; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new AssignmentToCatchBlockParameterVisitor(this, inspectionManager, onTheFly); + } + + private static class AssignmentToCatchBlockParameterVisitor extends BaseInspectionVisitor { + private AssignmentToCatchBlockParameterVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitAssignmentExpression(PsiAssignmentExpression expression) { + super.visitAssignmentExpression(expression); + final PsiExpression lhs = expression.getLExpression(); + if (lhs == null) { + return; + } + if (!(lhs instanceof PsiReferenceExpression)) { + return; + } + final PsiReferenceExpression ref = (PsiReferenceExpression) lhs; + final PsiElement variable = ref.resolve(); + if (!(variable instanceof PsiParameter)) { + return; + } + if (!(variable.getParent() instanceof PsiTryStatement)) { + return; + } + registerError(expression); + } + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/confusing/AssignmentToForLoopParameterInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/confusing/AssignmentToForLoopParameterInspection.java new file mode 100644 index 000000000000..be7a90053dd9 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/confusing/AssignmentToForLoopParameterInspection.java @@ -0,0 +1,128 @@ +package com.siyeh.ig.confusing; + +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 AssignmentToForLoopParameterInspection extends ExpressionInspection { + + public String getDisplayName() { + return "Assignment to for-loop parameter"; + } + + public String getGroupDisplayName() { + return GroupNames.CONFUSING_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "Assignment to for-loop parameter #ref #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new AssignmentToForLoopParameterVisitor(this, inspectionManager, onTheFly); + } + + private static class AssignmentToForLoopParameterVisitor extends BaseInspectionVisitor { + private AssignmentToForLoopParameterVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitAssignmentExpression(PsiAssignmentExpression expression) { + super.visitAssignmentExpression(expression); + final PsiExpression lhs = expression.getLExpression(); + if (lhs == null) { + return; + } + checkForForLoopParam(lhs); + checkForForeachLoopParam(lhs); + } + + public void visitPrefixExpression(PsiPrefixExpression expression) { + super.visitPrefixExpression(expression); + final PsiJavaToken sign = expression.getOperationSign(); + if (sign == null) { + return; + } + if (sign.getTokenType() != JavaTokenType.PLUSPLUS && + sign.getTokenType() != JavaTokenType.MINUSMINUS) { + return; + } + final PsiExpression operand = expression.getOperand(); + if (operand == null) { + return; + } + checkForForLoopParam(operand); + } + + public void visitPostfixExpression(PsiPostfixExpression expression) { + super.visitPostfixExpression(expression); + final PsiJavaToken sign = expression.getOperationSign(); + if (sign == null) { + return; + } + if (sign.getTokenType() != JavaTokenType.PLUSPLUS && + sign.getTokenType() != JavaTokenType.MINUSMINUS) { + return; + } + final PsiExpression operand = expression.getOperand(); + if (operand == null) { + return; + } + checkForForLoopParam(operand); + } + + private void checkForForLoopParam(PsiExpression expression) { + if (!(expression instanceof PsiReferenceExpression)) { + return; + } + final PsiReferenceExpression ref = (PsiReferenceExpression) expression; + final PsiElement element = ref.resolve(); + if (!(element instanceof PsiLocalVariable)) { + return; + } + final PsiLocalVariable variable = (PsiLocalVariable) element; + final PsiDeclarationStatement decl = (PsiDeclarationStatement) variable.getParent(); + if (!(decl.getParent() instanceof PsiForStatement)) { + return; + } + final PsiForStatement forStatement = (PsiForStatement) decl.getParent(); + final PsiStatement initialization = forStatement.getInitialization(); + if (initialization == null) { + return; + } + if (!initialization.equals(decl)) { + return; + } + if (!isInForStatementBody(expression, forStatement)) { + return; + } + registerError(expression); + } + + private void checkForForeachLoopParam(PsiExpression expression) { + if (!(expression instanceof PsiReferenceExpression)) { + return; + } + final PsiReferenceExpression ref = (PsiReferenceExpression) expression; + final PsiElement element = ref.resolve(); + if (!(element instanceof PsiParameter)) { + return; + } + final PsiParameter parameter = (PsiParameter) element; + if (!(parameter.getParent() instanceof PsiForeachStatement)) { + return; + } + registerError(expression); + } + + private static boolean isInForStatementBody(PsiExpression expression, PsiForStatement statement) { + final PsiStatement body = statement.getBody(); + return PsiTreeUtil.isAncestor(body, expression, true); + } + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/confusing/AssignmentToMethodParameterInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/confusing/AssignmentToMethodParameterInspection.java new file mode 100644 index 000000000000..492070095f16 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/confusing/AssignmentToMethodParameterInspection.java @@ -0,0 +1,95 @@ +package com.siyeh.ig.confusing; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.psi.*; +import com.intellij.psi.tree.IElementType; +import com.siyeh.ig.BaseInspection; +import com.siyeh.ig.BaseInspectionVisitor; +import com.siyeh.ig.ExpressionInspection; +import com.siyeh.ig.GroupNames; + +public class AssignmentToMethodParameterInspection extends ExpressionInspection { + + public String getDisplayName() { + return "Assignment to method parameter"; + } + + public String getGroupDisplayName() { + return GroupNames.CONFUSING_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "Assignment to method parameter #ref #loc "; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new AssignmentToMethodParameterVisitor(this, inspectionManager, onTheFly); + } + + private static class AssignmentToMethodParameterVisitor extends BaseInspectionVisitor { + private AssignmentToMethodParameterVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitAssignmentExpression(PsiAssignmentExpression expression) { + super.visitAssignmentExpression(expression); + final PsiExpression lhs = expression.getLExpression(); + if (lhs == null) { + return; + } + checkForMethodParam(lhs); + } + + public void visitPrefixExpression(PsiPrefixExpression expression) { + super.visitPrefixExpression(expression); + final PsiJavaToken sign = expression.getOperationSign(); + if (sign == null) { + return; + } + final IElementType tokenType = sign.getTokenType(); + if (!tokenType.equals(JavaTokenType.PLUSPLUS) && + !tokenType.equals(JavaTokenType.MINUSMINUS)) { + return; + } + final PsiExpression operand = expression.getOperand(); + if (operand == null) { + return; + } + checkForMethodParam(operand); + } + + public void visitPostfixExpression(PsiPostfixExpression expression) { + super.visitPostfixExpression(expression); + final PsiJavaToken sign = expression.getOperationSign(); + if (sign == null) { + return; + } + final IElementType tokenType = sign.getTokenType(); + if (!tokenType.equals(JavaTokenType.PLUSPLUS) && + !tokenType.equals(JavaTokenType.MINUSMINUS)) { + return; + } + final PsiExpression operand = expression.getOperand(); + if (operand == null) { + return; + } + checkForMethodParam(operand); + } + + private void checkForMethodParam(PsiExpression expression) { + if (!(expression instanceof PsiReferenceExpression)) { + return; + } + final PsiReferenceExpression ref = (PsiReferenceExpression) expression; + final PsiElement variable = ref.resolve(); + if (!(variable instanceof PsiParameter)) { + return; + } + if (variable.getParent() instanceof PsiTryStatement) { + return; + } + registerError(expression); + } + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/confusing/BreakStatementInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/confusing/BreakStatementInspection.java new file mode 100644 index 000000000000..85cccb213c61 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/confusing/BreakStatementInspection.java @@ -0,0 +1,63 @@ +package com.siyeh.ig.confusing; + +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.GroupNames; +import com.siyeh.ig.StatementInspection; + +public class BreakStatementInspection extends StatementInspection { + + public String getDisplayName() { + return "'break' statement"; + } + + public String getGroupDisplayName() { + return GroupNames.CONFUSING_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "#ref statement #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new BreakStatementVisitor(this, inspectionManager, onTheFly); + } + + private static class BreakStatementVisitor extends BaseInspectionVisitor { + private BreakStatementVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitBreakStatement(PsiBreakStatement statement) { + super.visitBreakStatement(statement); + + final PsiSwitchStatement switchStatement = + (PsiSwitchStatement) PsiTreeUtil.getParentOfType(statement, PsiSwitchStatement.class); + if (switchStatement != null && + isBreakAtTopLevel(switchStatement, statement)) { + return; + } + registerStatementError(statement); + } + + private static boolean isBreakAtTopLevel(PsiSwitchStatement switchStatement, PsiBreakStatement statement) { + final PsiCodeBlock body = switchStatement.getBody(); + if (body == null) { + return false; + } + final PsiStatement[] statements = body.getStatements(); + for (int i = 0; i < statements.length; i++) { + final PsiStatement child = statements[i]; + if (child.equals(statement)) { + return true; + } + } + return false; + } + + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/confusing/BreakStatementWithLabelInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/confusing/BreakStatementWithLabelInspection.java new file mode 100644 index 000000000000..11e542ae2c48 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/confusing/BreakStatementWithLabelInspection.java @@ -0,0 +1,54 @@ +package com.siyeh.ig.confusing; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.psi.PsiBreakStatement; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiIdentifier; +import com.siyeh.ig.BaseInspection; +import com.siyeh.ig.BaseInspectionVisitor; +import com.siyeh.ig.GroupNames; +import com.siyeh.ig.StatementInspection; + +public class BreakStatementWithLabelInspection extends StatementInspection { + + public String getDisplayName() { + return "'break' statement with label"; + } + + public String getGroupDisplayName() { + return GroupNames.CONFUSING_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "#ref statement with label #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new BreakStatementWithLabelVisitor(this, inspectionManager, onTheFly); + } + + private static class BreakStatementWithLabelVisitor extends BaseInspectionVisitor { + private BreakStatementWithLabelVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitBreakStatement(PsiBreakStatement statement) { + super.visitBreakStatement(statement); + final PsiIdentifier labelIdentifier = statement.getLabelIdentifier(); + if (labelIdentifier == null) { + return; + } + final PsiIdentifier identifier = statement.getLabelIdentifier(); + final String labelText = identifier.getText(); + if (labelText == null) { + return; + } + if (labelText.length() == 0) { + return; + } + registerStatementError(statement); + } + + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/confusing/CastThatLosesPrecisionInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/confusing/CastThatLosesPrecisionInspection.java new file mode 100644 index 000000000000..0e78916481e4 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/confusing/CastThatLosesPrecisionInspection.java @@ -0,0 +1,89 @@ +package com.siyeh.ig.confusing; + +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; +import com.siyeh.ig.psiutils.ClassUtils; + +import java.util.HashMap; +import java.util.Map; + +public class CastThatLosesPrecisionInspection extends StatementInspection { + + private static final Map s_typePrecisions = new HashMap(7); + + static { + s_typePrecisions.put("byte", new Integer(1)); + s_typePrecisions.put("char", new Integer(2)); + s_typePrecisions.put("short", new Integer(2)); + s_typePrecisions.put("int", new Integer(3)); + s_typePrecisions.put("long", new Integer(4)); + s_typePrecisions.put("float", new Integer(5)); + s_typePrecisions.put("double", new Integer(6)); + } + + public String getDisplayName() { + return "Numeric cast that loses precision"; + } + + public String getGroupDisplayName() { + return GroupNames.CONFUSING_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + final PsiTypeCastExpression expression = (PsiTypeCastExpression) location.getParent(); + final PsiExpression operand = expression.getOperand(); + final PsiType operandType = operand.getType(); + return "Cast to #ref from " + operandType.getPresentableText() + " may result in loss of precision #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new CastThatLosesPrecisionVisitor(this, inspectionManager, onTheFly); + } + + private static class CastThatLosesPrecisionVisitor extends BaseInspectionVisitor { + private CastThatLosesPrecisionVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitTypeCastExpression(PsiTypeCastExpression exp) { + final PsiType castType = exp.getType(); + if (castType == null) { + return; + } + if (!ClassUtils.isPrimitiveNumericType(castType)) { + return; + } + + final PsiExpression operand = exp.getOperand(); + + final PsiType operandType = operand.getType(); + if (operandType == null) { + return; + } + + if (!ClassUtils.isPrimitiveNumericType(operandType)) { + return; + } + + if (hasLowerPrecision(operandType, castType)) { + return; + } + final PsiTypeElement castTypeElement = exp.getCastType(); + registerError(castTypeElement); + } + + private static boolean hasLowerPrecision(PsiType operandType, PsiType castType) { + final String operandTypeText = operandType.getCanonicalText(); + final Integer operandPrecision = (Integer) s_typePrecisions.get(operandTypeText); + final String castTypeText = castType.getCanonicalText(); + final Integer castPrecision = (Integer) s_typePrecisions.get(castTypeText); + return operandPrecision.intValue() <= castPrecision.intValue(); + } + + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/confusing/ChainedEqualityInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/confusing/ChainedEqualityInspection.java new file mode 100644 index 000000000000..212128b1eb3d --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/confusing/ChainedEqualityInspection.java @@ -0,0 +1,58 @@ +package com.siyeh.ig.confusing; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.psi.*; +import com.intellij.psi.tree.IElementType; +import com.siyeh.ig.BaseInspection; +import com.siyeh.ig.BaseInspectionVisitor; +import com.siyeh.ig.ExpressionInspection; +import com.siyeh.ig.GroupNames; + +public class ChainedEqualityInspection extends ExpressionInspection { + + public String getDisplayName() { + return "Chained equality comparisons"; + } + + public String getGroupDisplayName() { + return GroupNames.CONFUSING_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "Chained equality comparison #ref #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new ChainedEqualityVisitor(this, inspectionManager, onTheFly); + } + + private static class ChainedEqualityVisitor extends BaseInspectionVisitor { + private ChainedEqualityVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitBinaryExpression(PsiBinaryExpression expression) { + super.visitBinaryExpression(expression); + if (!isEqualityComparison(expression)) { + return; + } + final PsiExpression lhs = expression.getLOperand(); + if (lhs == null || !(lhs instanceof PsiBinaryExpression)) { + return; + } + if (!isEqualityComparison((PsiBinaryExpression) lhs)) { + return; + } + registerError(expression); + } + + private static boolean isEqualityComparison(PsiBinaryExpression expression) { + final PsiJavaToken sign = expression.getOperationSign(); + final IElementType tokenType = sign.getTokenType(); + return tokenType.equals(JavaTokenType.EQEQ) || + tokenType.equals(JavaTokenType.NE); + } + + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/confusing/ChainedMethodCallInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/confusing/ChainedMethodCallInspection.java new file mode 100644 index 000000000000..620bab596364 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/confusing/ChainedMethodCallInspection.java @@ -0,0 +1,115 @@ +package com.siyeh.ig.confusing; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.codeInspection.ProblemDescriptor; +import com.intellij.openapi.project.Project; +import com.intellij.psi.*; +import com.intellij.psi.util.PsiTreeUtil; +import com.intellij.refactoring.RefactoringActionHandler; +import com.intellij.refactoring.RefactoringActionHandlerFactory; +import com.siyeh.ig.*; +import com.siyeh.ig.ui.SingleCheckboxOptionsPanel; + +import javax.swing.*; + +public class ChainedMethodCallInspection extends ExpressionInspection { + private boolean m_ignoreFieldInitializations = true; + private final ChainedMethodCallFix fix = new ChainedMethodCallFix(); + + public String getDisplayName() { + return "Chained method calls"; + } + + public String getGroupDisplayName() { + return GroupNames.CONFUSING_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "Chained method call #ref() #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new ChainedMethodCallVisitor(this, inspectionManager, onTheFly); + } + + + public JComponent createOptionsPanel() { + return new SingleCheckboxOptionsPanel("Ignore chained method calls in field initializers", + this, "m_ignoreFieldInitializations"); + } + + protected boolean buildQuickFixesOnlyForOnTheFlyErrors() { + return true; + } + + protected InspectionGadgetsFix buildFix(PsiElement location) { + return fix; + } + + private static class ChainedMethodCallFix extends InspectionGadgetsFix { + public String getName() { + return "Introduce variable"; + } + + public void applyFix(Project project, ProblemDescriptor descriptor) { + final RefactoringActionHandlerFactory factory = + RefactoringActionHandlerFactory.getInstance(); + final RefactoringActionHandler introduceHandler = + factory.createIntroduceVariableHandler(); + final PsiElement methodNameElement = descriptor.getPsiElement(); + final PsiReferenceExpression methodCallExpression = + (PsiReferenceExpression) methodNameElement.getParent(); + final PsiExpression qualifier = methodCallExpression.getQualifierExpression(); + introduceHandler.invoke(project, + new PsiElement[]{qualifier}, + null); + } + } + + private class ChainedMethodCallVisitor extends BaseInspectionVisitor { + + private ChainedMethodCallVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitMethodCallExpression(PsiMethodCallExpression expression) { + super.visitMethodCallExpression(expression); + final PsiReferenceExpression reference = expression.getMethodExpression(); + if (reference == null) { + return; + } + final PsiExpression qualifier = reference.getQualifierExpression(); + if (qualifier == null) { + return; + } + if (!isCallExpression(qualifier)) { + return; + } + + if (m_ignoreFieldInitializations) { + final PsiElement field = PsiTreeUtil.getParentOfType(expression, PsiField.class); + if (field != null) { + return; + } + } + registerMethodCallError(expression); + } + + } + + private static boolean isCallExpression(PsiExpression expression) { + if (expression instanceof PsiMethodCallExpression || + expression instanceof PsiNewExpression) { + return true; + } + if (expression instanceof PsiParenthesizedExpression) { + final PsiParenthesizedExpression parenthesizedExpression = + (PsiParenthesizedExpression) expression; + final PsiExpression containedExpression = + parenthesizedExpression.getExpression(); + return isCallExpression(containedExpression); + } + return false; + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/confusing/ConditionalExpressionInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/confusing/ConditionalExpressionInspection.java new file mode 100644 index 000000000000..354c17ff43b0 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/confusing/ConditionalExpressionInspection.java @@ -0,0 +1,41 @@ +package com.siyeh.ig.confusing; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.psi.PsiConditionalExpression; +import com.intellij.psi.PsiElement; +import com.siyeh.ig.BaseInspection; +import com.siyeh.ig.BaseInspectionVisitor; +import com.siyeh.ig.ExpressionInspection; +import com.siyeh.ig.GroupNames; + +public class ConditionalExpressionInspection extends ExpressionInspection { + + public String getDisplayName() { + return "Conditional expression (?:)"; + } + + public String getGroupDisplayName() { + return GroupNames.CONFUSING_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "Conditional expression #ref #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new ConditionalExpressionVisitor(this, inspectionManager, onTheFly); + } + + private static class ConditionalExpressionVisitor extends BaseInspectionVisitor { + private ConditionalExpressionVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitConditionalExpression(PsiConditionalExpression exp) { + super.visitConditionalExpression(exp); + registerError(exp); + } + + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/confusing/ConfusingElseInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/confusing/ConfusingElseInspection.java new file mode 100644 index 000000000000..deb754fc9b79 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/confusing/ConfusingElseInspection.java @@ -0,0 +1,82 @@ +package com.siyeh.ig.confusing; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiIfStatement; +import com.intellij.psi.PsiStatement; +import com.siyeh.ig.BaseInspection; +import com.siyeh.ig.BaseInspectionVisitor; +import com.siyeh.ig.GroupNames; +import com.siyeh.ig.StatementInspection; +import com.siyeh.ig.psiutils.ControlFlowUtils; + +public class ConfusingElseInspection extends StatementInspection { + + public String getDisplayName() { + return "Confusing else branch"; + } + + public String getGroupDisplayName() { + return GroupNames.CONFUSING_GROUP_NAME; + } + + protected BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new UnnecessaryElseVisitor(this, inspectionManager, onTheFly); + } + + public String buildErrorString(PsiElement location) { + return "#ref branch may be unwrapped, or the following statements placed in the else branch, as the if branch never completes #loc"; + } + + private static class UnnecessaryElseVisitor extends BaseInspectionVisitor { + private UnnecessaryElseVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitIfStatement(PsiIfStatement statement) { + super.visitIfStatement(statement); + final PsiStatement thenBranch = statement.getThenBranch(); + if (thenBranch == null) { + return; + } + final PsiStatement elseBranch = statement.getElseBranch(); + if (elseBranch == null) { + return; + } + if (elseBranch instanceof PsiIfStatement) { + return; + } + + + if (ControlFlowUtils.statementMayCompleteNormally(thenBranch)) { + return; + } + + final PsiStatement nextStatement = findNextStatement(statement); + + if (nextStatement == null) { + return; + } + if (!ControlFlowUtils.statementMayCompleteNormally(elseBranch)) { + return; //protecting against an edge case where both branches return + // and are followed by a case label + } + + final PsiElement elseToken = statement.getElseElement(); + registerError(elseToken); + } + + private static PsiStatement findNextStatement(PsiStatement statement) { + PsiElement next = statement.getNextSibling(); + while (next != null) { + if (next instanceof PsiStatement) { + return (PsiStatement) next; + } + next = next.getNextSibling(); + } + return null; + } + + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/confusing/ConfusingFloatingPointLiteralInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/confusing/ConfusingFloatingPointLiteralInspection.java new file mode 100644 index 000000000000..a48c80c65b0f --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/confusing/ConfusingFloatingPointLiteralInspection.java @@ -0,0 +1,125 @@ +package com.siyeh.ig.confusing; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.codeInspection.ProblemDescriptor; +import com.intellij.openapi.project.Project; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiExpression; +import com.intellij.psi.PsiLiteralExpression; +import com.intellij.psi.PsiType; +import com.siyeh.ig.*; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class ConfusingFloatingPointLiteralInspection extends ExpressionInspection { + private static final Pattern pickyFloatingPointPattern = + Pattern.compile("[0-9]+\\.[0-9]+((e|E)(-)?[0-9]+)?(f|F|d|D)?"); + private final ConfusingFloatingPointLiteralFix fix = new ConfusingFloatingPointLiteralFix(); + + public String getDisplayName() { + return "Confusing floating-point literal"; + } + + public String getGroupDisplayName() { + return GroupNames.CONFUSING_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "Confusing floating point literal #ref #loc"; + } + + public InspectionGadgetsFix buildFix(PsiElement location) { + return fix; + } + + private static class ConfusingFloatingPointLiteralFix extends InspectionGadgetsFix { + public String getName() { + return "Change To canonical form"; + } + + public void applyFix(Project project, ProblemDescriptor descriptor) { + final PsiExpression literalExpression = (PsiExpression) descriptor.getPsiElement(); + final String text = literalExpression.getText(); + final String newText = getCanonicalForm(text); + replaceExpression(project, literalExpression, newText); + } + + private static String getCanonicalForm(String text) { + final String suffix; + final String prefix; + if (text.indexOf((int) 'e') > 0) { + final int breakPoint = text.indexOf((int) 'e'); + suffix = text.substring(breakPoint); + prefix = text.substring(0, breakPoint); + } else if (text.indexOf((int) 'E') > 0) { + final int breakPoint = text.indexOf((int) 'E'); + suffix = text.substring(breakPoint); + prefix = text.substring(0, breakPoint); + } else if (text.indexOf((int) 'f') > 0) { + final int breakPoint = text.indexOf((int) 'f'); + suffix = text.substring(breakPoint); + prefix = text.substring(0, breakPoint); + } else if (text.indexOf((int) 'F') > 0) { + final int breakPoint = text.indexOf((int) 'F'); + suffix = text.substring(breakPoint); + prefix = text.substring(0, breakPoint); + } else if (text.indexOf((int) 'd') > 0) { + final int breakPoint = text.indexOf((int) 'd'); + suffix = text.substring(breakPoint); + prefix = text.substring(0, breakPoint); + } else if (text.indexOf((int) 'D') > 0) { + final int breakPoint = text.indexOf((int) 'D'); + suffix = text.substring(breakPoint); + prefix = text.substring(0, breakPoint); + } else { + suffix = ""; + prefix = text; + } + final int indexPoint = prefix.indexOf((int) '.'); + if (indexPoint < 0) { + return prefix + ".0" + suffix; + } else if (indexPoint == 0) { + return '0' + prefix + suffix; + } else { + return prefix + '0' + suffix; + } + + } + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new ConfusingFloatingPointLiteralVisitor(this, inspectionManager, onTheFly); + } + + private static class ConfusingFloatingPointLiteralVisitor extends BaseInspectionVisitor { + private ConfusingFloatingPointLiteralVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitLiteralExpression(PsiLiteralExpression literal) { + super.visitLiteralExpression(literal); + final PsiType type = literal.getType(); + if (type == null) { + return; + } + if (!(type.equals(PsiType.FLOAT) || type.equals(PsiType.DOUBLE))) { + return; + } + final String text = literal.getText(); + if (text == null) { + return; + } + if (!isConfusing(text)) { + return; + } + registerError(literal); + } + + private static boolean isConfusing(String text) { + final Matcher matcher = pickyFloatingPointPattern.matcher(text); + return !matcher.matches(); + } + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/confusing/ConfusingOctalEscapeInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/confusing/ConfusingOctalEscapeInspection.java new file mode 100644 index 000000000000..a954d097e6f7 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/confusing/ConfusingOctalEscapeInspection.java @@ -0,0 +1,75 @@ +package com.siyeh.ig.confusing; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiLiteralExpression; +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 ConfusingOctalEscapeInspection extends ExpressionInspection { + + public String getDisplayName() { + return "Confusing octal escape sequence"; + } + + public String getGroupDisplayName() { + return GroupNames.CONFUSING_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "String #ref contains potentially confusing octal escape sequence #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new ConfusingOctalEscapeVisitor(this, inspectionManager, onTheFly); + } + + private static class ConfusingOctalEscapeVisitor extends BaseInspectionVisitor { + private ConfusingOctalEscapeVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitLiteralExpression(PsiLiteralExpression exp) { + super.visitLiteralExpression(exp); + if (!TypeUtils.expressionHasType("java.lang.String", exp)) { + return; + } + final String text = exp.getText(); + if (!containsConfusingOctalEscape(text)) { + return; + } + registerError(exp); + } + + } + + private static boolean containsConfusingOctalEscape(String text) { + int escapeStart = -1; + while (true) { + escapeStart = text.indexOf((int) '\\', escapeStart + 1); + if (escapeStart < 0) { + return false; + } + int digitPosition = escapeStart + 1; + while (digitPosition < text.length() && + Character.isDigit(text.charAt(digitPosition))) { + digitPosition++; + } + if (digitPosition > escapeStart + 1) { + final String escapeString = text.substring(escapeStart + 1, digitPosition); + if (escapeString.length() > 3) { + return true; + } + if (escapeString.indexOf((int) '8') > 0 || + escapeString.indexOf((int) '9') > 0) { + return true; + } + } + } + } + + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/confusing/ContinueStatementInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/confusing/ContinueStatementInspection.java new file mode 100644 index 000000000000..23e10037bef4 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/confusing/ContinueStatementInspection.java @@ -0,0 +1,41 @@ +package com.siyeh.ig.confusing; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.psi.PsiContinueStatement; +import com.intellij.psi.PsiElement; +import com.siyeh.ig.BaseInspection; +import com.siyeh.ig.BaseInspectionVisitor; +import com.siyeh.ig.GroupNames; +import com.siyeh.ig.StatementInspection; + +public class ContinueStatementInspection extends StatementInspection { + + public String getDisplayName() { + return "'continue' statement"; + } + + public String getGroupDisplayName() { + return GroupNames.CONFUSING_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "#ref statement #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new ContinueStatementVisitor(this, inspectionManager, onTheFly); + } + + private static class ContinueStatementVisitor extends BaseInspectionVisitor { + private ContinueStatementVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitContinueStatement(PsiContinueStatement statement) { + super.visitContinueStatement(statement); + registerStatementError(statement); + } + + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/confusing/ContinueStatementWithLabelInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/confusing/ContinueStatementWithLabelInspection.java new file mode 100644 index 000000000000..bb46c1dc4f37 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/confusing/ContinueStatementWithLabelInspection.java @@ -0,0 +1,53 @@ +package com.siyeh.ig.confusing; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.psi.PsiContinueStatement; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiIdentifier; +import com.siyeh.ig.BaseInspection; +import com.siyeh.ig.BaseInspectionVisitor; +import com.siyeh.ig.GroupNames; +import com.siyeh.ig.StatementInspection; + +public class ContinueStatementWithLabelInspection extends StatementInspection { + + public String getDisplayName() { + return "'continue' statement with label"; + } + + public String getGroupDisplayName() { + return GroupNames.CONFUSING_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "#ref statement with label #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new ContinueStatementVisitor(this, inspectionManager, onTheFly); + } + + private static class ContinueStatementVisitor extends BaseInspectionVisitor { + private ContinueStatementVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitContinueStatement(PsiContinueStatement statement) { + super.visitContinueStatement(statement); + final PsiIdentifier label = statement.getLabelIdentifier(); + if (label == null) { + return; + } + final String labelText = label.getText(); + if (labelText == null) { + return; + } + if (labelText.length() == 0) { + return; + } + registerStatementError(statement); + } + + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/confusing/IfStatementWithTooManyBranchesInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/confusing/IfStatementWithTooManyBranchesInspection.java new file mode 100644 index 000000000000..fa1e5d6126fc --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/confusing/IfStatementWithTooManyBranchesInspection.java @@ -0,0 +1,81 @@ +package com.siyeh.ig.confusing; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiIfStatement; +import com.intellij.psi.PsiStatement; +import com.siyeh.ig.BaseInspection; +import com.siyeh.ig.BaseInspectionVisitor; +import com.siyeh.ig.GroupNames; +import com.siyeh.ig.StatementInspection; +import com.siyeh.ig.ui.SingleIntegerFieldOptionsPanel; + +import javax.swing.*; + +public class IfStatementWithTooManyBranchesInspection extends StatementInspection { + private static final int DEFAULT_BRANCH_LIMIT = 3; + + public int m_limit = DEFAULT_BRANCH_LIMIT; //this is public for the DefaultJDOMExternalizer thingy + + public String getDisplayName() { + return "If statement with too many branches"; + } + + public String getGroupDisplayName() { + return GroupNames.CONFUSING_GROUP_NAME; + } + + private int getLimit() { + return m_limit; + } + + public JComponent createOptionsPanel() { + return new SingleIntegerFieldOptionsPanel("Maximum number of branches:", + this, "m_limit"); + } + + protected String buildErrorString(PsiElement location) { + final PsiIfStatement statement = (PsiIfStatement) location.getParent(); + final int branches = calculateNumBranches(statement); + return "'#ref' has too many branches (" + branches + ") #loc"; + } + + private int calculateNumBranches(PsiIfStatement statement) { + final PsiStatement branch = statement.getElseBranch(); + if (branch == null) { + return 1; + } + if (!(branch instanceof PsiIfStatement)) { + return 2; + } + return 1 + calculateNumBranches((PsiIfStatement) branch); + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new IfStatementWithTooManyBranchesVisitor(this, inspectionManager, onTheFly); + } + + private class IfStatementWithTooManyBranchesVisitor extends BaseInspectionVisitor { + private IfStatementWithTooManyBranchesVisitor(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; + } + } + final int branches = calculateNumBranches(statement); + if (branches <= getLimit()) { + return; + } + registerStatementError(statement); + } + + } +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/confusing/ImplicitCallToSuperInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/confusing/ImplicitCallToSuperInspection.java new file mode 100644 index 000000000000..496e92fbc839 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/confusing/ImplicitCallToSuperInspection.java @@ -0,0 +1,119 @@ +package com.siyeh.ig.confusing; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.codeInspection.ProblemDescriptor; +import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.project.Project; +import com.intellij.psi.*; +import com.intellij.psi.codeStyle.CodeStyleManager; +import com.intellij.util.IncorrectOperationException; +import com.siyeh.ig.*; + +public class ImplicitCallToSuperInspection extends MethodInspection { + + public String getDisplayName() { + return "Implicit call to super()"; + } + + public String getGroupDisplayName() { + return GroupNames.CONFUSING_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "Implicit call to super() #ref #loc"; + } + + public InspectionGadgetsFix buildFix(PsiElement location) { + return new AddExplicitSuperCall(); + } + + private static class AddExplicitSuperCall extends InspectionGadgetsFix { + public String getName() { + return "Make construction of super() explicit"; + } + + public void applyFix(Project project, ProblemDescriptor descriptor) { + try { + final PsiElement methodName = descriptor.getPsiElement(); + final PsiMethod method = (PsiMethod) methodName.getParent(); + final PsiCodeBlock body = method.getBody(); + final PsiManager psiManager = PsiManager.getInstance(project); + final PsiElementFactory factory = psiManager.getElementFactory(); + final PsiStatement newStatement = factory.createStatementFromText("super();", null); + final CodeStyleManager styleManager = psiManager.getCodeStyleManager(); + final PsiJavaToken brace = body.getLBrace(); + body.addAfter(newStatement, brace); + styleManager.reformat(body); + } catch (IncorrectOperationException e) { + final Class aClass = getClass(); + final String className = aClass.getName(); + final Logger logger = Logger.getInstance(className); + logger.error(e); + } + } + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new ImplicitCallToSuperVisitor(this, inspectionManager, onTheFly); + } + + private static class ImplicitCallToSuperVisitor extends BaseInspectionVisitor { + private ImplicitCallToSuperVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitMethod(PsiMethod method) { + super.visitMethod(method); + if (!method.isConstructor()) { + return; + } + final PsiClass containingClass = method.getContainingClass(); + if (containingClass == null) { + return; + } + if (containingClass.isEnum()) { + return; + } + final PsiCodeBlock body = method.getBody(); + if (body == null) { + return; + } + final PsiStatement[] statements = body.getStatements(); + if (statements == null) { + return; + } + if (statements.length == 0) { + registerMethodError(method); + return; + } + final PsiStatement firstStatement = statements[0]; + if (isConstructorCall(firstStatement)) { + return; + } + registerMethodError(method); + } + + private static boolean isConstructorCall(PsiStatement statement) { + if (!(statement instanceof PsiExpressionStatement)) { + return false; + } + final PsiExpressionStatement expressionStatement = (PsiExpressionStatement) statement; + final PsiExpression expression = expressionStatement.getExpression(); + if (expression == null) { + return false; + } + if (!(expression instanceof PsiMethodCallExpression)) { + return false; + } + final PsiMethodCallExpression methodCall = (PsiMethodCallExpression) expression; + final PsiReferenceExpression methodExpression = methodCall.getMethodExpression(); + if (methodExpression == null) { + return false; + } + final String text = methodExpression.getText(); + + return "super".equals(text) || "this".equals(text); + } + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/confusing/ImplicitNumericConversionInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/confusing/ImplicitNumericConversionInspection.java new file mode 100644 index 000000000000..94707a754a9e --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/confusing/ImplicitNumericConversionInspection.java @@ -0,0 +1,197 @@ +package com.siyeh.ig.confusing; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.codeInspection.ProblemDescriptor; +import com.intellij.openapi.project.Project; +import com.intellij.psi.*; +import com.siyeh.ig.*; +import com.siyeh.ig.psiutils.ClassUtils; +import com.siyeh.ig.psiutils.ExpectedTypeUtils; +import com.siyeh.ig.psiutils.ParenthesesUtils; + +public class ImplicitNumericConversionInspection extends ExpressionInspection { + + public String getDisplayName() { + return "Implicit numeric conversions"; + } + + public String getGroupDisplayName() { + return GroupNames.CONFUSING_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + final PsiExpression expression = (PsiExpression) location; + final PsiType type = expression.getType(); + final PsiType expectedType = ExpectedTypeUtils.findExpectedType(expression); + return "Implicit numeric conversion of #ref from " + type.getPresentableText() + " to " + + expectedType.getPresentableText() + + " #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new ImplicitNumericConversionVisitor(this, inspectionManager, onTheFly); + } + + public InspectionGadgetsFix buildFix(PsiElement location) { + return new ImplicitNumericConversionFix(location); + } + + private static class ImplicitNumericConversionFix extends InspectionGadgetsFix { + private final String m_name; + + private ImplicitNumericConversionFix(PsiElement field) { + super(); + final PsiExpression expression = (PsiExpression) field; + final PsiType expectedType = ExpectedTypeUtils.findExpectedType(expression); + if (isConvertible(expression, expectedType)) { + m_name = "Convert to " + expectedType.getCanonicalText() + " literal"; + } else { + m_name = "Make conversion explicit"; + } + } + + public String getName() { + return m_name; + } + + public void applyFix(Project project, ProblemDescriptor descriptor) { + final PsiExpression expression = (PsiExpression) descriptor.getPsiElement(); + final PsiType expectedType = ExpectedTypeUtils.findExpectedType(expression); + if (isConvertible(expression, expectedType)) { + final String newExpression = convertExpression(expression, expectedType); + replaceExpression(project, expression, newExpression); + } else { + final String newExpression; + if (ParenthesesUtils.getPrecendence(expression) <= ParenthesesUtils.TYPE_CAST_PRECEDENCE) { + newExpression = '(' + expectedType.getPresentableText() + ')' + expression.getText(); + } else { + newExpression = '(' + expectedType.getPresentableText() + ")(" + expression.getText() + ')'; + } + replaceExpression(project, expression, newExpression); + } + } + + private static String convertExpression(PsiExpression expression, PsiType expectedType) { + final PsiType expressionType = expression.getType(); + + if (expressionType.equals(PsiType.INT) && expectedType.equals(PsiType.LONG)) { + return expression.getText() + 'L'; + } + if (expressionType.equals(PsiType.INT) && expectedType.equals(PsiType.FLOAT)) { + return expression.getText() + ".0F"; + } + if (expressionType.equals(PsiType.INT) && expectedType.equals(PsiType.DOUBLE)) { + return expression.getText() + ".0"; + } + if (expressionType.equals(PsiType.LONG) && expectedType.equals(PsiType.FLOAT)) { + final String text = expression.getText(); + final int length = text.length(); + return text.substring(0, length - 1) + ".0F"; + } + if (expressionType.equals(PsiType.LONG) && expectedType.equals(PsiType.DOUBLE)) { + final String text = expression.getText(); + final int length = text.length(); + return text.substring(0, length - 1) + ".0"; + } + if (expressionType.equals(PsiType.DOUBLE) && expectedType.equals(PsiType.FLOAT)) { + final String text = expression.getText(); + final int length = text.length(); + if (text.charAt(length - 1) == 'd' || text.charAt(length - 1) == 'D') { + return text.substring(0, length - 1) + 'F'; + } else { + return text + 'F'; + } + } + if (expressionType.equals(PsiType.FLOAT) && expectedType.equals(PsiType.DOUBLE)) { + final String text = expression.getText(); + final int length = text.length(); + return text.substring(0, length - 1); + } + return null; //can't happen + } + + private static boolean isConvertible(PsiExpression expression, PsiType expectedType) { + if (!(expression instanceof PsiLiteralExpression)) { + return false; + } + final PsiType expressionType = expression.getType(); + if (expressionType == null) { + return false; + } + if (isIntegral(expressionType) && isIntegral(expectedType)) { + return true; + } + if (isIntegral(expressionType) && isFloatingPoint(expectedType)) { + return true; + } + if (isFloatingPoint(expressionType) && isFloatingPoint(expectedType)) { + return true; + } + + return false; + } + + private static boolean isIntegral(PsiType expressionType) { + return expressionType.equals(PsiType.INT) || expressionType.equals(PsiType.LONG); + } + + private static boolean isFloatingPoint(PsiType expressionType) { + return expressionType.equals(PsiType.FLOAT) || expressionType.equals(PsiType.DOUBLE); + } + } + + private static class ImplicitNumericConversionVisitor extends BaseInspectionVisitor { + private ImplicitNumericConversionVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitReferenceExpression(PsiReferenceExpression exp) { + super.visitReferenceExpression(exp); + final PsiType expressionType = exp.getType(); + if (expressionType == null) { + return; + } + if (!ClassUtils.isPrimitiveNumericType(expressionType)) { + return; + } + + final PsiType expectedType = ExpectedTypeUtils.findExpectedType(exp); + if (expectedType == null) { + return; + } + + if (!ClassUtils.isPrimitiveNumericType(expectedType)) { + return; + } + if (expectedType.equals(expressionType)) { + return; + } + registerError(exp); + } + + public void visitExpression(PsiExpression exp) { + super.visitExpression(exp); + final PsiType expressionType = exp.getType(); + if (expressionType == null) { + return; + } + if (!ClassUtils.isPrimitiveNumericType(expressionType)) { + return; + } + + final PsiType expectedType = ExpectedTypeUtils.findExpectedType(exp); + if (expectedType == null) { + return; + } + if (!ClassUtils.isPrimitiveNumericType(expectedType)) { + return; + } + + if (expectedType.equals(expressionType)) { + return; + } + registerError(exp); + } + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/confusing/IncrementDecrementUsedAsExpressionInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/confusing/IncrementDecrementUsedAsExpressionInspection.java new file mode 100644 index 000000000000..dad34d6916bd --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/confusing/IncrementDecrementUsedAsExpressionInspection.java @@ -0,0 +1,88 @@ +package com.siyeh.ig.confusing; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.psi.*; +import com.intellij.psi.tree.IElementType; +import com.siyeh.ig.BaseInspection; +import com.siyeh.ig.BaseInspectionVisitor; +import com.siyeh.ig.ExpressionInspection; +import com.siyeh.ig.GroupNames; + +public class IncrementDecrementUsedAsExpressionInspection extends ExpressionInspection { + + public String getDisplayName() { + return "Value of ++ or -- used"; + } + + public String getGroupDisplayName() { + return GroupNames.CONFUSING_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + final String expressionType; + if (location instanceof PsiPostfixExpression) { + final PsiJavaToken sign = ((PsiPostfixExpression) location).getOperationSign(); + if (sign.getTokenType() == JavaTokenType.PLUSPLUS) { + expressionType = "post-increment"; + } else { + expressionType = "post-decrement"; + } + } else { + final PsiJavaToken sign = ((PsiPrefixExpression) location).getOperationSign(); + if (sign.getTokenType() == JavaTokenType.PLUSPLUS) { + expressionType = "pre-increment"; + } else { + expressionType = "pre-decrement"; + } + } + return "Value of " + expressionType + " expression #ref is used #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new IncrementDecrementUsedAsExpressionVisitor(this, inspectionManager, onTheFly); + } + + private static class IncrementDecrementUsedAsExpressionVisitor extends BaseInspectionVisitor { + private IncrementDecrementUsedAsExpressionVisitor(BaseInspection inspection, + InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitPostfixExpression(PsiPostfixExpression expression) { + super.visitPostfixExpression(expression); + if (expression.getParent() instanceof PsiExpressionStatement) { + return; + } + final PsiJavaToken sign = expression.getOperationSign(); + if (sign == null) { + return; + } + final IElementType tokenType = sign.getTokenType(); + if (!tokenType.equals(JavaTokenType.PLUSPLUS) && + !tokenType.equals(JavaTokenType.MINUSMINUS)) { + return; + } + registerError(expression); + } + + public void visitPrefixExpression(PsiPrefixExpression expression) { + super.visitPrefixExpression(expression); + + if (expression.getParent() instanceof PsiExpressionStatement || + expression.getParent() instanceof PsiExpressionList) { + return; + } + final PsiJavaToken sign = expression.getOperationSign(); + if (sign == null) { + return; + } + final IElementType tokenType = sign.getTokenType(); + if (!tokenType.equals(JavaTokenType.PLUSPLUS) && + !tokenType.equals(JavaTokenType.MINUSMINUS)) { + return; + } + registerError(expression); + } + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/confusing/LocalVariableAccessVisitor.java b/plugins/InspectionGadgets/src/com/siyeh/ig/confusing/LocalVariableAccessVisitor.java new file mode 100644 index 000000000000..8b80ce447c11 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/confusing/LocalVariableAccessVisitor.java @@ -0,0 +1,39 @@ +package com.siyeh.ig.confusing; + +import com.intellij.psi.*; + +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; + +class LocalVariableAccessVisitor extends PsiRecursiveElementVisitor { + private final Set m_accesssedVariables = new HashSet(2); + + LocalVariableAccessVisitor() { + super(); + } + + 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); + } + if (qualifier != null && !(qualifier instanceof PsiThisExpression)) { + return; + } + final PsiElement element = ref.resolve(); + if (!(element instanceof PsiLocalVariable)) { + return; + } + m_accesssedVariables.add(element); + } + + public Set getAccessedVariables() { + return Collections.unmodifiableSet(m_accesssedVariables); + } +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/confusing/LongLiteralsEndingWithLowercaseLInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/confusing/LongLiteralsEndingWithLowercaseLInspection.java new file mode 100644 index 000000000000..b0572d26ad6e --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/confusing/LongLiteralsEndingWithLowercaseLInspection.java @@ -0,0 +1,77 @@ +package com.siyeh.ig.confusing; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.codeInspection.ProblemDescriptor; +import com.intellij.openapi.project.Project; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiExpression; +import com.intellij.psi.PsiLiteralExpression; +import com.intellij.psi.PsiType; +import com.siyeh.ig.*; + +public class LongLiteralsEndingWithLowercaseLInspection extends ExpressionInspection { + private final LongLiteralFix fix = new LongLiteralFix(); + + public String getDisplayName() { + return "Long literal ending with 'l' instead of 'L'"; + } + + public String getGroupDisplayName() { + return GroupNames.CONFUSING_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "Long literal #ref ends with lowercase 'l' #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new LongLiteralWithLowercaseLVisitor(this, inspectionManager, onTheFly); + } + + public InspectionGadgetsFix buildFix(PsiElement location) { + return fix; + } + + private static class LongLiteralFix extends InspectionGadgetsFix { + public String getName() { + return "Replace 'l' with 'L'"; + } + + public void applyFix(Project project, ProblemDescriptor descriptor) { + final PsiExpression literal = (PsiExpression) descriptor.getPsiElement(); + final String text = literal.getText(); + final String newText = text.replace('l', 'L'); + replaceExpression(project, literal, newText); + } + } + + private static class LongLiteralWithLowercaseLVisitor extends BaseInspectionVisitor { + private LongLiteralWithLowercaseLVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitLiteralExpression(PsiLiteralExpression expression) { + super.visitLiteralExpression(expression); + final PsiType type = expression.getType(); + if (type == null) { + return; + } + if (!type.equals(PsiType.LONG)) { + return; + } + final String text = expression.getText(); + if (text == null) { + return; + } + final int length = text.length(); + if (length == 0) { + return; + } + if (text.charAt(length - 1) != 'l') { + return; + } + registerError(expression); + } + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/confusing/MethodNamesDifferOnlyByCaseInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/confusing/MethodNamesDifferOnlyByCaseInspection.java new file mode 100644 index 000000000000..b51586231046 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/confusing/MethodNamesDifferOnlyByCaseInspection.java @@ -0,0 +1,63 @@ +package com.siyeh.ig.confusing; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.psi.PsiClass; +import com.intellij.psi.PsiIdentifier; +import com.intellij.psi.PsiMethod; +import com.siyeh.ig.BaseInspection; +import com.siyeh.ig.BaseInspectionVisitor; +import com.siyeh.ig.GroupNames; +import com.siyeh.ig.MethodInspection; + +public class MethodNamesDifferOnlyByCaseInspection extends MethodInspection { + + public String getDisplayName() { + return "Method names differing only by case"; + } + + public String getGroupDisplayName() { + return GroupNames.CONFUSING_GROUP_NAME; + } + + public String buildErrorString(Object val) { + return "Method names '#ref' and '" + val + "' differ only by case"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new OverloadedMethodsWithSameNumberOfParametersVisitor(this, inspectionManager, onTheFly); + } + + private static class OverloadedMethodsWithSameNumberOfParametersVisitor extends BaseInspectionVisitor { + private OverloadedMethodsWithSameNumberOfParametersVisitor(BaseInspection inspection, + InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitMethod(PsiMethod method) { + if (method.isConstructor()) { + return; + } + final PsiIdentifier nameIdentifier = method.getNameIdentifier(); + if (nameIdentifier == null) { + return; + } + final String methodName = method.getName(); + if (methodName == null) { + return; + } + final PsiClass aClass = method.getContainingClass(); + if (aClass == null) { + return; + } + final PsiMethod[] methods = aClass.getMethods(); + for (int i = 0; i < methods.length; i++) { + final String testMethName = methods[i].getName(); + if (testMethName != null && !methodName.equals(testMethName) && + methodName.equalsIgnoreCase(testMethName)) { + registerError(nameIdentifier, testMethName); + } + } + } + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/confusing/NegatedConditionalInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/confusing/NegatedConditionalInspection.java new file mode 100644 index 000000000000..38c47c4c9ce3 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/confusing/NegatedConditionalInspection.java @@ -0,0 +1,101 @@ +package com.siyeh.ig.confusing; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.psi.*; +import com.intellij.psi.tree.IElementType; +import com.siyeh.ig.BaseInspection; +import com.siyeh.ig.BaseInspectionVisitor; +import com.siyeh.ig.ExpressionInspection; +import com.siyeh.ig.GroupNames; +import com.siyeh.ig.ui.SingleCheckboxOptionsPanel; + +import javax.swing.*; + +public class NegatedConditionalInspection extends ExpressionInspection { + public boolean m_ignoreNegatedNullComparison = true; + + public String getDisplayName() { + return "Conditional expression with negated condition"; + } + + public String getGroupDisplayName() { + return GroupNames.CONFUSING_GROUP_NAME; + } + + protected BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new NegatedConditionalVisitor(this, inspectionManager, onTheFly); + } + + public String buildErrorString(PsiElement location) { + return "Conditional expression with negated condition #loc"; + } + + public JComponent createOptionsPanel() { + return new SingleCheckboxOptionsPanel("Ignore '!= null' comparisons", + this, "m_ignoreNegatedNullComparison"); + } + + private class NegatedConditionalVisitor extends BaseInspectionVisitor { + private NegatedConditionalVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitConditionalExpression(PsiConditionalExpression expression) { + super.visitConditionalExpression(expression); + final PsiExpression thenBranch = expression.getThenExpression(); + if (thenBranch == null) { + return; + } + final PsiExpression elseBranch = expression.getElseExpression(); + if (elseBranch == null) { + return; + } + + final PsiExpression condition = expression.getCondition(); + if (condition == null) { + return; + } + if (!isNegation(condition)) { + return; + } + registerError(condition); + } + + private boolean isNegation(PsiExpression condition) { + if (condition instanceof PsiPrefixExpression) { + final PsiPrefixExpression prefixExpression = (PsiPrefixExpression) condition; + final PsiJavaToken sign = prefixExpression.getOperationSign(); + final IElementType tokenType = sign.getTokenType(); + return tokenType.equals(JavaTokenType.EXCL); + } else if (condition instanceof PsiBinaryExpression) { + final PsiBinaryExpression binaryExpression = (PsiBinaryExpression) condition; + final PsiJavaToken sign = binaryExpression.getOperationSign(); + final PsiExpression lhs = binaryExpression.getLOperand(); + final PsiExpression rhs = binaryExpression.getROperand(); + if (lhs == null || rhs == null) { + return false; + } + final IElementType tokenType = sign.getTokenType(); + if (tokenType.equals(JavaTokenType.NE)) { + if (m_ignoreNegatedNullComparison) { + final String lhsText = lhs.getText(); + final String rhsText = rhs.getText(); + return !"null".equals(lhsText) && !"null".equals(rhsText); + } else { + return true; + } + } else { + return false; + } + } else if (condition instanceof PsiParenthesizedExpression) { + final PsiExpression expression = + ((PsiParenthesizedExpression) condition).getExpression(); + return isNegation(expression); + } else { + return false; + } + } + + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/confusing/NegatedIfElseInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/confusing/NegatedIfElseInspection.java new file mode 100644 index 000000000000..d5998486d92a --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/confusing/NegatedIfElseInspection.java @@ -0,0 +1,104 @@ +package com.siyeh.ig.confusing; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.psi.*; +import com.intellij.psi.tree.IElementType; +import com.siyeh.ig.BaseInspection; +import com.siyeh.ig.BaseInspectionVisitor; +import com.siyeh.ig.GroupNames; +import com.siyeh.ig.StatementInspection; +import com.siyeh.ig.ui.SingleCheckboxOptionsPanel; + +import javax.swing.*; + +public class NegatedIfElseInspection extends StatementInspection { + public boolean m_ignoreNegatedNullComparison = true; + + public String getDisplayName() { + return "If statement with negated condition"; + } + + public String getGroupDisplayName() { + return GroupNames.CONFUSING_GROUP_NAME; + } + + protected BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new NegatedIfElseVisitor(this, inspectionManager, onTheFly); + } + + public String buildErrorString(PsiElement location) { + return "#ref statement with negated condition #loc"; + } + + public JComponent createOptionsPanel() { + return new SingleCheckboxOptionsPanel("Ignore '!= null' comparisons", + this, "m_ignoreNegatedNullComparison"); + } + + private class NegatedIfElseVisitor extends BaseInspectionVisitor { + private NegatedIfElseVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitIfStatement(PsiIfStatement statement) { + super.visitIfStatement(statement); + final PsiStatement thenBranch = statement.getThenBranch(); + if (thenBranch == null) { + return; + } + final PsiStatement elseBranch = statement.getElseBranch(); + if (elseBranch == null) { + return; + } + if (elseBranch instanceof PsiIfStatement) { + return; + } + + final PsiExpression condition = statement.getCondition(); + if (condition == null) { + return; + } + if (!isNegation(condition)) { + return; + } + final PsiElement parent = statement.getParent(); + if (parent instanceof PsiIfStatement) { + return; + } + registerStatementError(statement); + } + + private boolean isNegation(PsiExpression condition) { + if (condition instanceof PsiPrefixExpression) { + final PsiPrefixExpression prefixExpression = (PsiPrefixExpression) condition; + final PsiJavaToken sign = prefixExpression.getOperationSign(); + final IElementType tokenType = sign.getTokenType(); + return tokenType.equals(JavaTokenType.EXCL); + } else if (condition instanceof PsiBinaryExpression) { + final PsiBinaryExpression binaryExpression = (PsiBinaryExpression) condition; + final PsiJavaToken sign = binaryExpression.getOperationSign(); + final PsiExpression lhs = binaryExpression.getLOperand(); + final PsiExpression rhs = binaryExpression.getROperand(); + if (lhs == null || rhs == null) { + return false; + } + final IElementType tokenType = sign.getTokenType(); + if (tokenType.equals(JavaTokenType.NE)) { + if (m_ignoreNegatedNullComparison) { + final String lhsText = lhs.getText(); + final String rhsText = rhs.getText(); + return !"null".equals(lhsText) && !"null".equals(rhsText); + } else { + return true; + } + } else { + return false; + } + } else { + return false; + } + } + + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/confusing/NestedAssignmentInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/confusing/NestedAssignmentInspection.java new file mode 100644 index 000000000000..a668adf2d95c --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/confusing/NestedAssignmentInspection.java @@ -0,0 +1,46 @@ +package com.siyeh.ig.confusing; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.psi.PsiAssignmentExpression; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiExpressionList; +import com.intellij.psi.PsiExpressionStatement; +import com.siyeh.ig.BaseInspection; +import com.siyeh.ig.BaseInspectionVisitor; +import com.siyeh.ig.ExpressionInspection; +import com.siyeh.ig.GroupNames; + +public class NestedAssignmentInspection extends ExpressionInspection { + + public String getDisplayName() { + return "Nested assignment"; + } + + public String getGroupDisplayName() { + return GroupNames.CONFUSING_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "Nested assignment #ref #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new NestedAssignmentVisitor(this, inspectionManager, onTheFly); + } + + private static class NestedAssignmentVisitor extends BaseInspectionVisitor { + private NestedAssignmentVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitAssignmentExpression(PsiAssignmentExpression expression) { + super.visitAssignmentExpression(expression); + if (expression.getParent() instanceof PsiExpressionStatement || + expression.getParent() instanceof PsiExpressionList) { + return; + } + registerError(expression); + } + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/confusing/NestedConditionalExpressionInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/confusing/NestedConditionalExpressionInspection.java new file mode 100644 index 000000000000..910eb0451f37 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/confusing/NestedConditionalExpressionInspection.java @@ -0,0 +1,44 @@ +package com.siyeh.ig.confusing; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.psi.PsiConditionalExpression; +import com.intellij.psi.PsiElement; +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 NestedConditionalExpressionInspection extends ExpressionInspection { + + public String getDisplayName() { + return "Nested conditional expression"; + } + + public String getGroupDisplayName() { + return GroupNames.CONFUSING_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "Nested conditional expression #ref #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new NestedConditionalExpressionVisitor(this, inspectionManager, onTheFly); + } + + private static class NestedConditionalExpressionVisitor extends BaseInspectionVisitor { + private NestedConditionalExpressionVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitConditionalExpression(PsiConditionalExpression exp) { + super.visitConditionalExpression(exp); + if (PsiTreeUtil.getParentOfType(exp, PsiConditionalExpression.class) != null) { + registerError(exp); + } + } + + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/confusing/NestedMethodCallInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/confusing/NestedMethodCallInspection.java new file mode 100644 index 000000000000..ad6fac06d735 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/confusing/NestedMethodCallInspection.java @@ -0,0 +1,113 @@ +package com.siyeh.ig.confusing; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.codeInspection.ProblemDescriptor; +import com.intellij.openapi.project.Project; +import com.intellij.psi.*; +import com.intellij.psi.util.PsiTreeUtil; +import com.intellij.refactoring.RefactoringActionHandler; +import com.intellij.refactoring.RefactoringActionHandlerFactory; +import com.siyeh.ig.*; +import com.siyeh.ig.ui.SingleCheckboxOptionsPanel; + +import javax.swing.*; + +public class NestedMethodCallInspection extends ExpressionInspection { + private boolean m_ignoreFieldInitializations = true; + private final NestedMethodCallFix fix = new NestedMethodCallFix(); + + public String getDisplayName() { + return "Nested method calls"; + } + + public String getGroupDisplayName() { + return GroupNames.CONFUSING_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "Nested method call #ref() #loc"; + } + + public JComponent createOptionsPanel() { + return new SingleCheckboxOptionsPanel("Ignore nested method calls in field initializers", + this, "m_ignoreFieldInitializations"); + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new NestedMethodCallVisitor(this, inspectionManager, onTheFly); + } + + protected InspectionGadgetsFix buildFix(PsiElement location) { + return fix; + } + + protected boolean buildQuickFixesOnlyForOnTheFlyErrors() { + return true; + } + + private static class NestedMethodCallFix extends InspectionGadgetsFix { + public String getName() { + return "Introduce variable"; + } + + public void applyFix(Project project, ProblemDescriptor descriptor) { + final RefactoringActionHandlerFactory factory = RefactoringActionHandlerFactory.getInstance(); + final RefactoringActionHandler introduceHandler = + factory.createIntroduceVariableHandler(); + final PsiElement methodNameElement = descriptor.getPsiElement(); + final PsiElement methodExpression = methodNameElement.getParent(); + final PsiElement methodCallExpression = methodExpression.getParent(); + introduceHandler.invoke(project, new PsiElement[]{methodCallExpression}, null); + } + } + + private class NestedMethodCallVisitor extends BaseInspectionVisitor { + private NestedMethodCallVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitMethodCallExpression(PsiMethodCallExpression expression) { + super.visitMethodCallExpression(expression); + PsiExpression outerExpression = expression; + while (outerExpression.getParent() instanceof PsiExpression) { + outerExpression = (PsiExpression) outerExpression.getParent(); + } + final PsiElement parent = outerExpression.getParent(); + if (parent == null) { + return; + } + if (!(parent instanceof PsiExpressionList)) { + return; + } + final PsiElement grandParent = parent.getParent(); + if (!(grandParent instanceof PsiCallExpression)) { + return; + } + if(grandParent instanceof PsiMethodCallExpression) + { + + final PsiMethodCallExpression surroundingCall = + (PsiMethodCallExpression)grandParent; + final PsiReferenceExpression methodExpression = surroundingCall.getMethodExpression(); + final String callName = methodExpression.getReferenceName(); + if("this".equals(callName)||"super".equals(callName)) + { + return; //ignore nested method calls at the start of a constructor, + //where they can't be extracted + } + + } + final PsiReferenceExpression reference = expression.getMethodExpression(); + if (reference == null) { + return; + } + if (m_ignoreFieldInitializations) { + final PsiElement field = PsiTreeUtil.getParentOfType(expression, PsiField.class); + if (field != null) { + return; + } + } + registerMethodCallError(expression); + } + } +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/confusing/NestedSwitchStatementInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/confusing/NestedSwitchStatementInspection.java new file mode 100644 index 000000000000..751d76501b4f --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/confusing/NestedSwitchStatementInspection.java @@ -0,0 +1,45 @@ +package com.siyeh.ig.confusing; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiSwitchStatement; +import com.intellij.psi.util.PsiTreeUtil; +import com.siyeh.ig.BaseInspection; +import com.siyeh.ig.BaseInspectionVisitor; +import com.siyeh.ig.GroupNames; +import com.siyeh.ig.StatementInspection; + +public class NestedSwitchStatementInspection extends StatementInspection { + + public String getDisplayName() { + return "Nested 'switch' statement"; + } + + public String getGroupDisplayName() { + return GroupNames.CONFUSING_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "Nested '#ref' statement #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new NestedSwitchStatementVisitor(this, inspectionManager, onTheFly); + } + + private static class NestedSwitchStatementVisitor extends BaseInspectionVisitor { + private NestedSwitchStatementVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitSwitchStatement(PsiSwitchStatement statement) { + super.visitSwitchStatement(statement); + if (PsiTreeUtil.getParentOfType(statement, PsiSwitchStatement.class) == null) { + return; + } + registerStatementError(statement); + } + + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/confusing/OctalLiteralInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/confusing/OctalLiteralInspection.java new file mode 100644 index 000000000000..13b75bbeffe1 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/confusing/OctalLiteralInspection.java @@ -0,0 +1,55 @@ +package com.siyeh.ig.confusing; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiLiteralExpression; +import com.intellij.psi.PsiType; +import com.siyeh.ig.*; + +public class OctalLiteralInspection extends ExpressionInspection { + + public String getDisplayName() { + return "Octal integer"; + } + + public String getGroupDisplayName() { + return GroupNames.CONFUSING_GROUP_NAME; + } + + protected String buildErrorString(PsiElement location) { + return "Octal integer #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new OctalLiteralVisitor(this, inspectionManager, onTheFly); + } + + private static class OctalLiteralVisitor extends BaseInspectionVisitor { + private OctalLiteralVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitLiteralExpression(PsiLiteralExpression literal) { + super.visitLiteralExpression(literal); + final PsiType type = literal.getType(); + if (type == null) { + return; + } + if (!(type.equals(PsiType.INT) + || type.equals(PsiType.LONG))) { + return; + } + final String text = literal.getText(); + if ("0".equals(text)||"0L".equals(text)) { + return; + } + if (text.charAt(0) != '0') { + return; + } + if (text.startsWith("0x") || text.startsWith("0X")) { + return; + } + registerError(literal); + } + } +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/confusing/OverloadedMethodsWithSameNumberOfParametersInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/confusing/OverloadedMethodsWithSameNumberOfParametersInspection.java new file mode 100644 index 000000000000..d3268a5b3911 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/confusing/OverloadedMethodsWithSameNumberOfParametersInspection.java @@ -0,0 +1,71 @@ +package com.siyeh.ig.confusing; + +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.MethodInspection; + +public class OverloadedMethodsWithSameNumberOfParametersInspection extends MethodInspection { + + public String getDisplayName() { + return "Overloaded methods with same number of parameters"; + } + + public String getGroupDisplayName() { + return GroupNames.CONFUSING_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "Multiple methods names '#ref' with the same number of parameters"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new OverloadedMethodsWithSameNumberOfParametersVisitor(this, inspectionManager, onTheFly); + } + + private static class OverloadedMethodsWithSameNumberOfParametersVisitor extends BaseInspectionVisitor { + private OverloadedMethodsWithSameNumberOfParametersVisitor(BaseInspection inspection, + InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitMethod(PsiMethod method) { + if (method.isConstructor()) { + return; + } + + final String methodName = method.getName(); + if (methodName == null) { + return; + } + final int parameterCount = calculateParamCount(method); + + final PsiClass aClass = method.getContainingClass(); + if (aClass == null) { + return; + } + final PsiMethod[] methods = aClass.getMethods(); + for (int i = 0; i < methods.length; i++) { + if (!methods[i].equals(method)) { + final String testMethName = methods[i].getName(); + + final int testParameterCount = calculateParamCount(methods[i]); + if (testMethName != null && methodName.equals(testMethName) && + parameterCount == testParameterCount) { + registerMethodError(method); + } + } + } + } + + private static int calculateParamCount(PsiMethod method) { + final PsiParameterList paramList = method.getParameterList(); + final PsiParameter[] parameters = paramList.getParameters(); + final int parameterCount = parameters.length; + return parameterCount; + } + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/confusing/OverlyComplexArithmeticExpressionInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/confusing/OverlyComplexArithmeticExpressionInspection.java new file mode 100644 index 000000000000..c3ce028ca7a8 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/confusing/OverlyComplexArithmeticExpressionInspection.java @@ -0,0 +1,136 @@ +package com.siyeh.ig.confusing; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.psi.*; +import com.intellij.psi.tree.IElementType; +import com.siyeh.ig.BaseInspection; +import com.siyeh.ig.BaseInspectionVisitor; +import com.siyeh.ig.GroupNames; +import com.siyeh.ig.StatementInspection; +import com.siyeh.ig.psiutils.TypeUtils; +import com.siyeh.ig.ui.SingleIntegerFieldOptionsPanel; + +import javax.swing.*; + +public class OverlyComplexArithmeticExpressionInspection extends StatementInspection { + private static final int TERM_LIMIT = 6; + + public int m_limit = TERM_LIMIT; //this is public for the DefaultJDOMExternalizer thingy + + public String getDisplayName() { + return "Overly complex arithmetic expression"; + } + + public String getGroupDisplayName() { + return GroupNames.CONFUSING_GROUP_NAME; + } + + private int getLimit() { + return m_limit; + } + + public JComponent createOptionsPanel() { + return new SingleIntegerFieldOptionsPanel("Maximum number of terms:", + this, "m_limit"); + } + + protected String buildErrorString(PsiElement location) { + return "Overly complex arithmetic expression #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new SwitchStatementWithTooManyBranchesVisitor(this, inspectionManager, onTheFly); + } + + private class SwitchStatementWithTooManyBranchesVisitor extends BaseInspectionVisitor { + private SwitchStatementWithTooManyBranchesVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitBinaryExpression(PsiBinaryExpression expression) { + super.visitBinaryExpression(expression); + checkExpression(expression); + } + + public void visitPrefixExpression(PsiPrefixExpression expression) { + super.visitPrefixExpression(expression); + checkExpression(expression); + } + + public void visitParenthesizedExpression(PsiParenthesizedExpression expression) { + super.visitParenthesizedExpression(expression); + checkExpression(expression); + } + + private void checkExpression(PsiExpression expression) { + if (!isArithmetic(expression)) { + return; + } + if (isParentArithmetic(expression)) { + return; + } + final int numTerms = countTerms(expression); + if (numTerms <= getLimit()) { + return; + } + registerError(expression); + } + + private int countTerms(PsiExpression expression) { + if (!isArithmetic(expression)) { + return 1; + } + if (expression instanceof PsiBinaryExpression) { + final PsiBinaryExpression binaryExpression = (PsiBinaryExpression) expression; + final PsiExpression lhs = binaryExpression.getLOperand(); + final PsiExpression rhs = binaryExpression.getROperand(); + return countTerms(lhs) + countTerms(rhs); + } else if (expression instanceof PsiPrefixExpression) { + final PsiPrefixExpression prefixExpression = (PsiPrefixExpression) expression; + final PsiExpression operand = prefixExpression.getOperand(); + return countTerms(operand); + } else if (expression instanceof PsiParenthesizedExpression) { + final PsiParenthesizedExpression parenthesizedExpression = (PsiParenthesizedExpression) expression; + final PsiExpression contents = parenthesizedExpression.getExpression(); + return countTerms(contents); + } + return 1; + } + + private boolean isParentArithmetic(PsiExpression expression) { + final PsiElement parent = expression.getParent(); + if (!(parent instanceof PsiExpression)) { + return false; + } + return isArithmetic((PsiExpression) parent); + } + + private boolean isArithmetic(PsiExpression expression) { + if (expression instanceof PsiBinaryExpression) { + final PsiType type = expression.getType(); + if (TypeUtils.isJavaLangString(type)) { + return false; //ignore string concatenations + } + final PsiBinaryExpression binaryExpression = (PsiBinaryExpression) expression; + final PsiJavaToken sign = binaryExpression.getOperationSign(); + final IElementType tokenType = sign.getTokenType(); + return tokenType.equals(JavaTokenType.PLUS) || + tokenType.equals(JavaTokenType.MINUS) || + tokenType.equals(JavaTokenType.ASTERISK) || + tokenType.equals(JavaTokenType.DIV) || + tokenType.equals(JavaTokenType.PERC); + } else if (expression instanceof PsiPrefixExpression) { + final PsiPrefixExpression prefixExpression = (PsiPrefixExpression) expression; + final PsiJavaToken sign = prefixExpression.getOperationSign(); + final IElementType tokenType = sign.getTokenType(); + return tokenType.equals(JavaTokenType.PLUS) || + tokenType.equals(JavaTokenType.MINUS); + } else if (expression instanceof PsiParenthesizedExpression) { + final PsiParenthesizedExpression parenthesizedExpression = (PsiParenthesizedExpression) expression; + final PsiExpression contents = parenthesizedExpression.getExpression(); + return isArithmetic(contents); + } + return false; + } + } +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/confusing/OverlyComplexBooleanExpressionInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/confusing/OverlyComplexBooleanExpressionInspection.java new file mode 100644 index 000000000000..a23d41232ca3 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/confusing/OverlyComplexBooleanExpressionInspection.java @@ -0,0 +1,127 @@ +package com.siyeh.ig.confusing; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.psi.*; +import com.intellij.psi.tree.IElementType; +import com.siyeh.ig.BaseInspection; +import com.siyeh.ig.BaseInspectionVisitor; +import com.siyeh.ig.GroupNames; +import com.siyeh.ig.StatementInspection; +import com.siyeh.ig.ui.SingleIntegerFieldOptionsPanel; + +import javax.swing.*; + +public class OverlyComplexBooleanExpressionInspection extends StatementInspection { + private static final int TERM_LIMIT = 3; + + public int m_limit = TERM_LIMIT; //this is public for the DefaultJDOMExternalizer thingy + + public String getDisplayName() { + return "Overly complex boolean expression"; + } + + public String getGroupDisplayName() { + return GroupNames.CONFUSING_GROUP_NAME; + } + + private int getLimit() { + return m_limit; + } + + public JComponent createOptionsPanel() { + return new SingleIntegerFieldOptionsPanel("Maximum number of terms:", + this, "m_limit"); + } + + protected String buildErrorString(PsiElement location) { + return "Overly complex boolean expression #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new SwitchStatementWithTooManyBranchesVisitor(this, inspectionManager, onTheFly); + } + + private class SwitchStatementWithTooManyBranchesVisitor extends BaseInspectionVisitor { + private SwitchStatementWithTooManyBranchesVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitBinaryExpression(PsiBinaryExpression expression) { + super.visitBinaryExpression(expression); + checkExpression(expression); + } + + public void visitPrefixExpression(PsiPrefixExpression expression) { + super.visitPrefixExpression(expression); + checkExpression(expression); + } + + public void visitParenthesizedExpression(PsiParenthesizedExpression expression) { + super.visitParenthesizedExpression(expression); + checkExpression(expression); + } + + private void checkExpression(PsiExpression expression) { + if (!isBoolean(expression)) { + return; + } + if (isParentBoolean(expression)) { + return; + } + final int numTerms = countTerms(expression); + if (numTerms <= getLimit()) { + return; + } + registerError(expression); + } + + private int countTerms(PsiExpression expression) { + if (!isBoolean(expression)) { + return 1; + } + if (expression instanceof PsiBinaryExpression) { + final PsiBinaryExpression binaryExpression = (PsiBinaryExpression) expression; + final PsiExpression lhs = binaryExpression.getLOperand(); + final PsiExpression rhs = binaryExpression.getROperand(); + return countTerms(lhs) + countTerms(rhs); + } else if (expression instanceof PsiPrefixExpression) { + final PsiPrefixExpression prefixExpression = (PsiPrefixExpression) expression; + final PsiExpression operand = prefixExpression.getOperand(); + return countTerms(operand); + } else if (expression instanceof PsiParenthesizedExpression) { + final PsiParenthesizedExpression parenthesizedExpression = (PsiParenthesizedExpression) expression; + final PsiExpression contents = parenthesizedExpression.getExpression(); + return countTerms(contents); + } + return 1; + } + + private boolean isParentBoolean(PsiExpression expression) { + final PsiElement parent = expression.getParent(); + if (!(parent instanceof PsiExpression)) { + return false; + } + return isBoolean((PsiExpression) parent); + } + + private boolean isBoolean(PsiExpression expression) { + if (expression instanceof PsiBinaryExpression) { + final PsiBinaryExpression binaryExpression = (PsiBinaryExpression) expression; + final PsiJavaToken sign = binaryExpression.getOperationSign(); + final IElementType tokenType = sign.getTokenType(); + return tokenType.equals(JavaTokenType.ANDAND) || + tokenType.equals(JavaTokenType.OROR); + } else if (expression instanceof PsiPrefixExpression) { + final PsiPrefixExpression prefixExpression = (PsiPrefixExpression) expression; + final PsiJavaToken sign = prefixExpression.getOperationSign(); + final IElementType tokenType = sign.getTokenType(); + return tokenType.equals(JavaTokenType.EXCL); + } else if (expression instanceof PsiParenthesizedExpression) { + final PsiParenthesizedExpression parenthesizedExpression = (PsiParenthesizedExpression) expression; + final PsiExpression contents = parenthesizedExpression.getExpression(); + return isBoolean(contents); + } + return false; + } + } +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/confusing/RefusedBequestInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/confusing/RefusedBequestInspection.java new file mode 100644 index 000000000000..3632190628bc --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/confusing/RefusedBequestInspection.java @@ -0,0 +1,121 @@ +package com.siyeh.ig.confusing; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.psi.*; +import com.intellij.psi.util.PsiSuperMethodUtil; +import com.siyeh.ig.BaseInspection; +import com.siyeh.ig.BaseInspectionVisitor; +import com.siyeh.ig.GroupNames; +import com.siyeh.ig.MethodInspection; + +public class RefusedBequestInspection extends MethodInspection { + + public String getDisplayName() { + return "Refused bequest"; + } + + public String getGroupDisplayName() { + return GroupNames.CONFUSING_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "Method #ref ignores defined method in superclass #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new RefusedBequestVisitor(this, inspectionManager, onTheFly); + } + + private static class RefusedBequestVisitor extends BaseInspectionVisitor { + private RefusedBequestVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitMethod(PsiMethod method) { + super.visitMethod(method); + final PsiCodeBlock body = method.getBody(); + if (body == null) { + return; + } + PsiMethod leastConcreteSuperMethod = null; + final PsiMethod[] superMethods = PsiSuperMethodUtil.findSuperMethods(method, true); + for (int i = 0; i < superMethods.length; i++) { + final PsiMethod superMethod = superMethods[i]; + final PsiClass containingClass = superMethod.getContainingClass(); + if (!superMethod.hasModifierProperty(PsiModifier.ABSTRACT) && + !containingClass.isInterface()) { + leastConcreteSuperMethod = superMethod; + break; + } + } + if (leastConcreteSuperMethod == null) { + return; + } + final PsiClass containingClass = leastConcreteSuperMethod.getContainingClass(); + final String className = containingClass.getQualifiedName(); + if ("java.lang.Object".equals(className)) { + return; + } + if (containsSuperCall(body, leastConcreteSuperMethod)) { + return; + } + + registerMethodError(method); + } + } + + private static boolean containsSuperCall(PsiCodeBlock body, PsiMethod method) { + final SuperCallVisitor visitor = new SuperCallVisitor(method); + body.accept(visitor); + return visitor.hasSuperCall(); + } + + private static class SuperCallVisitor extends PsiRecursiveElementVisitor { + private PsiMethod methodToSearchFor; + private boolean hasSuperCall = false; + + SuperCallVisitor(PsiMethod methodToSearchFor) { + super(); + this.methodToSearchFor = methodToSearchFor; + } + + public void visitReferenceExpression(PsiReferenceExpression expression) { + final PsiExpression qualifier = expression.getQualifierExpression(); + if (qualifier != null) { + qualifier.accept(this); + } + final PsiReferenceParameterList typeParameters = expression.getParameterList(); + if (typeParameters != null) { + typeParameters.accept(this); + } + } + + public void visitMethodCallExpression(PsiMethodCallExpression expression) { + super.visitMethodCallExpression(expression); + final PsiReferenceExpression methodExpression = expression.getMethodExpression(); + if (methodExpression == null) { + return; + } + final PsiExpression qualifier = methodExpression.getQualifierExpression(); + if (qualifier == null) { + return; + } + final String text = qualifier.getText(); + if (!"super".equals(text)) { + return; + } + final PsiMethod method = expression.resolveMethod(); + if (method == null) { + return; + } + if (method.equals(methodToSearchFor)) { + hasSuperCall = true; + } + } + + public boolean hasSuperCall() { + return hasSuperCall; + } + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/confusing/SwitchStatementDensityInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/confusing/SwitchStatementDensityInspection.java new file mode 100644 index 000000000000..4a3131b6263b --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/confusing/SwitchStatementDensityInspection.java @@ -0,0 +1,103 @@ +package com.siyeh.ig.confusing; + +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; +import com.siyeh.ig.ui.SingleIntegerFieldOptionsPanel; + +import javax.swing.*; + +public class SwitchStatementDensityInspection extends StatementInspection { + private static final int DEFAULT_DENSITY_LIMIT = 20; + + public int m_limit = DEFAULT_DENSITY_LIMIT; //this is public for the DefaultJDOMExternalizer thingy + + public String getDisplayName() { + return "Switch statement with too low of branch density"; + } + + public String getGroupDisplayName() { + return GroupNames.CONFUSING_GROUP_NAME; + } + + private int getLimit() { + return m_limit; + } + + public JComponent createOptionsPanel() { + return new SingleIntegerFieldOptionsPanel("Minimum density of branches: %", + this, "m_limit"); + } + + protected String buildErrorString(PsiElement location) { + final PsiSwitchStatement statement = (PsiSwitchStatement) location.getParent(); + final double density = calculateDensity(statement); + final int intDensity = (int) (density * 100.0); + return "'#ref' has too low of branch density (" + intDensity + "%) #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new SwitchStatementWithTooFewBranchesVisitor(this, inspectionManager, onTheFly); + } + + private class SwitchStatementWithTooFewBranchesVisitor extends BaseInspectionVisitor { + private SwitchStatementWithTooFewBranchesVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitSwitchStatement(PsiSwitchStatement statement) { + final PsiCodeBlock body = statement.getBody(); + if (body == null) { + return; + } + final double density = calculateDensity(statement); + if (density * 100.0 > getLimit()) { + return; + } + registerStatementError(statement); + } + } + + private static double calculateDensity(PsiSwitchStatement statement) { + int branches = 0; + final PsiCodeBlock body = statement.getBody(); + final PsiStatement[] statements = body.getStatements(); + for (int i = 0; i < statements.length; i++) { + final PsiStatement child = statements[i]; + if (child instanceof PsiSwitchLabelStatement) { + branches++; + } + } + final StatementCountVisitor visitor = new StatementCountVisitor(); + body.accept(visitor); + final int numStatements = visitor.getNumStatements(); + return (double) branches / (double) numStatements; + } + + private static class StatementCountVisitor extends PsiRecursiveElementVisitor { + private int numStatements = 0; + + public void visitReferenceExpression(PsiReferenceExpression expression) { + final PsiExpression qualifier = expression.getQualifierExpression(); + if (qualifier != null) { + qualifier.accept(this); + } + final PsiReferenceParameterList typeParameters = expression.getParameterList(); + if (typeParameters != null) { + typeParameters.accept(this); + } + } + + public void visitStatement(PsiStatement psiStatement) { + super.visitStatement(psiStatement); + numStatements++; + } + + public int getNumStatements() { + return numStatements; + } + } +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/confusing/SwitchStatementWithConfusingDeclarationInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/confusing/SwitchStatementWithConfusingDeclarationInspection.java new file mode 100644 index 000000000000..e711c2eb8b18 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/confusing/SwitchStatementWithConfusingDeclarationInspection.java @@ -0,0 +1,76 @@ +package com.siyeh.ig.confusing; + +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; + +import java.util.HashSet; +import java.util.Iterator; +import java.util.Set; + +public class SwitchStatementWithConfusingDeclarationInspection extends StatementInspection { + public String getDisplayName() { + return "Local variable used and declared in different 'switch' branches"; + } + + public String getGroupDisplayName() { + return GroupNames.CONFUSING_GROUP_NAME; + } + + protected String buildErrorString(PsiElement location) { + return "Local variable #ref declared in one switch branch and used in another #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new SwitchStatementWithConfusingDeclarationVisitor(this, inspectionManager, onTheFly); + } + + private static class SwitchStatementWithConfusingDeclarationVisitor extends BaseInspectionVisitor { + private SwitchStatementWithConfusingDeclarationVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitSwitchStatement(PsiSwitchStatement statement) { + final Set variablesInCurrentBranch = new HashSet(10); + final Set variablesInPreviousBranches = new HashSet(10); + final PsiCodeBlock body = statement.getBody(); + if (body == null) { + return; + } + final PsiStatement[] statements = body.getStatements(); + for (int i = 0; i < statements.length; i++) { + final PsiStatement child = statements[i]; + if (child instanceof PsiDeclarationStatement) { + final PsiDeclarationStatement declaration = (PsiDeclarationStatement) child; + final PsiElement[] declaredElements = declaration.getDeclaredElements(); + for (int j = 0; j < declaredElements.length; j++) { + final PsiElement declaredElement = declaredElements[j]; + if (declaredElement instanceof PsiLocalVariable) { + final PsiLocalVariable localVar = (PsiLocalVariable) declaredElement; + variablesInCurrentBranch.add(localVar); + } + } + } + if (child instanceof PsiBreakStatement) { + variablesInPreviousBranches.addAll(variablesInCurrentBranch); + variablesInCurrentBranch.clear(); + } + final LocalVariableAccessVisitor visitor = new LocalVariableAccessVisitor(); + child.accept(visitor); + final Set accessedVariables = visitor.getAccessedVariables(); + for (Iterator iterator = accessedVariables.iterator(); iterator.hasNext();) { + final PsiLocalVariable localVar = (PsiLocalVariable) iterator.next(); + if (variablesInPreviousBranches.contains(localVar)) { + variablesInPreviousBranches.remove(localVar); + registerVariableError(localVar); + } + } + + } + } + + } +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/confusing/SwitchStatementWithTooFewBranchesInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/confusing/SwitchStatementWithTooFewBranchesInspection.java new file mode 100644 index 000000000000..a5d9dce74cac --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/confusing/SwitchStatementWithTooFewBranchesInspection.java @@ -0,0 +1,78 @@ +package com.siyeh.ig.confusing; + +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; +import com.siyeh.ig.ui.SingleIntegerFieldOptionsPanel; + +import javax.swing.*; + +public class SwitchStatementWithTooFewBranchesInspection extends StatementInspection { + private static final int DEFAULT_BRANCH_LIMIT = 2; + + public int m_limit = DEFAULT_BRANCH_LIMIT; //this is public for the DefaultJDOMExternalizer thingy + + public String getDisplayName() { + return "Switch statement with too few branches"; + } + + public String getGroupDisplayName() { + return GroupNames.CONFUSING_GROUP_NAME; + } + + private int getLimit() { + return m_limit; + } + + public JComponent createOptionsPanel() { + return new SingleIntegerFieldOptionsPanel("Minimum number of branches:", + this, "m_limit"); + } + + protected String buildErrorString(PsiElement location) { + int branches = 0; + final PsiSwitchStatement statement = (PsiSwitchStatement) location.getParent(); + final PsiCodeBlock body = statement.getBody(); + final PsiStatement[] statements = body.getStatements(); + for (int i = 0; i < statements.length; i++) { + final PsiStatement child = statements[i]; + if (child instanceof PsiSwitchLabelStatement) { + branches++; + } + } + return "'#ref' has too few branches (" + branches + "), and should probably be replaced by an 'if' statement #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new SwitchStatementWithTooFewBranchesVisitor(this, inspectionManager, onTheFly); + } + + private class SwitchStatementWithTooFewBranchesVisitor extends BaseInspectionVisitor { + private SwitchStatementWithTooFewBranchesVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitSwitchStatement(PsiSwitchStatement statement) { + int branches = 0; + final PsiCodeBlock body = statement.getBody(); + if (body == null) { + return; + } + final PsiStatement[] statements = body.getStatements(); + for (int i = 0; i < statements.length; i++) { + final PsiStatement child = statements[i]; + if (child instanceof PsiSwitchLabelStatement) { + branches++; + } + } + if (branches >= getLimit()) { + return; + } + registerStatementError(statement); + } + + } +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/confusing/SwitchStatementWithTooManyBranchesInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/confusing/SwitchStatementWithTooManyBranchesInspection.java new file mode 100644 index 000000000000..c9c453418271 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/confusing/SwitchStatementWithTooManyBranchesInspection.java @@ -0,0 +1,78 @@ +package com.siyeh.ig.confusing; + +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; +import com.siyeh.ig.ui.SingleIntegerFieldOptionsPanel; + +import javax.swing.*; + +public class SwitchStatementWithTooManyBranchesInspection extends StatementInspection { + private static final int DEFAULT_BRANCH_LIMIT = 10; + + public int m_limit = DEFAULT_BRANCH_LIMIT; //this is public for the DefaultJDOMExternalizer thingy + + public String getDisplayName() { + return "Switch statement with too many branches"; + } + + public String getGroupDisplayName() { + return GroupNames.CONFUSING_GROUP_NAME; + } + + private int getLimit() { + return m_limit; + } + + public JComponent createOptionsPanel() { + return new SingleIntegerFieldOptionsPanel("Maximum number of branches:", + this, "m_limit"); + } + + protected String buildErrorString(PsiElement location) { + int branches = 0; + final PsiSwitchStatement statement = (PsiSwitchStatement) location.getParent(); + final PsiCodeBlock body = statement.getBody(); + final PsiStatement[] statements = body.getStatements(); + for (int i = 0; i < statements.length; i++) { + final PsiStatement child = statements[i]; + if (child instanceof PsiSwitchLabelStatement) { + branches++; + } + } + return "'#ref' has too many branches (" + branches + ") #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new SwitchStatementWithTooManyBranchesVisitor(this, inspectionManager, onTheFly); + } + + private class SwitchStatementWithTooManyBranchesVisitor extends BaseInspectionVisitor { + private SwitchStatementWithTooManyBranchesVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitSwitchStatement(PsiSwitchStatement statement) { + int branches = 0; + final PsiCodeBlock body = statement.getBody(); + if (body == null) { + return; + } + final PsiStatement[] statements = body.getStatements(); + for (int i = 0; i < statements.length; i++) { + final PsiStatement child = statements[i]; + if (child instanceof PsiSwitchLabelStatement) { + branches++; + } + } + if (branches <= getLimit()) { + return; + } + registerStatementError(statement); + } + + } +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/encapsulation/AssignmentToCollectionFieldFromParameterInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/encapsulation/AssignmentToCollectionFieldFromParameterInspection.java new file mode 100644 index 000000000000..fbc0d04b3147 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/encapsulation/AssignmentToCollectionFieldFromParameterInspection.java @@ -0,0 +1,80 @@ +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; +import com.siyeh.ig.psiutils.CollectionUtils; + +public class AssignmentToCollectionFieldFromParameterInspection extends ExpressionInspection { + + public String getDisplayName() { + return "Assignment to Collection or array field from parameter"; + } + + public String getGroupDisplayName() { + return GroupNames.ENCAPSULATION_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + final PsiAssignmentExpression assignment = (PsiAssignmentExpression) location.getParent(); + final PsiExpression lhs = assignment.getLExpression(); + final PsiExpression rhs = assignment.getRExpression(); + final PsiElement element = ((PsiReference) lhs).resolve(); + + final PsiField field = (PsiField) element; + final PsiType type = field.getType(); + if (type.getArrayDimensions() > 0) { + return "assignment to array field #ref from parameter " + rhs.getText() + "#loc"; + } else { + return "assignment to Collection field #ref from parameter " + rhs.getText() + "#loc"; + } + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new AssignmentToCollectionFieldFromParameterVisitor(this, inspectionManager, onTheFly); + } + + private static class AssignmentToCollectionFieldFromParameterVisitor extends BaseInspectionVisitor { + private AssignmentToCollectionFieldFromParameterVisitor(BaseInspection inspection, + InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitAssignmentExpression(PsiAssignmentExpression expression) { + super.visitAssignmentExpression(expression); + final PsiJavaToken sign = expression.getOperationSign(); + if (sign == null) { + return; + } + if (sign.getTokenType() != JavaTokenType.EQ) { + return; + } + final PsiExpression lhs = expression.getLExpression(); + if (lhs == null) { + return; + } + if (!CollectionUtils.isArrayOrCollectionField(lhs)) { + return; + } + final PsiExpression rhs = expression.getRExpression(); + if (rhs == null) { + return; + } + if (!(rhs instanceof PsiReferenceExpression)) { + return; + } + final PsiElement element = ((PsiReference) rhs).resolve(); + if (!(element instanceof PsiParameter)) { + return; + } + if (!(element.getParent() instanceof PsiParameterList)) { + return; + } + registerError(lhs); + } + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/encapsulation/AssignmentToDateFieldFromParameterInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/encapsulation/AssignmentToDateFieldFromParameterInspection.java new file mode 100644 index 000000000000..0d27c5005bc0 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/encapsulation/AssignmentToDateFieldFromParameterInspection.java @@ -0,0 +1,77 @@ +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; +import com.siyeh.ig.psiutils.TypeUtils; + +public class AssignmentToDateFieldFromParameterInspection extends ExpressionInspection { + + public String getDisplayName() { + return "Assignment to Date or Calendar field from parameter"; + } + + public String getGroupDisplayName() { + return GroupNames.ENCAPSULATION_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + final PsiAssignmentExpression assignment = (PsiAssignmentExpression) location.getParent(); + final PsiExpression lhs = assignment.getLExpression(); + final PsiExpression rhs = assignment.getRExpression(); + final PsiElement element = ((PsiReference) lhs).resolve(); + + final PsiField field = (PsiField) element; + final PsiType type = field.getType(); + return "assignment to " + type.getPresentableText() + " field #ref from parameter " + rhs.getText() + "#loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new AssignmentToDateFieldFromParameterVisitor(this, inspectionManager, onTheFly); + } + + private static class AssignmentToDateFieldFromParameterVisitor extends BaseInspectionVisitor { + private AssignmentToDateFieldFromParameterVisitor(BaseInspection inspection, + InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitAssignmentExpression(PsiAssignmentExpression expression) { + super.visitAssignmentExpression(expression); + final PsiJavaToken sign = expression.getOperationSign(); + if (sign == null) { + return; + } + if (sign.getTokenType() != JavaTokenType.EQ) { + return; + } + final PsiExpression lhs = expression.getLExpression(); + if (lhs == null) { + return; + } + if (!TypeUtils.expressionHasTypeOrSubtype("java.util.Date", lhs) + && !TypeUtils.expressionHasTypeOrSubtype("java.util.Calendar", lhs)) { + return; + } + final PsiExpression rhs = expression.getRExpression(); + if (rhs == null) { + return; + } + if (!(rhs instanceof PsiReferenceExpression)) { + return; + } + final PsiElement element = ((PsiReference) rhs).resolve(); + if (!(element instanceof PsiParameter)) { + return; + } + if (!(element.getParent() instanceof PsiParameterList)) { + return; + } + registerError(lhs); + } + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/encapsulation/PackageVisibleFieldInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/encapsulation/PackageVisibleFieldInspection.java new file mode 100644 index 000000000000..f8d61e63dc99 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/encapsulation/PackageVisibleFieldInspection.java @@ -0,0 +1,57 @@ +package com.siyeh.ig.encapsulation; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiField; +import com.intellij.psi.PsiModifier; +import com.siyeh.ig.*; +import com.siyeh.ig.fixes.EncapsulateVariableFix; + +public class PackageVisibleFieldInspection extends ClassInspection { + private final EncapsulateVariableFix fix = new EncapsulateVariableFix(); + + public String getDisplayName() { + return "Package-visible field"; + } + + public String getGroupDisplayName() { + return GroupNames.ENCAPSULATION_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "Package-visible field #ref #loc"; + } + + protected InspectionGadgetsFix buildFix(PsiElement location) { + return fix; + } + + protected boolean buildQuickFixesOnlyForOnTheFlyErrors() { + return true; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new ProtectedFieldVisitor(this, inspectionManager, onTheFly); + } + + private static class ProtectedFieldVisitor extends BaseInspectionVisitor { + private ProtectedFieldVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitField(PsiField field) { + if (field.hasModifierProperty(PsiModifier.PROTECTED) || + field.hasModifierProperty(PsiModifier.PUBLIC) || + field.hasModifierProperty(PsiModifier.PRIVATE)) { + return; + } + if (field.hasModifierProperty(PsiModifier.STATIC) && + field.hasModifierProperty(PsiModifier.FINAL)) { + return; + } + registerFieldError(field); + } + + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/encapsulation/PackageVisibleInnerClassInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/encapsulation/PackageVisibleInnerClassInspection.java new file mode 100644 index 000000000000..51064b4204cc --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/encapsulation/PackageVisibleInnerClassInspection.java @@ -0,0 +1,57 @@ +package com.siyeh.ig.encapsulation; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.psi.PsiClass; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiModifier; +import com.siyeh.ig.*; +import com.siyeh.ig.fixes.MoveClassFix; +import com.siyeh.ig.psiutils.ClassUtils; + +public class PackageVisibleInnerClassInspection extends ClassInspection { + private final MoveClassFix fix = new MoveClassFix(); + + public String getDisplayName() { + return "Package-visible inner class"; + } + + public String getGroupDisplayName() { + return GroupNames.ENCAPSULATION_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "Package-visible inner class #ref #loc"; + } + + protected InspectionGadgetsFix buildFix(PsiElement location) { + return fix; + } + + protected boolean buildQuickFixesOnlyForOnTheFlyErrors() { + return true; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new PackageVisibleInnerClassVisitor(this, inspectionManager, onTheFly); + } + + private static class PackageVisibleInnerClassVisitor extends BaseInspectionVisitor { + private PackageVisibleInnerClassVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitClass(PsiClass aClass) { + if (aClass.hasModifierProperty(PsiModifier.PUBLIC) || + aClass.hasModifierProperty(PsiModifier.PROTECTED) || + aClass.hasModifierProperty(PsiModifier.PRIVATE)) { + return; + } + if (!ClassUtils.isInnerClass(aClass)) { + return; + } + registerClassError(aClass); + } + + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/encapsulation/ProtectedFieldInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/encapsulation/ProtectedFieldInspection.java new file mode 100644 index 000000000000..fa9525f3a1c7 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/encapsulation/ProtectedFieldInspection.java @@ -0,0 +1,55 @@ +package com.siyeh.ig.encapsulation; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiField; +import com.intellij.psi.PsiModifier; +import com.siyeh.ig.*; +import com.siyeh.ig.fixes.EncapsulateVariableFix; + +public class ProtectedFieldInspection extends FieldInspection { + private final EncapsulateVariableFix fix = new EncapsulateVariableFix(); + + public String getDisplayName() { + return "Protected field"; + } + + public String getGroupDisplayName() { + return GroupNames.ENCAPSULATION_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "Protected field #ref #loc"; + } + + protected InspectionGadgetsFix buildFix(PsiElement location) { + return fix; + } + + protected boolean buildQuickFixesOnlyForOnTheFlyErrors() { + return true; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new ProtectedFieldVisitor(this, inspectionManager, onTheFly); + } + + private static class ProtectedFieldVisitor extends BaseInspectionVisitor { + private ProtectedFieldVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitField(PsiField field) { + if (!field.hasModifierProperty(PsiModifier.PROTECTED)) { + return; + } + if (field.hasModifierProperty(PsiModifier.STATIC) && + field.hasModifierProperty(PsiModifier.FINAL)) { + return; + } + registerFieldError(field); + } + + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/encapsulation/ProtectedInnerClassInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/encapsulation/ProtectedInnerClassInspection.java new file mode 100644 index 000000000000..15e2ef1bb111 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/encapsulation/ProtectedInnerClassInspection.java @@ -0,0 +1,55 @@ +package com.siyeh.ig.encapsulation; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.psi.PsiClass; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiModifier; +import com.siyeh.ig.*; +import com.siyeh.ig.fixes.MoveClassFix; +import com.siyeh.ig.psiutils.ClassUtils; + +public class ProtectedInnerClassInspection extends ClassInspection { + private final MoveClassFix fix = new MoveClassFix(); + + public String getDisplayName() { + return "Protected inner class"; + } + + public String getGroupDisplayName() { + return GroupNames.ENCAPSULATION_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "Protected inner class #ref #loc"; + } + + protected InspectionGadgetsFix buildFix(PsiElement location) { + return fix; + } + + protected boolean buildQuickFixesOnlyForOnTheFlyErrors() { + return true; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new PackageVisibleInnerClassVisitor(this, inspectionManager, onTheFly); + } + + private static class PackageVisibleInnerClassVisitor extends BaseInspectionVisitor { + private PackageVisibleInnerClassVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitClass(PsiClass aClass) { + if (!aClass.hasModifierProperty(PsiModifier.PROTECTED)) { + return; + } + if (!ClassUtils.isInnerClass(aClass)) { + return; + } + registerClassError(aClass); + } + + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/encapsulation/PublicFieldInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/encapsulation/PublicFieldInspection.java new file mode 100644 index 000000000000..9ad04a9426a3 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/encapsulation/PublicFieldInspection.java @@ -0,0 +1,55 @@ +package com.siyeh.ig.encapsulation; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiField; +import com.intellij.psi.PsiModifier; +import com.siyeh.ig.*; +import com.siyeh.ig.fixes.EncapsulateVariableFix; + +public class PublicFieldInspection extends FieldInspection { + private final EncapsulateVariableFix fix = new EncapsulateVariableFix(); + + public String getDisplayName() { + return "Public field"; + } + + public String getGroupDisplayName() { + return GroupNames.ENCAPSULATION_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "Public field #ref #loc"; + } + + protected InspectionGadgetsFix buildFix(PsiElement location) { + return fix; + } + + protected boolean buildQuickFixesOnlyForOnTheFlyErrors() { + return true; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new PublicFieldVisitor(this, inspectionManager, onTheFly); + } + + private static class PublicFieldVisitor extends BaseInspectionVisitor { + private PublicFieldVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitField(PsiField field) { + if (!field.hasModifierProperty(PsiModifier.PUBLIC)) { + return; + } + if (field.hasModifierProperty(PsiModifier.STATIC) && + field.hasModifierProperty(PsiModifier.FINAL)) { + return; + } + registerFieldError(field); + } + + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/encapsulation/PublicInnerClassInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/encapsulation/PublicInnerClassInspection.java new file mode 100644 index 000000000000..352a9b2c64a7 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/encapsulation/PublicInnerClassInspection.java @@ -0,0 +1,55 @@ +package com.siyeh.ig.encapsulation; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.psi.PsiClass; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiModifier; +import com.siyeh.ig.*; +import com.siyeh.ig.fixes.MoveClassFix; +import com.siyeh.ig.psiutils.ClassUtils; + +public class PublicInnerClassInspection extends ClassInspection { + private final MoveClassFix fix = new MoveClassFix(); + + public String getDisplayName() { + return "Public inner class"; + } + + public String getGroupDisplayName() { + return GroupNames.ENCAPSULATION_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "Public inner class #ref #loc"; + } + + protected InspectionGadgetsFix buildFix(PsiElement location) { + return fix; + } + + protected boolean buildQuickFixesOnlyForOnTheFlyErrors() { + return true; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new PublicInnerClassVisitor(this, inspectionManager, onTheFly); + } + + private static class PublicInnerClassVisitor extends BaseInspectionVisitor { + private PublicInnerClassVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitClass(PsiClass aClass) { + if (!aClass.hasModifierProperty(PsiModifier.PUBLIC)) { + return; + } + if (!ClassUtils.isInnerClass(aClass)) { + return; + } + registerClassError(aClass); + } + + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/encapsulation/ReturnOfCollectionFieldInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/encapsulation/ReturnOfCollectionFieldInspection.java new file mode 100644 index 000000000000..c41044c55b02 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/encapsulation/ReturnOfCollectionFieldInspection.java @@ -0,0 +1,54 @@ +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; +import com.siyeh.ig.psiutils.CollectionUtils; + +public class ReturnOfCollectionFieldInspection extends ExpressionInspection { + + public String getDisplayName() { + return "Return of Collection or array field"; + } + + public String getGroupDisplayName() { + return GroupNames.ENCAPSULATION_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + final PsiField field = (PsiField) ((PsiReference) location).resolve(); + final PsiType type = field.getType(); + if (type.getArrayDimensions() > 0) { + return "'return' of array field #ref #loc"; + } else { + return "'return' of Collection field #ref #loc"; + } + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new ReturnOfCollectionFieldVisitor(this, inspectionManager, onTheFly); + } + + private static class ReturnOfCollectionFieldVisitor extends BaseInspectionVisitor { + private ReturnOfCollectionFieldVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitReturnStatement(PsiReturnStatement statement) { + super.visitReturnStatement(statement); + final PsiExpression returnValue = statement.getReturnValue(); + if (returnValue == null) { + return; + } + if (!CollectionUtils.isArrayOrCollectionField(returnValue)) { + return; + } + registerError(returnValue); + } + + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/encapsulation/ReturnOfDateFieldInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/encapsulation/ReturnOfDateFieldInspection.java new file mode 100644 index 000000000000..b59ce345ee8b --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/encapsulation/ReturnOfDateFieldInspection.java @@ -0,0 +1,60 @@ +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; +import com.siyeh.ig.psiutils.TypeUtils; + +public class ReturnOfDateFieldInspection extends ExpressionInspection { + + public String getDisplayName() { + return "Return of Date or Calendar field"; + } + + public String getGroupDisplayName() { + return GroupNames.ENCAPSULATION_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + final PsiField field = (PsiField) ((PsiReference) location).resolve(); + final PsiType type = field.getType(); + return "'return' of " + type.getPresentableText() + " field #ref #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new ReturnOfDateFieldVisitor(this, inspectionManager, onTheFly); + } + + private static class ReturnOfDateFieldVisitor extends BaseInspectionVisitor { + private ReturnOfDateFieldVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitReturnStatement(PsiReturnStatement statement) { + super.visitReturnStatement(statement); + final PsiExpression returnValue = statement.getReturnValue(); + if (returnValue == null) { + return; + } + if (!(returnValue instanceof PsiReferenceExpression)) { + return ; + } + final PsiReferenceExpression fieldReference = (PsiReferenceExpression) returnValue; + + final PsiElement element = fieldReference.resolve(); + if (!(element instanceof PsiField)) { + return; + } + if (!TypeUtils.expressionHasTypeOrSubtype("java.util.Date", returnValue) + && !TypeUtils.expressionHasTypeOrSubtype("java.util.Calendar", returnValue)) { + return; + } + registerError(returnValue); + } + + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/errorhandling/CatchGenericClassInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/errorhandling/CatchGenericClassInspection.java new file mode 100644 index 000000000000..8f0dd728caac --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/errorhandling/CatchGenericClassInspection.java @@ -0,0 +1,69 @@ +package com.siyeh.ig.errorhandling; + +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; +import com.siyeh.ig.psiutils.ExceptionUtils; + +import java.util.Set; + +public class CatchGenericClassInspection extends StatementInspection { + + public String getDisplayName() { + return "'catch' generic class"; + } + + public String getGroupDisplayName() { + return GroupNames.ERRORHANDLING_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "catch of generic #ref class should be replaced by more precise exception #loc"; + } + + protected BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new CatchGenericClassVisitor(this, inspectionManager, onTheFly); + } + + private static class CatchGenericClassVisitor extends BaseInspectionVisitor { + private CatchGenericClassVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitTryStatement(PsiTryStatement statement) { + super.visitTryStatement(statement); + final PsiCodeBlock tryBlock = statement.getTryBlock(); + if (tryBlock == null) { + return; + } + final PsiManager manager = statement.getManager(); + final PsiElementFactory factory = manager.getElementFactory(); + + final Set exceptionsThrown = + ExceptionUtils.calculateExceptionsThrown(tryBlock, factory); + final PsiParameter[] parameters = statement.getCatchBlockParameters(); + for (int i = 0; i < parameters.length; i++) { + final PsiParameter parameter = parameters[i]; + checkParameter(parameter, exceptionsThrown); + } + } + + private void checkParameter(PsiParameter parameter, Set exceptionsThrown) { + final PsiType type = parameter.getType(); + if (type == null) { + return; + } + if (!ExceptionUtils.isGenericExceptionClass(type)) { + return; + } + if (exceptionsThrown.contains(type)) { + return; + } + final PsiTypeElement typeElement = parameter.getTypeElement(); + registerError(typeElement); + } + } +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/errorhandling/CatchParameterUsedVisitor.java b/plugins/InspectionGadgets/src/com/siyeh/ig/errorhandling/CatchParameterUsedVisitor.java new file mode 100644 index 000000000000..3147a4ab3335 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/errorhandling/CatchParameterUsedVisitor.java @@ -0,0 +1,32 @@ +package com.siyeh.ig.errorhandling; + +import com.intellij.psi.*; + +public class CatchParameterUsedVisitor extends PsiRecursiveElementVisitor { + private final PsiParameter m_parameter; + private boolean m_used = false; + + public CatchParameterUsedVisitor(PsiParameter variable) { + super(); + m_parameter = variable; + } + + public void visitReferenceExpression(PsiReferenceExpression reference) { + final PsiExpression qualifier = reference.getQualifierExpression(); + if (qualifier != null) { + qualifier.accept(this); + } + final PsiReferenceParameterList typeParameters = reference.getParameterList(); + if (typeParameters != null) { + typeParameters.accept(this); + } + final PsiElement element = reference.resolve(); + if (m_parameter.equals(element)) { + m_used = true; + } + } + + public boolean isUsed() { + return m_used; + } +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/errorhandling/CheckedExceptionClassInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/errorhandling/CheckedExceptionClassInspection.java new file mode 100644 index 000000000000..803c73e69849 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/errorhandling/CheckedExceptionClassInspection.java @@ -0,0 +1,47 @@ +package com.siyeh.ig.errorhandling; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.psi.PsiClass; +import com.intellij.psi.PsiElement; +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 CheckedExceptionClassInspection extends ClassInspection { + + public String getDisplayName() { + return "Checked exception class"; + } + + public String getGroupDisplayName() { + return GroupNames.ERRORHANDLING_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "Checked exception class #ref #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new CheckedExceptionClassVisitor(this, inspectionManager, onTheFly); + } + + private static class CheckedExceptionClassVisitor extends BaseInspectionVisitor { + private CheckedExceptionClassVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitClass(PsiClass aClass) { + if (!ClassUtils.isSubclass(aClass, "java.lang.Throwable")) { + return; + } + if (ClassUtils.isSubclass(aClass, "java.lang.RuntimeException")) { + return; + } + registerClassError(aClass); + } + + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/errorhandling/ContinueOrBreakFromFinallyBlockInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/errorhandling/ContinueOrBreakFromFinallyBlockInspection.java new file mode 100644 index 000000000000..10f2f0a6bca3 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/errorhandling/ContinueOrBreakFromFinallyBlockInspection.java @@ -0,0 +1,62 @@ +package com.siyeh.ig.errorhandling; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.psi.PsiBreakStatement; +import com.intellij.psi.PsiContinueStatement; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiStatement; +import com.siyeh.ig.BaseInspection; +import com.siyeh.ig.BaseInspectionVisitor; +import com.siyeh.ig.GroupNames; +import com.siyeh.ig.StatementInspection; +import com.siyeh.ig.psiutils.ControlFlowUtils; + +public class ContinueOrBreakFromFinallyBlockInspection extends StatementInspection { + + public String getDisplayName() { + return "'continue' or 'break' inside 'finally' block"; + } + + public String getGroupDisplayName() { + return GroupNames.ERRORHANDLING_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "'#ref' inside 'finally' block #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new ContinueOrBreakFromFinallyBlockVisitor(this, inspectionManager, onTheFly); + } + + private static class ContinueOrBreakFromFinallyBlockVisitor extends BaseInspectionVisitor { + private ContinueOrBreakFromFinallyBlockVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitContinueStatement(PsiContinueStatement statement) { + super.visitContinueStatement(statement); + if (!ControlFlowUtils.isInFinallyBlock(statement)) { + return; + } + final PsiStatement continuedStatement = statement.findContinuedStatement(); + if (ControlFlowUtils.isInFinallyBlock(continuedStatement)) { + return; + } + registerStatementError(statement); + } + + public void visitBreakStatement(PsiBreakStatement statement) { + super.visitBreakStatement(statement); + if (!ControlFlowUtils.isInFinallyBlock(statement)) { + return; + } + final PsiStatement exitedStatement = statement.findExitedStatement(); + if (ControlFlowUtils.isInFinallyBlock(exitedStatement)) { + return; + } + registerStatementError(statement); + } + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/errorhandling/EmptyCatchBlockInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/errorhandling/EmptyCatchBlockInspection.java new file mode 100644 index 000000000000..d12b90e56636 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/errorhandling/EmptyCatchBlockInspection.java @@ -0,0 +1,125 @@ +package com.siyeh.ig.errorhandling; + +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; +import com.siyeh.ig.psiutils.ClassUtils; + +import javax.swing.*; +import javax.swing.event.ChangeEvent; +import javax.swing.event.ChangeListener; +import java.awt.*; + +public class EmptyCatchBlockInspection extends StatementInspection { + public boolean m_includeComments = false; + public boolean m_ignoreTestCases = false; + + public String getDisplayName() { + return "Empty 'catch' block"; + } + + public String getGroupDisplayName() { + return GroupNames.ERRORHANDLING_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "Empty #ref block #loc"; + } + + public JComponent createOptionsPanel() { + final GridBagLayout layout = new GridBagLayout(); + final JPanel panel = new JPanel(layout); + final JCheckBox commentsCheckBox = new JCheckBox("Comments count as content", m_includeComments); + final ButtonModel commentsModel = commentsCheckBox.getModel(); + commentsModel.addChangeListener(new ChangeListener() { + + public void stateChanged(ChangeEvent e) { + m_includeComments = commentsModel.isSelected(); + } + }); + final JCheckBox testCaseCheckBox = new JCheckBox("Ignore empty catch blocks in JUnit test cases", m_ignoreTestCases); + final ButtonModel model = testCaseCheckBox.getModel(); + model.addChangeListener(new ChangeListener() { + + public void stateChanged(ChangeEvent e) { + m_ignoreTestCases = model.isSelected(); + } + }); + final GridBagConstraints constraints = new GridBagConstraints(); + constraints.gridx = 0; + constraints.gridy = 0; + constraints.fill = GridBagConstraints.HORIZONTAL; + panel.add(commentsCheckBox, constraints); + + constraints.gridx = 0; + constraints.gridy = 1; + panel.add(testCaseCheckBox, constraints); + return panel; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new EmptyCatchBlockVisitor(this, inspectionManager, onTheFly); + } + + private class EmptyCatchBlockVisitor extends BaseInspectionVisitor { + private EmptyCatchBlockVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitTryStatement(PsiTryStatement statement) { + super.visitTryStatement(statement); + if (m_ignoreTestCases) { + final PsiClass aClass = + ClassUtils.getContainingClass(statement); + if (aClass != null && + ClassUtils.isSubclass(aClass, "junit.framework.TestCase")) { + return; + } + } + + final PsiCodeBlock[] catchBlocks = statement.getCatchBlocks(); + for (int i = 0; i < catchBlocks.length; i++) { + final PsiCodeBlock block = catchBlocks[i]; + if (catchBlockIsEmpty(block)) { + final PsiElement catchToken = getCatchToken(statement, i); + registerError(catchToken); + } + } + } + + private PsiElement getCatchToken(PsiTryStatement statement, int i) { + final PsiElement[] children = statement.getChildren(); + int catchNumber = 0; + for (int j = 0; j < children.length; j++) { + final PsiElement child = children[j]; + final String childText = child.getText(); + if ("catch".equals(childText)) { + if (catchNumber == i) { + return child; + } + catchNumber++; + } + } + return null; + } + + private boolean catchBlockIsEmpty(PsiCodeBlock block) { + if (m_includeComments) { + final PsiElement[] children = block.getChildren(); + for (int i = 0; i < children.length; i++) { + final PsiElement child = children[i]; + if (child instanceof PsiComment || child instanceof PsiStatement) { + return false; + } + } + return true; + } else { + return block.getStatements().length == 0; + } + } + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/errorhandling/EmptyFinallyBlockInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/errorhandling/EmptyFinallyBlockInspection.java new file mode 100644 index 000000000000..00908ad47274 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/errorhandling/EmptyFinallyBlockInspection.java @@ -0,0 +1,56 @@ +package com.siyeh.ig.errorhandling; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.psi.PsiCodeBlock; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiTryStatement; +import com.siyeh.ig.BaseInspection; +import com.siyeh.ig.BaseInspectionVisitor; +import com.siyeh.ig.GroupNames; +import com.siyeh.ig.StatementInspection; + +public class EmptyFinallyBlockInspection extends StatementInspection { + + public String getDisplayName() { + return "Empty 'finally' block"; + } + + public String getGroupDisplayName() { + return GroupNames.ERRORHANDLING_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "Empty #ref block #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new EmptyFinallyBlockVisitor(this, inspectionManager, onTheFly); + } + + private static class EmptyFinallyBlockVisitor extends BaseInspectionVisitor { + private EmptyFinallyBlockVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitTryStatement(PsiTryStatement statement) { + super.visitTryStatement(statement); + final PsiCodeBlock finallyBlock = statement.getFinallyBlock(); + if (finallyBlock == null) { + return; + } + if (finallyBlock.getStatements().length != 0) { + return; + } + final PsiElement[] children = statement.getChildren(); + for (int j = 0; j < children.length; j++) { + final PsiElement child = children[j]; + final String childText = child.getText(); + if ("finally".equals(childText)) { + registerError(child); + return; + } + } + } + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/errorhandling/EmptyTryBlockInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/errorhandling/EmptyTryBlockInspection.java new file mode 100644 index 000000000000..7e12eaf85f45 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/errorhandling/EmptyTryBlockInspection.java @@ -0,0 +1,48 @@ +package com.siyeh.ig.errorhandling; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.psi.PsiCodeBlock; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiTryStatement; +import com.siyeh.ig.BaseInspection; +import com.siyeh.ig.BaseInspectionVisitor; +import com.siyeh.ig.GroupNames; +import com.siyeh.ig.StatementInspection; + +public class EmptyTryBlockInspection extends StatementInspection { + + public String getDisplayName() { + return "Empty 'try' block"; + } + + public String getGroupDisplayName() { + return GroupNames.ERRORHANDLING_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "Empty #ref block #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new EmptyFinallyBlockVisitor(this, inspectionManager, onTheFly); + } + + private static class EmptyFinallyBlockVisitor extends BaseInspectionVisitor { + private EmptyFinallyBlockVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitTryStatement(PsiTryStatement statement) { + super.visitTryStatement(statement); + final PsiCodeBlock finallyBlock = statement.getTryBlock(); + if (finallyBlock == null) { + return; + } + if (finallyBlock.getStatements().length != 0) { + return; + } + registerStatementError(statement); + } + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/errorhandling/ErrorRethrownInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/errorhandling/ErrorRethrownInspection.java new file mode 100644 index 000000000000..ea03ce2f6ac6 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/errorhandling/ErrorRethrownInspection.java @@ -0,0 +1,91 @@ +package com.siyeh.ig.errorhandling; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.psi.*; +import com.intellij.psi.util.PsiUtil; +import com.siyeh.ig.BaseInspection; +import com.siyeh.ig.BaseInspectionVisitor; +import com.siyeh.ig.GroupNames; +import com.siyeh.ig.StatementInspection; +import com.siyeh.ig.psiutils.ClassUtils; +import com.siyeh.ig.psiutils.TypeUtils; + +public class ErrorRethrownInspection extends StatementInspection { + + public String getDisplayName() { + return "Error not rethrown"; + } + + public String getGroupDisplayName() { + return GroupNames.ERRORHANDLING_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "Error #ref not rethrown #loc"; + } + + protected BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new ErrorRethrownVisitor(this, inspectionManager, onTheFly); + } + + private static class ErrorRethrownVisitor extends BaseInspectionVisitor { + private ErrorRethrownVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitTryStatement(PsiTryStatement statement) { + super.visitTryStatement(statement); + final PsiParameter[] parameters = statement.getCatchBlockParameters(); + if (parameters == null) { + return; + } + final PsiCodeBlock[] catchBlocks = statement.getCatchBlocks(); + if (catchBlocks == null) { + return; + } + final int length = Math.min(parameters.length, catchBlocks.length); + for (int i = 0; i < length; i++) { + final PsiParameter parameter = parameters[i]; + final PsiCodeBlock catchBlock = catchBlocks[i]; + checkCatchBlock(parameter, catchBlock); + } + } + + private void checkCatchBlock(PsiParameter parameter, PsiCodeBlock catchBlock) { + final PsiType type = parameter.getType(); + final PsiClass aClass = PsiUtil.resolveClassInType(type); + if (!ClassUtils.isSubclass(aClass, "java.lang.Error")) { + return; + } + if (TypeUtils.typeEquals("java.lang.ThreadDeath", type)) { + return; + } + final PsiTypeElement typeElement = parameter.getTypeElement(); + if (typeElement == null) { + return; + } + final PsiStatement[] statements = catchBlock.getStatements(); + if (statements.length == 0) { + registerError(typeElement); + return; + } + final PsiStatement lastStatement = statements[statements.length - 1]; + if (!(lastStatement instanceof PsiThrowStatement)) { + registerError(typeElement); + return; + } + final PsiThrowStatement throwStatement = (PsiThrowStatement) lastStatement; + final PsiExpression exception = throwStatement.getException(); + if (!(exception instanceof PsiReferenceExpression)) { + registerError(typeElement); + return; + } + final PsiElement element = ((PsiReference) exception).resolve(); + if (!element.equals(parameter)) { + registerError(typeElement); + return; + } + } + + } +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/errorhandling/ExceptionFromCatchWhichDoesntWrapInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/errorhandling/ExceptionFromCatchWhichDoesntWrapInspection.java new file mode 100644 index 000000000000..ef3260b5d1b9 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/errorhandling/ExceptionFromCatchWhichDoesntWrapInspection.java @@ -0,0 +1,82 @@ +package com.siyeh.ig.errorhandling; + +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; +import com.siyeh.ig.psiutils.ControlFlowUtils; + +public class ExceptionFromCatchWhichDoesntWrapInspection extends StatementInspection { + + public String getDisplayName() { + return "'throw' inside 'catch' block which ignores the caught exception"; + } + + public String getGroupDisplayName() { + return GroupNames.ERRORHANDLING_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "'#ref' inside 'catch' block ignores the caught exception #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new ExceptionFromCatchWhichDoesntWrapVisitor(this, inspectionManager, onTheFly); + } + + private static class ExceptionFromCatchWhichDoesntWrapVisitor extends BaseInspectionVisitor { + private ExceptionFromCatchWhichDoesntWrapVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitThrowStatement(PsiThrowStatement statement) { + super.visitThrowStatement(statement); + if (!ControlFlowUtils.isInCatchBlock(statement)) { + return; + } + final PsiExpression exception = statement.getException(); + if (exception == null) { + return; + } + if (!(exception instanceof PsiNewExpression)) { + return; + } + final PsiNewExpression newExpression = (PsiNewExpression) exception; + final PsiMethod constructor = newExpression.resolveConstructor(); + if (constructor == null) { + return; + } + final PsiExpressionList argumentList = newExpression.getArgumentList(); + if (argumentList == null) { + return; + } + final PsiExpression[] args = argumentList.getExpressions(); + if (args == null) { + return; + } + if (argIsCatchParameter(args)) { + return; + } + registerStatementError(statement); + } + + private static boolean argIsCatchParameter(PsiExpression[] args) { + for (int i = 0; i < args.length; i++) { + final PsiExpression arg = args[i]; + if (arg instanceof PsiReferenceExpression) { + final PsiReferenceExpression ref = (PsiReferenceExpression) arg; + final PsiElement referent = ref.resolve(); + if (referent != null + && referent instanceof PsiParameter + && referent.getParent() instanceof PsiTryStatement) { + return true; + } + } + } + return false; + } + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/errorhandling/InstanceofCatchParameterInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/errorhandling/InstanceofCatchParameterInspection.java new file mode 100644 index 000000000000..35aec600135c --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/errorhandling/InstanceofCatchParameterInspection.java @@ -0,0 +1,63 @@ +package com.siyeh.ig.errorhandling; + +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.ControlFlowUtils; + +public class InstanceofCatchParameterInspection extends ExpressionInspection { + + public String getDisplayName() { + return "'instanceof' on 'catch' parameter"; + } + + public String getGroupDisplayName() { + return GroupNames.ERRORHANDLING_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "'instanceof' on 'catch' parameter #ref #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new InstanceofCatchParameterVisitor(this, inspectionManager, onTheFly); + } + + private static class InstanceofCatchParameterVisitor extends BaseInspectionVisitor { + private InstanceofCatchParameterVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitInstanceOfExpression(PsiInstanceOfExpression exp) { + super.visitInstanceOfExpression(exp); + if (!ControlFlowUtils.isInCatchBlock(exp)) { + return; + } + + final PsiExpression operand = exp.getOperand(); + if (operand == null) { + return; + } + if (!(operand instanceof PsiReferenceExpression)) { + return; + } + final PsiReferenceExpression ref = (PsiReferenceExpression) operand; + final PsiElement referent = ref.resolve(); + if (referent == null) { + return; + } + if (!(referent instanceof PsiParameter)) { + return; + } + if (!(referent.getParent() instanceof PsiTryStatement)) { + return; + } + registerError(exp); + } + + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/errorhandling/NestedTryStatementInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/errorhandling/NestedTryStatementInspection.java new file mode 100644 index 000000000000..1a69dfc8be8f --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/errorhandling/NestedTryStatementInspection.java @@ -0,0 +1,52 @@ +package com.siyeh.ig.errorhandling; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.psi.PsiCodeBlock; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiTryStatement; +import com.intellij.psi.util.PsiTreeUtil; +import com.siyeh.ig.BaseInspection; +import com.siyeh.ig.BaseInspectionVisitor; +import com.siyeh.ig.GroupNames; +import com.siyeh.ig.StatementInspection; + +public class NestedTryStatementInspection extends StatementInspection { + + public String getDisplayName() { + return "Nested 'try' statement"; + } + + public String getGroupDisplayName() { + return GroupNames.ERRORHANDLING_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "Nested '#ref' statement #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new NestedTryStatementVisitor(this, inspectionManager, onTheFly); + } + + private static class NestedTryStatementVisitor extends BaseInspectionVisitor { + private NestedTryStatementVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitTryStatement(PsiTryStatement statement) { + super.visitTryStatement(statement); + final PsiTryStatement parentTry = (PsiTryStatement) PsiTreeUtil.getParentOfType(statement, + PsiTryStatement.class); + if (parentTry == null) { + return; + } + final PsiCodeBlock tryBlock = parentTry.getTryBlock(); + if (!PsiTreeUtil.isAncestor(tryBlock, statement, true)) { + return; + } + registerStatementError(statement); + } + + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/errorhandling/ReturnFromFinallyBlockInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/errorhandling/ReturnFromFinallyBlockInspection.java new file mode 100644 index 000000000000..f8b77fd3efc7 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/errorhandling/ReturnFromFinallyBlockInspection.java @@ -0,0 +1,45 @@ +package com.siyeh.ig.errorhandling; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiReturnStatement; +import com.siyeh.ig.BaseInspection; +import com.siyeh.ig.BaseInspectionVisitor; +import com.siyeh.ig.GroupNames; +import com.siyeh.ig.StatementInspection; +import com.siyeh.ig.psiutils.ControlFlowUtils; + +public class ReturnFromFinallyBlockInspection extends StatementInspection { + + public String getDisplayName() { + return "'return' inside 'finally' block"; + } + + public String getGroupDisplayName() { + return GroupNames.ERRORHANDLING_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "'#ref' inside 'finally' block #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new ReturnFromFinallyBlockVisitor(this, inspectionManager, onTheFly); + } + + private static class ReturnFromFinallyBlockVisitor extends BaseInspectionVisitor { + private ReturnFromFinallyBlockVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitReturnStatement(PsiReturnStatement statement) { + super.visitReturnStatement(statement); + if (!ControlFlowUtils.isInFinallyBlock(statement)) { + return; + } + registerStatementError(statement); + } + + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/errorhandling/ThreadDeathRethrownInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/errorhandling/ThreadDeathRethrownInspection.java new file mode 100644 index 000000000000..2c0b882eec57 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/errorhandling/ThreadDeathRethrownInspection.java @@ -0,0 +1,85 @@ +package com.siyeh.ig.errorhandling; + +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; +import com.siyeh.ig.psiutils.TypeUtils; + +public class ThreadDeathRethrownInspection extends StatementInspection { + + public String getDisplayName() { + return "ThreadDeath not rethrown"; + } + + public String getGroupDisplayName() { + return GroupNames.ERRORHANDLING_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "#ref not rethrown #loc"; + } + + protected BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new ThreadDeathRethrownVisitor(this, inspectionManager, onTheFly); + } + + private static class ThreadDeathRethrownVisitor extends BaseInspectionVisitor { + private ThreadDeathRethrownVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitTryStatement(PsiTryStatement statement) { + super.visitTryStatement(statement); + final PsiParameter[] parameters = statement.getCatchBlockParameters(); + final PsiCodeBlock[] catchBlocks = statement.getCatchBlocks(); + if (parameters == null) { + return; + } + if (catchBlocks == null) { + return; + } + final int length = Math.min(parameters.length, catchBlocks.length); + for (int i = 0; i < length; i++) { + final PsiParameter parameter = parameters[i]; + final PsiCodeBlock catchBlock = catchBlocks[i]; + checkCatchBlock(parameter, catchBlock); + } + } + + private void checkCatchBlock(PsiParameter parameter, PsiCodeBlock catchBlock) { + final PsiType type = parameter.getType(); + if (!TypeUtils.typeEquals("java.lang.ThreadDeath", type)) { + return; + } + final PsiTypeElement typeElement = parameter.getTypeElement(); + if (typeElement == null) { + return; + } + final PsiStatement[] statements = catchBlock.getStatements(); + if (statements.length == 0) { + registerError(typeElement); + return; + } + final PsiStatement lastStatement = statements[statements.length - 1]; + if (!(lastStatement instanceof PsiThrowStatement)) { + registerError(typeElement); + return; + } + final PsiThrowStatement throwStatement = (PsiThrowStatement) lastStatement; + final PsiExpression exception = throwStatement.getException(); + if (!(exception instanceof PsiReferenceExpression)) { + registerError(typeElement); + return; + } + final PsiElement element = ((PsiReference) exception).resolve(); + if (!element.equals(parameter)) { + registerError(typeElement); + return; + } + } + + } +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/errorhandling/ThrowCaughtLocallyInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/errorhandling/ThrowCaughtLocallyInspection.java new file mode 100644 index 000000000000..bcf1352d7935 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/errorhandling/ThrowCaughtLocallyInspection.java @@ -0,0 +1,67 @@ +package com.siyeh.ig.errorhandling; + +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.GroupNames; +import com.siyeh.ig.StatementInspection; + +public class ThrowCaughtLocallyInspection extends StatementInspection { + + public String getDisplayName() { + return "'throw' caught by containing 'try' statement"; + } + + public String getGroupDisplayName() { + return GroupNames.ERRORHANDLING_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "'#ref' caught by containing 'try' statement #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new ThrowCaughtLocallyVisitor(this, inspectionManager, onTheFly); + } + + private static class ThrowCaughtLocallyVisitor extends BaseInspectionVisitor { + private ThrowCaughtLocallyVisitor(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 exceptionType = exception.getType(); + if (exceptionType == null) { + return; + } + + PsiTryStatement containingTryStatement = + (PsiTryStatement) PsiTreeUtil.getParentOfType(statement, PsiTryStatement.class); + while (containingTryStatement != null) { + final PsiCodeBlock tryBlock = containingTryStatement.getTryBlock(); + if (PsiTreeUtil.isAncestor(tryBlock, statement, true)) { + final PsiParameter[] catchBlockParameters = + containingTryStatement.getCatchBlockParameters(); + for (int i = 0; i < catchBlockParameters.length; i++) { + final PsiParameter parameter = catchBlockParameters[i]; + final PsiType parameterType = parameter.getType(); + if (parameterType.isAssignableFrom(exceptionType)) { + registerStatementError(statement); + return; + } + } + } + containingTryStatement = + (PsiTryStatement) PsiTreeUtil.getParentOfType(containingTryStatement, PsiTryStatement.class); + } + } + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/errorhandling/ThrowFromFinallyBlockInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/errorhandling/ThrowFromFinallyBlockInspection.java new file mode 100644 index 000000000000..ce20790ebe56 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/errorhandling/ThrowFromFinallyBlockInspection.java @@ -0,0 +1,44 @@ +package com.siyeh.ig.errorhandling; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiThrowStatement; +import com.siyeh.ig.BaseInspection; +import com.siyeh.ig.BaseInspectionVisitor; +import com.siyeh.ig.GroupNames; +import com.siyeh.ig.StatementInspection; +import com.siyeh.ig.psiutils.ControlFlowUtils; + +public class ThrowFromFinallyBlockInspection extends StatementInspection { + + public String getDisplayName() { + return "'throw' inside 'finally' block"; + } + + public String getGroupDisplayName() { + return GroupNames.ERRORHANDLING_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "'#ref' inside 'finally' block #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new ThrowFromFinallyBlockVisitor(this, inspectionManager, onTheFly); + } + + private static class ThrowFromFinallyBlockVisitor extends BaseInspectionVisitor { + private ThrowFromFinallyBlockVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitThrowStatement(PsiThrowStatement statement) { + super.visitThrowStatement(statement); + if (!ControlFlowUtils.isInFinallyBlock(statement)) { + return; + } + registerStatementError(statement); + } + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/errorhandling/TooBroadCatchInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/errorhandling/TooBroadCatchInspection.java new file mode 100644 index 000000000000..b0d78698215a --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/errorhandling/TooBroadCatchInspection.java @@ -0,0 +1,71 @@ +package com.siyeh.ig.errorhandling; + +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; +import com.siyeh.ig.psiutils.ExceptionUtils; + +import java.util.HashSet; +import java.util.Iterator; +import java.util.Set; + +public class TooBroadCatchInspection extends StatementInspection { + + public String getDisplayName() { + return "Overly broad 'catch' block"; + } + + public String getGroupDisplayName() { + return GroupNames.ERRORHANDLING_GROUP_NAME; + } + + public String buildErrorString(Object val) { + return "Catch of #ref is too broad, masking exception " + val + " #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new TooBroadCatchVisitor(this, inspectionManager, onTheFly); + } + + private static class TooBroadCatchVisitor extends BaseInspectionVisitor { + private TooBroadCatchVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitTryStatement(PsiTryStatement statement) { + super.visitTryStatement(statement); + + final PsiManager manager = statement.getManager(); + final PsiElementFactory factory = manager.getElementFactory(); + final PsiCodeBlock tryBlock = statement.getTryBlock(); + if (tryBlock == null) { + return; + } + final Set exceptionsThrown = ExceptionUtils.calculateExceptionsThrown(tryBlock, factory); + final int numExceptionsThrown = exceptionsThrown.size(); + final Set exceptionsCaught = new HashSet(numExceptionsThrown); + final PsiParameter[] parameters = statement.getCatchBlockParameters(); + for (int i = 0; i < parameters.length; i++) { + final PsiParameter parameter = parameters[i]; + final PsiType typeCaught = parameter.getType(); + for (Iterator iterator = exceptionsThrown.iterator(); iterator.hasNext();) { + final PsiType typeThrown = (PsiType) iterator.next(); + if (exceptionsCaught.contains(typeThrown)) { + // don't do anything + } else if (typeCaught.equals(typeThrown)) { + exceptionsCaught.add(typeCaught); + } else if (typeCaught.isAssignableFrom(typeThrown)) { + exceptionsCaught.add(typeCaught); + final String typeThrownText = typeThrown.getPresentableText(); + final PsiTypeElement typeElement = parameter.getTypeElement(); + registerError(typeElement, typeThrownText); + } + } + } + } + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/errorhandling/UncheckedExceptionClassInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/errorhandling/UncheckedExceptionClassInspection.java new file mode 100644 index 000000000000..6b409cb3ebe5 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/errorhandling/UncheckedExceptionClassInspection.java @@ -0,0 +1,48 @@ +package com.siyeh.ig.errorhandling; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.psi.PsiClass; +import com.intellij.psi.PsiElement; +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 UncheckedExceptionClassInspection extends ClassInspection { + + public String getDisplayName() { + return "Unchecked exception class"; + } + + public String getGroupDisplayName() { + return GroupNames.ERRORHANDLING_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "Unchecked exception class #ref #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new UncheckedExceptionClassVisitor(this, inspectionManager, onTheFly); + } + + private static class UncheckedExceptionClassVisitor extends BaseInspectionVisitor { + private UncheckedExceptionClassVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitClass(PsiClass aClass) { + if (!ClassUtils.isSubclass(aClass, "java.lang.Throwable")) { + return; + } + if (ClassUtils.isSubclass(aClass, "java.lang.Exception") && + !ClassUtils.isSubclass(aClass, "java.lang.RuntimeException")) { + return; + } + registerClassError(aClass); + } + + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/errorhandling/UnusedCatchParameterInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/errorhandling/UnusedCatchParameterInspection.java new file mode 100644 index 000000000000..b99a36df67a4 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/errorhandling/UnusedCatchParameterInspection.java @@ -0,0 +1,108 @@ +package com.siyeh.ig.errorhandling; + +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; +import com.siyeh.ig.psiutils.ClassUtils; + +import javax.swing.*; +import javax.swing.event.ChangeEvent; +import javax.swing.event.ChangeListener; +import java.awt.*; + +public class UnusedCatchParameterInspection extends StatementInspection { + public boolean m_ignoreCatchBlocksWithComments = false; + public boolean m_ignoreTestCases = false; + + public String getDisplayName() { + return "Unused 'catch' parameter"; + } + + public String getGroupDisplayName() { + return GroupNames.ERRORHANDLING_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "Unused catch parameter #ref #loc"; + } + + public JComponent createOptionsPanel() { + final GridBagLayout layout = new GridBagLayout(); + final JPanel panel = new JPanel(layout); + final JCheckBox commentsCheckBox = new JCheckBox("Ignore catch blocks containing comments", m_ignoreCatchBlocksWithComments); + final ButtonModel commentsModel = commentsCheckBox.getModel(); + commentsModel.addChangeListener(new ChangeListener() { + + public void stateChanged(ChangeEvent e) { + m_ignoreCatchBlocksWithComments = commentsModel.isSelected(); + } + }); + final JCheckBox testCaseCheckBox = new JCheckBox("Ignore empty catch blocks in JUnit test cases", m_ignoreTestCases); + final ButtonModel model = testCaseCheckBox.getModel(); + model.addChangeListener(new ChangeListener() { + + public void stateChanged(ChangeEvent e) { + m_ignoreTestCases = model.isSelected(); + } + }); + final GridBagConstraints constraints = new GridBagConstraints(); + constraints.gridx = 0; + constraints.gridy = 0; + constraints.fill = GridBagConstraints.HORIZONTAL; + panel.add(commentsCheckBox, constraints); + + constraints.gridx = 0; + constraints.gridy = 1; + panel.add(testCaseCheckBox, constraints); + return panel; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new EmptyCatchBlockVisitor(this, inspectionManager, onTheFly); + } + + private class EmptyCatchBlockVisitor extends BaseInspectionVisitor { + private EmptyCatchBlockVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitTryStatement(PsiTryStatement statement) { + super.visitTryStatement(statement); + if (m_ignoreTestCases) { + final PsiClass aClass = + ClassUtils.getContainingClass(statement); + if (aClass != null && ClassUtils.isSubclass(aClass, "junit.framework.TestCase")) { + return; + } + } + + final PsiCodeBlock[] catchBlocks = statement.getCatchBlocks(); + final PsiParameter[] params = statement.getCatchBlockParameters(); + for (int i = 0; i < Math.min(catchBlocks.length, params.length); i++) { + final PsiCodeBlock block = catchBlocks[i]; + final PsiParameter param = params[i]; + if (m_ignoreCatchBlocksWithComments) { + final PsiElement[] children = block.getChildren(); + for (int j = 0; j < children.length; j++) { + final PsiElement child = children[i]; + if (child instanceof PsiComment) { + return; + } + } + } + if (block != null && param != null) { + final CatchParameterUsedVisitor visitor = + new CatchParameterUsedVisitor(param); + block.accept(visitor); + + if (!visitor.isUsed()) { + registerVariableError(param); + } + } + } + } + } +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/finalization/CallToSuperFinalizeVisitor.java b/plugins/InspectionGadgets/src/com/siyeh/ig/finalization/CallToSuperFinalizeVisitor.java new file mode 100644 index 000000000000..48c11611c6be --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/finalization/CallToSuperFinalizeVisitor.java @@ -0,0 +1,42 @@ +package com.siyeh.ig.finalization; + +import com.intellij.psi.*; + +class CallToSuperFinalizeVisitor extends PsiRecursiveElementVisitor { + private boolean m_callToSuperFinalizeFound = false; + + public void visitMethodCallExpression(PsiMethodCallExpression expression) { + super.visitMethodCallExpression(expression); + final PsiReferenceExpression methodExpression = expression.getMethodExpression(); + if (methodExpression == null) { + return; + } + final PsiExpression target = methodExpression.getQualifierExpression(); + if (target == null) { + return; + } + if (!(target instanceof PsiSuperExpression)) { + return; + } + final String methodName = methodExpression.getReferenceName(); + if (!"finalize".equals(methodName)) { + return; + } + m_callToSuperFinalizeFound = true; + } + + public void visitReferenceExpression(PsiReferenceExpression expression) { + final PsiExpression qualifier = expression.getQualifierExpression(); + if (qualifier != null) { + qualifier.accept(this); + } + final PsiReferenceParameterList typeParameters = expression.getParameterList(); + if (typeParameters != null) { + typeParameters.accept(this); + } + } + + public boolean isCallToSuperFinalizeFound() { + return m_callToSuperFinalizeFound; + } +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/finalization/FinalizeCallsSuperFinalizeInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/finalization/FinalizeCallsSuperFinalizeInspection.java new file mode 100644 index 000000000000..2bdfd0530d2d --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/finalization/FinalizeCallsSuperFinalizeInspection.java @@ -0,0 +1,55 @@ +package com.siyeh.ig.finalization; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiMethod; +import com.intellij.psi.PsiParameterList; +import com.siyeh.ig.BaseInspection; +import com.siyeh.ig.BaseInspectionVisitor; +import com.siyeh.ig.GroupNames; +import com.siyeh.ig.MethodInspection; + +public class FinalizeCallsSuperFinalizeInspection extends MethodInspection { + + public String getDisplayName() { + return "finalize() doesn't call super.finalize()"; + } + + public String getGroupDisplayName() { + return GroupNames.FINALIZATION_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "#ref() doesn't call super.finalize()"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new NoExplicitFinalizeCallsVisitor(this, inspectionManager, onTheFly); + } + + private static class NoExplicitFinalizeCallsVisitor extends BaseInspectionVisitor { + private NoExplicitFinalizeCallsVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitMethod(PsiMethod method) { + //note: no call to super; + final String methodName = method.getName(); + if (!"finalize".equals(methodName)) { + return; + } + final PsiParameterList parameterList = method.getParameterList(); + if (parameterList.getParameters().length != 0) { + return; + } + final CallToSuperFinalizeVisitor visitor = new CallToSuperFinalizeVisitor(); + method.accept(visitor); + if (visitor.isCallToSuperFinalizeFound()) { + return; + } + registerMethodError(method); + } + + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/finalization/FinalizeInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/finalization/FinalizeInspection.java new file mode 100644 index 000000000000..31d32ea87b23 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/finalization/FinalizeInspection.java @@ -0,0 +1,49 @@ +package com.siyeh.ig.finalization; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiMethod; +import com.intellij.psi.PsiParameterList; +import com.siyeh.ig.BaseInspection; +import com.siyeh.ig.BaseInspectionVisitor; +import com.siyeh.ig.GroupNames; +import com.siyeh.ig.MethodInspection; + +public class FinalizeInspection extends MethodInspection { + + public String getDisplayName() { + return "Use of finalize()"; + } + + public String getGroupDisplayName() { + return GroupNames.FINALIZATION_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "#ref() declared #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new FinalizeDeclaredVisitor(this, inspectionManager, onTheFly); + } + + private static class FinalizeDeclaredVisitor extends BaseInspectionVisitor { + private FinalizeDeclaredVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitMethod(PsiMethod method) { + //note: no call to super; + final String methodName = method.getName(); + if (!"finalize".equals(methodName)) { + return; + } + final PsiParameterList parameterList = method.getParameterList(); + if (parameterList.getParameters().length != 0) { + return; + } + registerMethodError(method); + } + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/finalization/FinalizeNotProtectedInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/finalization/FinalizeNotProtectedInspection.java new file mode 100644 index 000000000000..7ac37b6f7ac5 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/finalization/FinalizeNotProtectedInspection.java @@ -0,0 +1,77 @@ +package com.siyeh.ig.finalization; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.codeInspection.ProblemDescriptor; +import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.project.Project; +import com.intellij.psi.*; +import com.intellij.util.IncorrectOperationException; +import com.siyeh.ig.*; + +public class FinalizeNotProtectedInspection extends MethodInspection { + private static final Logger s_logger = + Logger.getInstance("FinalizeNotProtectedInspection"); + private final ProtectedFinalizeFix fix = new ProtectedFinalizeFix(); + + public String getDisplayName() { + return "finalize() not declared 'protected'"; + } + + public String getGroupDisplayName() { + return GroupNames.FINALIZATION_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "#ref() not declared 'protected' #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new FinalizeDeclaredProtectedVisitor(this, inspectionManager, onTheFly); + } + + public InspectionGadgetsFix buildFix(PsiElement location) { + return fix; + } + + private static class ProtectedFinalizeFix extends InspectionGadgetsFix { + public String getName() { + return "Make 'protected'"; + } + + public void applyFix(Project project, ProblemDescriptor descriptor) { + final PsiElement methodName = descriptor.getPsiElement(); + final PsiMethod method = (PsiMethod) methodName.getParent(); + try { + final PsiModifierList modifiers = method.getModifierList(); + modifiers.setModifierProperty(PsiModifier.PUBLIC, false); + modifiers.setModifierProperty(PsiModifier.PRIVATE, false); + modifiers.setModifierProperty(PsiModifier.PROTECTED, true); + } catch (IncorrectOperationException e) { + s_logger.error(e); + } + } + } + + private static class FinalizeDeclaredProtectedVisitor extends BaseInspectionVisitor { + private FinalizeDeclaredProtectedVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitMethod(PsiMethod method) { + //note: no call to super; + final String methodName = method.getName(); + if (!"finalize".equals(methodName)) { + return; + } + final PsiParameterList parameterList = method.getParameterList(); + if (parameterList.getParameters().length != 0) { + return; + } + if (method.hasModifierProperty(PsiModifier.PROTECTED)) { + return; + } + registerMethodError(method); + } + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/finalization/NoExplicitFinalizeCallsInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/finalization/NoExplicitFinalizeCallsInspection.java new file mode 100644 index 000000000000..02c09f1d0e5c --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/finalization/NoExplicitFinalizeCallsInspection.java @@ -0,0 +1,60 @@ +package com.siyeh.ig.finalization; + +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 NoExplicitFinalizeCallsInspection extends ExpressionInspection { + + public String getDisplayName() { + return "finalize() called explicitly"; + } + + public String getGroupDisplayName() { + return GroupNames.FINALIZATION_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "#ref() called explicitly #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new NoExplicitFinalizeCallsVisitor(this, inspectionManager, onTheFly); + } + + private static class NoExplicitFinalizeCallsVisitor extends BaseInspectionVisitor { + private NoExplicitFinalizeCallsVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitMethodCallExpression(PsiMethodCallExpression expression) { + super.visitMethodCallExpression(expression); + final PsiReferenceExpression methodExpression = expression.getMethodExpression(); + if (methodExpression == null) { + return; + } + final String methodName = methodExpression.getReferenceName(); + if (!"finalize".equals(methodName)) { + return; + } + final PsiExpressionList argumentList = expression.getArgumentList(); + if (argumentList.getExpressions().length != 0) { + return; + } + final PsiMethod containingMethod = + (PsiMethod) PsiTreeUtil.getParentOfType(expression, PsiMethod.class); + final String containingMethodName = containingMethod.getName(); + final PsiParameterList parameterList = containingMethod.getParameterList(); + if ("finalize".equals(containingMethodName) + && parameterList.getParameters().length == 0) { + return; + } + registerMethodCallError(expression); + } + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/fixes/EncapsulateVariableFix.java b/plugins/InspectionGadgets/src/com/siyeh/ig/fixes/EncapsulateVariableFix.java new file mode 100644 index 000000000000..5313cf20b4f3 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/fixes/EncapsulateVariableFix.java @@ -0,0 +1,26 @@ +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.PsiField; +import com.intellij.refactoring.RefactoringActionHandler; +import com.intellij.refactoring.RefactoringActionHandlerFactory; +import com.siyeh.ig.InspectionGadgetsFix; + +public class EncapsulateVariableFix extends InspectionGadgetsFix { + + public String getName() { + return "Encapsulate variable"; + } + + public void applyFix(Project project, ProblemDescriptor problemDescriptor) { + final PsiElement nameElement = problemDescriptor.getPsiElement(); + final PsiField field = (PsiField) nameElement.getParent(); + final RefactoringActionHandlerFactory factory = + RefactoringActionHandlerFactory.getInstance(); + final RefactoringActionHandler renameHandler = + factory.createEncapsulateFieldsHandler(); + renameHandler.invoke(project, new PsiElement[]{field}, null); + } +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/fixes/IntroduceConstantFix.java b/plugins/InspectionGadgets/src/com/siyeh/ig/fixes/IntroduceConstantFix.java new file mode 100644 index 000000000000..4c67a2f870f8 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/fixes/IntroduceConstantFix.java @@ -0,0 +1,21 @@ +package com.siyeh.ig.fixes; + +import com.intellij.codeInspection.ProblemDescriptor; +import com.intellij.openapi.project.Project; +import com.intellij.psi.PsiElement; +import com.intellij.refactoring.RefactoringActionHandler; +import com.intellij.refactoring.RefactoringActionHandlerFactory; +import com.siyeh.ig.InspectionGadgetsFix; + +public class IntroduceConstantFix extends InspectionGadgetsFix { + public String getName() { + return "Introduce constant"; + } + + public void applyFix(Project project, ProblemDescriptor descriptor) { + final RefactoringActionHandlerFactory factory = RefactoringActionHandlerFactory.getInstance(); + final RefactoringActionHandler introduceHandler = factory.createIntroduceConstantHandler(); + final PsiElement constant = descriptor.getPsiElement(); + introduceHandler.invoke(project, new PsiElement[]{constant}, null); + } +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/fixes/MoveAnonymousToInnerClassFix.java b/plugins/InspectionGadgets/src/com/siyeh/ig/fixes/MoveAnonymousToInnerClassFix.java new file mode 100644 index 000000000000..41eeef270cb5 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/fixes/MoveAnonymousToInnerClassFix.java @@ -0,0 +1,24 @@ +package com.siyeh.ig.fixes; + +import com.intellij.codeInspection.ProblemDescriptor; +import com.intellij.openapi.project.Project; +import com.intellij.psi.PsiAnonymousClass; +import com.intellij.psi.PsiElement; +import com.intellij.refactoring.RefactoringActionHandler; +import com.intellij.refactoring.RefactoringActionHandlerFactory; +import com.siyeh.ig.InspectionGadgetsFix; + +public class MoveAnonymousToInnerClassFix extends InspectionGadgetsFix { + public String getName() { + return "Make named inner class"; + } + + public void applyFix(Project project, ProblemDescriptor problemDescriptor) { + final PsiElement nameElement = problemDescriptor.getPsiElement(); + final PsiAnonymousClass aClass = (PsiAnonymousClass) nameElement.getParent(); + final RefactoringActionHandlerFactory factory = + RefactoringActionHandlerFactory.getInstance(); + final RefactoringActionHandler anonymousToInner = factory.createAnonymousToInnerHandler(); + anonymousToInner.invoke(project, new PsiElement[]{aClass}, null); + } +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/fixes/MoveClassFix.java b/plugins/InspectionGadgets/src/com/siyeh/ig/fixes/MoveClassFix.java new file mode 100644 index 000000000000..c63e9dc47a98 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/fixes/MoveClassFix.java @@ -0,0 +1,24 @@ +package com.siyeh.ig.fixes; + +import com.intellij.codeInspection.ProblemDescriptor; +import com.intellij.openapi.project.Project; +import com.intellij.psi.PsiClass; +import com.intellij.psi.PsiElement; +import com.intellij.refactoring.RefactoringActionHandler; +import com.intellij.refactoring.RefactoringActionHandlerFactory; +import com.siyeh.ig.InspectionGadgetsFix; + +public class MoveClassFix extends InspectionGadgetsFix { + public String getName() { + return "Move class"; + } + + public void applyFix(Project project, ProblemDescriptor problemDescriptor) { + final PsiElement nameElement = problemDescriptor.getPsiElement(); + final PsiClass aClass = (PsiClass) nameElement.getParent(); + final RefactoringActionHandlerFactory factory = + RefactoringActionHandlerFactory.getInstance(); + final RefactoringActionHandler renameHandler = factory.createMoveHandler(); + renameHandler.invoke(project, new PsiElement[]{aClass}, null); + } +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/fixes/NormalizeDeclarationFix.java b/plugins/InspectionGadgets/src/com/siyeh/ig/fixes/NormalizeDeclarationFix.java new file mode 100644 index 000000000000..f42d9b80bf48 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/fixes/NormalizeDeclarationFix.java @@ -0,0 +1,28 @@ +package com.siyeh.ig.fixes; + +import com.siyeh.ig.InspectionGadgetsFix; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.diagnostic.Logger; +import com.intellij.codeInspection.ProblemDescriptor; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiVariable; +import com.intellij.util.IncorrectOperationException; + +public class NormalizeDeclarationFix extends InspectionGadgetsFix { + public String getName() { + return "Split into multiple declarations"; + } + + public void applyFix(Project project, ProblemDescriptor descriptor) { + final PsiElement variableNameElement = descriptor.getPsiElement(); + final PsiVariable var = (PsiVariable) variableNameElement.getParent(); + try { + var.normalizeDeclaration(); + } catch (IncorrectOperationException e) { + final Class aClass = getClass(); + final String className = aClass.getName(); + final Logger logger = Logger.getInstance(className); + logger.error(e); + } + } +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/fixes/RemoveModifierFix.java b/plugins/InspectionGadgets/src/com/siyeh/ig/fixes/RemoveModifierFix.java new file mode 100644 index 000000000000..4316c114f365 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/fixes/RemoveModifierFix.java @@ -0,0 +1,24 @@ +package com.siyeh.ig.fixes; + +import com.intellij.codeInspection.ProblemDescriptor; +import com.intellij.openapi.project.Project; +import com.intellij.psi.PsiElement; +import com.siyeh.ig.InspectionGadgetsFix; + +public class RemoveModifierFix extends InspectionGadgetsFix { + private final PsiElement modifier; + + public RemoveModifierFix(PsiElement modifier) { + super(); + this.modifier = modifier; + } + + public String getName() { + return "Remove '" + modifier.getText() + "' modifier"; + } + + public void applyFix(Project project, ProblemDescriptor descriptor) { + final PsiElement modifierElement = descriptor.getPsiElement(); + deleteElement(modifierElement); + } +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/fixes/RenameFix.java b/plugins/InspectionGadgets/src/com/siyeh/ig/fixes/RenameFix.java new file mode 100644 index 000000000000..0536f152c411 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/fixes/RenameFix.java @@ -0,0 +1,47 @@ +package com.siyeh.ig.fixes; + +import com.intellij.codeInspection.ProblemDescriptor; +import com.intellij.openapi.project.Project; +import com.intellij.psi.PsiElement; +import com.intellij.refactoring.RefactoringActionHandler; +import com.intellij.refactoring.RefactoringActionHandlerFactory; +import com.intellij.refactoring.RefactoringFactory; +import com.intellij.refactoring.RenameRefactoring; +import com.siyeh.ig.InspectionGadgetsFix; + +public class RenameFix extends InspectionGadgetsFix { + private final String m_targetName; + + public RenameFix() { + super(); + m_targetName = null; + } + + public RenameFix(String targetName) { + super(); + m_targetName = targetName; + } + + public String getName() { + if (m_targetName == null) { + return "Rename"; + } else { + return "Rename to '" + m_targetName + "()'"; + } + } + + public void applyFix(Project project, ProblemDescriptor problemDescriptor) { + final PsiElement nameIdentifier = problemDescriptor.getPsiElement(); + final PsiElement elementToRename = nameIdentifier.getParent(); + if (m_targetName == null) { + final RefactoringActionHandlerFactory factory = + RefactoringActionHandlerFactory.getInstance(); + final RefactoringActionHandler renameHandler = factory.createRenameHandler(); + renameHandler.invoke(project, new PsiElement[]{elementToRename}, null); + } else { + final RefactoringFactory factory = RefactoringFactory.getInstance(project); + final RenameRefactoring renameRefactoring = factory.createRename(elementToRename, m_targetName); + renameRefactoring.run(); + } + } +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/imports/ImportIsUsedVisitor.java b/plugins/InspectionGadgets/src/com/siyeh/ig/imports/ImportIsUsedVisitor.java new file mode 100644 index 000000000000..13629a90c335 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/imports/ImportIsUsedVisitor.java @@ -0,0 +1,66 @@ +package com.siyeh.ig.imports; + +import com.intellij.psi.*; + +class ImportIsUsedVisitor extends PsiRecursiveElementVisitor { + private final PsiImportStatement m_import; + private boolean m_used = false; + + ImportIsUsedVisitor(PsiImportStatement importStatement) { + super(); + m_import = importStatement; + } + + public void visitReferenceElement(PsiJavaCodeReferenceElement ref) { + super.visitReferenceElement(ref); + followReferenceToImport(ref); + } + + 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); + } + followReferenceToImport(ref); + } + + private void followReferenceToImport(PsiJavaCodeReferenceElement ref) { + final PsiElement element = ref.resolve(); + if (!(element instanceof PsiClass)) { + return; + } + final PsiClass referencedClass = (PsiClass) element; + if (ref.getQualifier()!=null) { + return; //it' already fully qualified, so the import statement wasn't responsible + } + final String importName = m_import.getQualifiedName(); + if (importName == null) { + return; + } + final String qualifiedName = referencedClass.getQualifiedName(); + if (qualifiedName == null) { + return; + } + if (m_import.isOnDemand()) { + final int lastComponentIndex = qualifiedName.lastIndexOf((int) '.'); + if (lastComponentIndex > 0) { + final String packageName = qualifiedName.substring(0, lastComponentIndex); + if (importName.equals(packageName)) { + m_used = true; + } + } + } else { + if (importName.equals(qualifiedName)) { + m_used = true; + } + } + } + + public boolean isUsed() { + return m_used; + } +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/imports/JavaLangImportInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/imports/JavaLangImportInspection.java new file mode 100644 index 000000000000..682f9cbeca21 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/imports/JavaLangImportInspection.java @@ -0,0 +1,89 @@ +package com.siyeh.ig.imports; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.codeInspection.ProblemDescriptor; +import com.intellij.psi.*; +import com.intellij.openapi.project.Project; +import com.siyeh.ig.*; +import com.siyeh.ig.psiutils.ImportUtils; + +public class JavaLangImportInspection extends ClassInspection { + private final JavaLangImportFix fix = new JavaLangImportFix(); + + public String getDisplayName() { + return "java.lang import"; + } + + public String getGroupDisplayName() { + return GroupNames.IMPORTS_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "Unnecessary import from package java.lang #loc"; + } + + public InspectionGadgetsFix buildFix(PsiElement location) { + return fix; + } + + private static class JavaLangImportFix extends InspectionGadgetsFix { + public String getName() { + return "Delete unnecessary import"; + } + + public void applyFix(Project project, ProblemDescriptor descriptor) { + final PsiElement importReference = descriptor.getPsiElement(); + final PsiElement importStatement = importReference.getParent(); + deleteElement(importStatement); + } + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new JavaLangImportVisitor(this, inspectionManager, onTheFly); + } + + private static class JavaLangImportVisitor extends BaseInspectionVisitor { + private JavaLangImportVisitor(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.getParent() instanceof PsiJavaFile)) { + return; + } + final PsiJavaFile file = (PsiJavaFile) aClass.getParent(); + if (!file.getClasses()[0].equals(aClass)) { + return; + } + final PsiImportList importList = file.getImportList(); + final PsiImportStatement[] importStatements = importList.getImportStatements(); + for (int i = 0; i < importStatements.length; i++) { + final PsiImportStatement importStatement = importStatements[i]; + final PsiJavaCodeReferenceElement reference = importStatement.getImportReference(); + if (reference != null) { + final String text = importStatement.getQualifiedName(); + if (text != null) { + if (importStatement.isOnDemand()) { + if ("java.lang".equals(text)) { + registerError(importStatement); + } + } else { + final int classNameIndex = text.lastIndexOf((int) '.'); + if (classNameIndex < 0) { + return; + } + final String parentName = text.substring(0, classNameIndex); + if ("java.lang".equals(parentName)) { + if (!ImportUtils.hasOnDemandImportConflict(text, file)) { + registerError(reference); + } + } + } + } + } + } + } + + } +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/imports/OnDemandImportInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/imports/OnDemandImportInspection.java new file mode 100644 index 000000000000..6b1ada3acb49 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/imports/OnDemandImportInspection.java @@ -0,0 +1,59 @@ +package com.siyeh.ig.imports; + +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; + +public class OnDemandImportInspection extends ClassInspection { + + public String getDisplayName() { + return "* import"; + } + + public String getGroupDisplayName() { + return GroupNames.IMPORTS_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "Importing package #ref.* #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new PackageImportVisitor(this, inspectionManager, onTheFly); + } + + private static class PackageImportVisitor extends BaseInspectionVisitor { + private PackageImportVisitor(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.getParent() instanceof PsiJavaFile)) { + return; + } + final PsiJavaFile file = (PsiJavaFile) aClass.getParent(); + if (!file.getClasses()[0].equals(aClass)) { + return; + } + final PsiImportList importList = file.getImportList(); + if (importList != null) { + final PsiImportStatement[] importStatements = importList.getImportStatements(); + for (int i = 0; i < importStatements.length; i++) { + final PsiImportStatement importStatement = importStatements[i]; + final PsiJavaCodeReferenceElement reference = importStatement.getImportReference(); + + if (importStatement.isOnDemand()) { + if (reference != null) { + registerError(reference); + } + } + } + } + } + + } +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/imports/RedundantImportInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/imports/RedundantImportInspection.java new file mode 100644 index 000000000000..af84e0ef3e18 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/imports/RedundantImportInspection.java @@ -0,0 +1,92 @@ +package com.siyeh.ig.imports; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.codeInspection.ProblemDescriptor; +import com.intellij.psi.*; +import com.intellij.openapi.project.Project; +import com.siyeh.ig.*; +import com.siyeh.ig.psiutils.ImportUtils; + +import java.util.HashSet; +import java.util.Set; + +public class RedundantImportInspection extends ClassInspection { + private final RedundantImportFix fix = new RedundantImportFix(); + + public String getDisplayName() { + return "Redundant import"; + } + + public String getGroupDisplayName() { + return GroupNames.IMPORTS_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "Redundant import #ref #loc"; + } + + public InspectionGadgetsFix buildFix(PsiElement location) { + return fix; + } + + private static class RedundantImportFix extends InspectionGadgetsFix { + public String getName() { + return "Delete redundant import"; + } + + public void applyFix(Project project, ProblemDescriptor descriptor) { + final PsiElement importReference = descriptor.getPsiElement(); + final PsiElement importStatement = importReference.getParent(); + deleteElement(importStatement); + } + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new RedundantImportVisitor(this, inspectionManager, onTheFly); + } + + private static class RedundantImportVisitor extends BaseInspectionVisitor { + private RedundantImportVisitor(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.getParent() instanceof PsiJavaFile)) { + return; + } + final PsiJavaFile file = (PsiJavaFile) aClass.getParent(); + if (!file.getClasses()[0].equals(aClass)) { + return; + } + final PsiImportList importList = file.getImportList(); + final PsiImportStatement[] importStatements = importList.getImportStatements(); + final Set imports = new HashSet(importStatements.length); + for (int i = 0; i < importStatements.length; i++) { + final PsiImportStatement importStatement = importStatements[i]; + final String text = importStatement.getQualifiedName(); + if (text == null) { + return; + } + if (imports.contains(text)) { + registerError(importStatement); + } + if (!importStatement.isOnDemand()) { + final int classNameIndex = text.lastIndexOf((int) '.'); + if (classNameIndex < 0) { + return; + } + final String parentName = text.substring(0, classNameIndex); + if (imports.contains(parentName)) { + if (!ImportUtils.hasOnDemandImportConflict(text, file)) { + final PsiJavaCodeReferenceElement importReference = importStatement.getImportReference(); + registerError(importReference); + } + } + } + imports.add(text); + } + } + + } +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/imports/SamePackageImportInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/imports/SamePackageImportInspection.java new file mode 100644 index 000000000000..489f982cc662 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/imports/SamePackageImportInspection.java @@ -0,0 +1,83 @@ +package com.siyeh.ig.imports; + +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 SamePackageImportInspection extends ClassInspection { + private final SamePackageImportFix fix = new SamePackageImportFix(); + + public String getDisplayName() { + return "Import from same package"; + } + + public String getGroupDisplayName() { + return GroupNames.IMPORTS_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "Unnecessary import from same package package #loc"; + } + + public InspectionGadgetsFix buildFix(PsiElement location) { + return fix; + } + + private static class SamePackageImportFix extends InspectionGadgetsFix { + public String getName() { + return "Delete unnecessary import"; + } + + public void applyFix(Project project, ProblemDescriptor descriptor) { + + final PsiElement importReference = descriptor.getPsiElement(); + final PsiElement importStatement = importReference.getParent(); + deleteElement(importStatement); + } + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new SamePackageImportVisitor(this, inspectionManager, onTheFly); + } + + private static class SamePackageImportVisitor extends BaseInspectionVisitor { + private SamePackageImportVisitor(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.getParent() instanceof PsiJavaFile)) { + return; + } + final PsiJavaFile file = (PsiJavaFile) aClass.getParent(); + if (!file.getClasses()[0].equals(aClass)) { + return; + } + final String packageName = file.getPackageName(); + final PsiImportList importList = file.getImportList(); + final PsiImportStatement[] importStatements = importList.getImportStatements(); + for (int i = 0; i < importStatements.length; i++) { + final PsiImportStatement importStatement = importStatements[i]; + final PsiJavaCodeReferenceElement reference = importStatement.getImportReference(); + if (reference != null) { + final String text = importStatement.getQualifiedName(); + if (importStatement.isOnDemand()) { + if (packageName.equals(text)) { + registerError(importStatement); + } + } else { + final int classNameIndex = text.lastIndexOf((int) '.'); + final String parentName = classNameIndex < 0 ? "" : text.substring(0, classNameIndex); + if (packageName.equals(parentName)) { + registerError(reference); + } + } + } + } + } + + } +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/imports/SingleClassImportInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/imports/SingleClassImportInspection.java new file mode 100644 index 000000000000..87e1d1e5b176 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/imports/SingleClassImportInspection.java @@ -0,0 +1,57 @@ +package com.siyeh.ig.imports; + +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; + +public class SingleClassImportInspection extends ClassInspection { + + public String getDisplayName() { + + return "Single class import"; + } + + public String getGroupDisplayName() { + return GroupNames.IMPORTS_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "Single class import: #ref #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new PackageImportVisitor(this, inspectionManager, onTheFly); + } + + private static class PackageImportVisitor extends BaseInspectionVisitor { + private PackageImportVisitor(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.getParent() instanceof PsiJavaFile)) { + return; + } + final PsiJavaFile file = (PsiJavaFile) aClass.getParent(); + if (!file.getClasses()[0].equals(aClass)) { + return; + } + final PsiImportList importList = file.getImportList(); + final PsiImportStatement[] importStatements = importList.getImportStatements(); + for (int i = 0; i < importStatements.length; i++) { + final PsiImportStatement importStatement = importStatements[i]; + if (!importStatement.isOnDemand()) { + final PsiJavaCodeReferenceElement reference = importStatement.getImportReference(); + if (reference != null) { + registerError(reference); + } + } + } + } + + } +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/imports/StaticImportInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/imports/StaticImportInspection.java new file mode 100644 index 000000000000..86638336874d --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/imports/StaticImportInspection.java @@ -0,0 +1,54 @@ +package com.siyeh.ig.imports; + +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; + +public class StaticImportInspection extends ClassInspection { + + public String getDisplayName() { + return "Static import"; + } + + public String getGroupDisplayName() { + return GroupNames.IMPORTS_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "Static import #ref #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new PackageImportVisitor(this, inspectionManager, onTheFly); + } + + private static class PackageImportVisitor extends BaseInspectionVisitor { + private PackageImportVisitor(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.getParent() instanceof PsiJavaFile)) { + return; + } + final PsiJavaFile file = (PsiJavaFile) aClass.getParent(); + if (!file.getClasses()[0].equals(aClass)) { + return; + } + final PsiImportList importList = file.getImportList(); + final PsiImportStaticStatement[] importStatements = importList.getImportStaticStatements(); + for (int i = 0; i < importStatements.length; i++) { + final PsiImportStaticStatement importStatement = importStatements[i]; + final PsiJavaCodeReferenceElement reference = importStatement.getImportReference(); + if (reference != null) { + registerError(reference); + } + } + } + + } +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/imports/UnusedImportInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/imports/UnusedImportInspection.java new file mode 100644 index 000000000000..b6c12651e2b4 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/imports/UnusedImportInspection.java @@ -0,0 +1,83 @@ +package com.siyeh.ig.imports; + +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 UnusedImportInspection extends ClassInspection { + private final UnusedImportFix fix = new UnusedImportFix(); + + public String getDisplayName() { + return "Unused import"; + } + + public String getGroupDisplayName() { + return GroupNames.IMPORTS_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "Unused import #ref #loc"; + } + + public InspectionGadgetsFix buildFix(PsiElement location) { + return fix; + } + + private static class UnusedImportFix extends InspectionGadgetsFix { + public String getName() { + return "Delete unused import"; + } + + public void applyFix(Project project, ProblemDescriptor descriptor) { + final PsiElement importReference = descriptor.getPsiElement(); + final PsiElement importStatement = importReference.getParent(); + deleteElement(importStatement); + } + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new UnusedImportVisitor(this, inspectionManager, onTheFly); + } + + private static class UnusedImportVisitor extends BaseInspectionVisitor { + private UnusedImportVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitClass(PsiClass aClass) { + if (!(aClass.getParent() instanceof PsiJavaFile)) { + return; + } + final PsiJavaFile file = (PsiJavaFile) aClass.getParent(); + if (!file.getClasses()[0].equals(aClass)) { + return; + } + final PsiImportList importList = file.getImportList(); + final PsiImportStatement[] importStatements = importList.getImportStatements(); + for (int i = 0; i < importStatements.length; i++) { + final PsiImportStatement importStatement = importStatements[i]; + if (!isNecessaryImport(importStatement, file.getClasses())) { + final PsiJavaCodeReferenceElement importReference + = importStatement.getImportReference(); + + registerError(importReference); + } + } + } + + private static boolean isNecessaryImport(PsiImportStatement importStatement, PsiClass[] classes) { + final ImportIsUsedVisitor visitor = new ImportIsUsedVisitor(importStatement); + for (int i = 0; i < classes.length; i++) { + classes[i].accept(visitor); + final PsiClass[] innerClasses = classes[i].getInnerClasses(); + for (int j = 0; j < innerClasses.length; j++) { + innerClasses[j].accept(visitor); + } + } + return visitor.isUsed(); + } + + } +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/initialization/AbstractMethodCallInConstructorInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/initialization/AbstractMethodCallInConstructorInspection.java new file mode 100644 index 000000000000..3eba53fb4a68 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/initialization/AbstractMethodCallInConstructorInspection.java @@ -0,0 +1,65 @@ +package com.siyeh.ig.initialization; + +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.GroupNames; +import com.siyeh.ig.MethodInspection; + +public class AbstractMethodCallInConstructorInspection extends MethodInspection { + + public String getDisplayName() { + return "Abstract method call in constructor"; + } + + public String getGroupDisplayName() { + return GroupNames.INITIALIZATION_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "Call to abstract method #ref during object construction #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new AbstractMethodCallInConstructorVisitor(this, inspectionManager, onTheFly); + } + + private static class AbstractMethodCallInConstructorVisitor extends BaseInspectionVisitor { + private AbstractMethodCallInConstructorVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitMethodCallExpression(PsiMethodCallExpression call) { + super.visitMethodCallExpression(call); + final PsiMethod method = (PsiMethod) PsiTreeUtil.getParentOfType(call, PsiMethod.class); + if (method == null) { + return; + } + if (!method.isConstructor()) { + return; + } + final PsiReferenceExpression methodExpression = call.getMethodExpression(); + if (methodExpression == null) { + return; + } + final PsiMethod calledMethod = (PsiMethod) methodExpression.resolve(); + if (calledMethod == null) { + return; + } + if (calledMethod.isConstructor()) { + return; + } + if (!calledMethod.hasModifierProperty(PsiModifier.ABSTRACT)) { + return; + } + final PsiClass calledMethodClass = calledMethod.getContainingClass(); + final PsiClass methodClass = method.getContainingClass(); + if (!calledMethodClass.equals(methodClass)) { + return; + } + registerMethodCallError(call); + } + } +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/initialization/InstanceVariableInitializationInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/initialization/InstanceVariableInitializationInspection.java new file mode 100644 index 000000000000..b8cbb4382b6d --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/initialization/InstanceVariableInitializationInspection.java @@ -0,0 +1,101 @@ +package com.siyeh.ig.initialization; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.psi.*; +import com.intellij.psi.search.PsiSearchHelper; +import com.siyeh.ig.BaseInspection; +import com.siyeh.ig.BaseInspectionVisitor; +import com.siyeh.ig.FieldInspection; +import com.siyeh.ig.GroupNames; +import com.siyeh.ig.psiutils.ClassUtils; +import com.siyeh.ig.psiutils.InitializationUtils; +import com.siyeh.ig.ui.SingleCheckboxOptionsPanel; + +import javax.swing.*; + +public class InstanceVariableInitializationInspection extends FieldInspection { + public boolean m_ignorePrimitives = false; + + public String getDisplayName() { + return "Instance variable may not be initialized"; + } + + public String getGroupDisplayName() { + return GroupNames.INITIALIZATION_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "Instance variable #ref may not be initialized during object construction #loc"; + } + + public JComponent createOptionsPanel() { + return new SingleCheckboxOptionsPanel("Ignore primitive fields", + this, "m_ignorePrimitives"); + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new InstanceVariableInitializationVisitor(this, inspectionManager, onTheFly); + } + + private class InstanceVariableInitializationVisitor extends BaseInspectionVisitor { + private InstanceVariableInitializationVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitField(PsiField field) { + if (field.hasModifierProperty(PsiModifier.STATIC)) { + return; + } + if (field.getInitializer() != null) { + return; + } + if (m_ignorePrimitives && ClassUtils.isPrimitive(field.getType())) { + return; + } + final PsiClass aClass = field.getContainingClass(); + if (aClass == null) { + return; + } + final PsiManager manager = field.getManager(); + final PsiSearchHelper searchHelper = manager.getSearchHelper(); + if (searchHelper.isFieldBoundToForm(field)) { + return; + } + if (isInitializedInInitializer(field)) { + return; + } + + final PsiMethod[] constructors = aClass.getConstructors(); + if (constructors == null || constructors.length == 0) { + registerFieldError(field); + return; + } + + for (int i = 0; i < constructors.length; i++) { + final PsiMethod constructor = constructors[i]; + final PsiCodeBlock body = constructor.getBody(); + if (!InitializationUtils.blockMustAssignVariable(field, body)) { + registerFieldError(field); + return; + } + } + + } + + private boolean isInitializedInInitializer(PsiField field) { + final PsiClass aClass = field.getContainingClass(); + final PsiClassInitializer[] initializers = aClass.getInitializers(); + for (int i = 0; i < initializers.length; i++) { + final PsiClassInitializer initializer = initializers[i]; + if (!initializer.hasModifierProperty(PsiModifier.STATIC)) { + final PsiCodeBlock body = initializer.getBody(); + if (InitializationUtils.blockMustAssignVariable(field, body)) { + return true; + } + } + } + return false; + } + + } +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/initialization/InstanceVariableUninitializedUseInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/initialization/InstanceVariableUninitializedUseInspection.java new file mode 100644 index 000000000000..650d54f0a786 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/initialization/InstanceVariableUninitializedUseInspection.java @@ -0,0 +1,107 @@ +package com.siyeh.ig.initialization; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.psi.*; +import com.intellij.psi.search.PsiSearchHelper; +import com.siyeh.ig.BaseInspection; +import com.siyeh.ig.BaseInspectionVisitor; +import com.siyeh.ig.FieldInspection; +import com.siyeh.ig.GroupNames; +import com.siyeh.ig.psiutils.ClassUtils; +import com.siyeh.ig.psiutils.InitializationReadUtils; +import com.siyeh.ig.ui.SingleCheckboxOptionsPanel; + +import javax.swing.*; + +public class InstanceVariableUninitializedUseInspection + extends FieldInspection { + public boolean m_ignorePrimitives = false; + + public String getDisplayName() { + return "Instance variable used before initialized"; + } + + public String getGroupDisplayName() { + return GroupNames.INITIALIZATION_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "Instance variable #ref used before initialized #loc"; + } + + public JComponent createOptionsPanel() { + return new SingleCheckboxOptionsPanel("Ignore primitive fields", + this, "m_ignorePrimitives"); + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new InstanceVariableInitializationVisitor(this, + inspectionManager, + onTheFly); + } + + private class InstanceVariableInitializationVisitor + extends BaseInspectionVisitor { + private InstanceVariableInitializationVisitor(BaseInspection inspection, InspectionManager inspectionManager, + boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + private InitializationReadUtils iru = new InitializationReadUtils(); + + public void visitField(PsiField field) { + if (field.hasModifierProperty(PsiModifier.STATIC)) { + return; + } + if (field.getInitializer() != null) { + return; + } + if (m_ignorePrimitives && + ClassUtils.isPrimitive(field.getType())) { + return; + } + final PsiClass aClass = field.getContainingClass(); + if (aClass == null) { + return; + } + final PsiManager manager = field.getManager(); + final PsiSearchHelper searchHelper = manager.getSearchHelper(); + if (searchHelper.isFieldBoundToForm(field)) { + return; + } + + if (!isInitializedInInitializer(field)) { + final PsiMethod[] constructors = aClass.getConstructors(); + + for (int i = 0; i < constructors.length; i++) { + final PsiMethod constructor = constructors[i]; + final PsiCodeBlock body = constructor.getBody(); + iru.blockMustAssignVariable(field, body); + } + } + + final java.util.List badReads = iru.getUninitializedReads(); + for (int i = 0; i < badReads.size(); i++) { + final PsiElement element = (PsiElement) badReads.get(i); + registerError(element); + } + + } + + private boolean isInitializedInInitializer(PsiField field) { + final PsiClass aClass = field.getContainingClass(); + final PsiClassInitializer[] initializers = aClass.getInitializers(); + for (int i = 0; i < initializers.length; i++) { + final PsiClassInitializer initializer = initializers[i]; + if (!initializer.hasModifierProperty(PsiModifier.STATIC)) { + final PsiCodeBlock body = initializer.getBody(); + if (iru.blockMustAssignVariable(field, body)) { + return true; + } + } + } + return false; + } + + } +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/initialization/OverridableMethodCallInConstructorInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/initialization/OverridableMethodCallInConstructorInspection.java new file mode 100644 index 000000000000..0e5f65f4c269 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/initialization/OverridableMethodCallInConstructorInspection.java @@ -0,0 +1,75 @@ +package com.siyeh.ig.initialization; + +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.GroupNames; +import com.siyeh.ig.MethodInspection; + +public class OverridableMethodCallInConstructorInspection extends MethodInspection { + + public String getDisplayName() { + return "Overridable method call in constructor"; + } + + public String getGroupDisplayName() { + return GroupNames.INITIALIZATION_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "Call to overridable method #ref during object construction #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new AbstractMethodCallInConstructorVisitor(this, inspectionManager, onTheFly); + } + + private static class AbstractMethodCallInConstructorVisitor extends BaseInspectionVisitor { + private AbstractMethodCallInConstructorVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitMethodCallExpression(PsiMethodCallExpression call) { + super.visitMethodCallExpression(call); + final PsiMethod method = (PsiMethod) PsiTreeUtil.getParentOfType(call, PsiMethod.class); + if (method == null) { + return; + } + if (!method.isConstructor()) { + return; + } + final PsiReferenceExpression methodExpression = call.getMethodExpression(); + if (methodExpression == null) { + return; + } + final PsiClass containingClass = method.getContainingClass(); + if (containingClass == null) { + return; + } + if (containingClass.hasModifierProperty(PsiModifier.FINAL)) { + return; + } + final PsiMethod calledMethod = (PsiMethod) methodExpression.resolve(); + if (calledMethod == null) { + return; + } + if (!isOverridable(calledMethod)) { + return; + } + final PsiClass calledMethodClass = calledMethod.getContainingClass(); + if (!calledMethodClass.equals(containingClass)) { + return; + } + registerMethodCallError(call); + } + + private static boolean isOverridable(PsiMethod calledMethod) { + return !calledMethod.isConstructor() && + !calledMethod.hasModifierProperty(PsiModifier.FINAL) && + !calledMethod.hasModifierProperty(PsiModifier.STATIC) && + !calledMethod.hasModifierProperty(PsiModifier.PRIVATE); + } + } +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/initialization/StaticVariableInitializationInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/initialization/StaticVariableInitializationInspection.java new file mode 100644 index 000000000000..138a216a570c --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/initialization/StaticVariableInitializationInspection.java @@ -0,0 +1,80 @@ +package com.siyeh.ig.initialization; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.psi.*; +import com.siyeh.ig.BaseInspection; +import com.siyeh.ig.BaseInspectionVisitor; +import com.siyeh.ig.FieldInspection; +import com.siyeh.ig.GroupNames; +import com.siyeh.ig.psiutils.ClassUtils; +import com.siyeh.ig.psiutils.InitializationUtils; +import com.siyeh.ig.ui.SingleCheckboxOptionsPanel; + +import javax.swing.*; + +public class StaticVariableInitializationInspection extends FieldInspection { + public boolean m_ignorePrimitives = false; + + public String getDisplayName() { + return "Static variable may not be initialized"; + } + + public String getGroupDisplayName() { + return GroupNames.INITIALIZATION_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "Static variable #ref may not be initialized during class initialization #loc"; + } + + public JComponent createOptionsPanel() { + return new SingleCheckboxOptionsPanel("Ignore primitive fields", + this, "m_ignorePrimitives"); + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new StaticVariableInitializationVisitor(this, inspectionManager, onTheFly); + } + + private class StaticVariableInitializationVisitor extends BaseInspectionVisitor { + private StaticVariableInitializationVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitField(PsiField field) { + if (!field.hasModifierProperty(PsiModifier.STATIC)) { + return; + } + if (field.getInitializer() != null) { + return; + } + final PsiClass containingClass = field.getContainingClass(); + + if (containingClass == null) { + return; + } + if (containingClass.isEnum()) { + return; + } + if (m_ignorePrimitives) { + final PsiType type = field.getType(); + if (ClassUtils.isPrimitive(type)) { + return; + } + } + + final PsiClassInitializer[] initializers = containingClass.getInitializers(); + for (int i = 0; i < initializers.length; i++) { + final PsiClassInitializer initializer = initializers[i]; + if (initializer.hasModifierProperty(PsiModifier.STATIC)) { + final PsiCodeBlock body = initializer.getBody(); + if (InitializationUtils.blockMustAssignVariable(field, body)) { + return; + } + } + } + registerFieldError(field); + } + + } +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/initialization/StaticVariableUninitializedUseInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/initialization/StaticVariableUninitializedUseInspection.java new file mode 100644 index 000000000000..74f3e0ec081d --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/initialization/StaticVariableUninitializedUseInspection.java @@ -0,0 +1,93 @@ +package com.siyeh.ig.initialization; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.psi.*; +import com.siyeh.ig.BaseInspection; +import com.siyeh.ig.BaseInspectionVisitor; +import com.siyeh.ig.FieldInspection; +import com.siyeh.ig.GroupNames; +import com.siyeh.ig.psiutils.ClassUtils; +import com.siyeh.ig.psiutils.InitializationReadUtils; +import com.siyeh.ig.ui.SingleCheckboxOptionsPanel; + +import javax.swing.*; +import java.util.List; + +public class StaticVariableUninitializedUseInspection extends FieldInspection { + public boolean m_ignorePrimitives = false; + + public String getDisplayName() { + return "Static variable used before initialization"; + } + + public String getGroupDisplayName() { + return GroupNames.INITIALIZATION_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "Static variable #ref used before initialization #loc"; + } + + public JComponent createOptionsPanel() { + return new SingleCheckboxOptionsPanel("Ignore primitive fields", + this, "m_ignorePrimitives"); + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new StaticVariableInitializationVisitor(this, inspectionManager, + onTheFly); + } + + private class StaticVariableInitializationVisitor + extends BaseInspectionVisitor { + private StaticVariableInitializationVisitor(BaseInspection inspection, + InspectionManager inspectionManager, + boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitField(PsiField field) { + if (!field.hasModifierProperty(PsiModifier.STATIC)) { + return; + } + if (field.getInitializer() != null) { + return; + } + final PsiClass containingClass = field.getContainingClass(); + + if (containingClass == null) { + return; + } + if (containingClass.isEnum()) { + return; + } + if (m_ignorePrimitives) { + final PsiType type = field.getType(); + if (ClassUtils.isPrimitive(type)) { + return; + } + } + final PsiClassInitializer[] initializers = containingClass.getInitializers(); + // Do the static initializers come in actual order in file? (They need to.) + final InitializationReadUtils iru; + iru = new InitializationReadUtils(); + + for (int i = 0; i < initializers.length; i++) { + final PsiClassInitializer initializer = initializers[i]; + if (initializer.hasModifierProperty(PsiModifier.STATIC)) { + final PsiCodeBlock body = initializer.getBody(); + if (iru.blockMustAssignVariable(field, body)) { + break; + } + } + } + + final List badReads = iru.getUninitializedReads(); + for (int i = 0; i < badReads.size(); i++) { + final PsiElement element = (PsiElement) badReads.get(i); + registerError(element); + } + } + + } +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/initialization/ThisEscapedInConstructorInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/initialization/ThisEscapedInConstructorInspection.java new file mode 100644 index 000000000000..01687d029891 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/initialization/ThisEscapedInConstructorInspection.java @@ -0,0 +1,240 @@ +package com.siyeh.ig.initialization; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.psi.*; +import com.intellij.psi.util.PsiTreeUtil; +import com.siyeh.ig.*; +import com.siyeh.ig.psiutils.ClassUtils; + +public class ThisEscapedInConstructorInspection extends ClassInspection { + + public String getDisplayName() { + return "'this' reference escaped in constructor"; + } + + public String getGroupDisplayName() { + return GroupNames.INITIALIZATION_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "Escape of '#ref' during object construction #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new ThisExposedInConstructorInspectionVisitor(this, + inspectionManager, + onTheFly); + } + + private static class ThisExposedInConstructorInspectionVisitor + extends BaseInspectionVisitor { + private boolean m_inClass = false; + + private ThisExposedInConstructorInspectionVisitor(BaseInspection inspection, InspectionManager inspectionManager, + boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitClass(PsiClass aClass) { + final boolean wasInClass = m_inClass; + if (!m_inClass) { + + m_inClass = true; + super.visitClass(aClass); + } + m_inClass = wasInClass; + } + + public void visitNewExpression(PsiNewExpression psiNewExpression) { + + super.visitNewExpression(psiNewExpression); + + final PsiMember methodOrInitializer = checkConstructorOrInstanceInitializer(psiNewExpression); + if (methodOrInitializer == null) { + return; + } + + if (psiNewExpression.getClassReference() == null) { + return; + } + + final PsiThisExpression thisExposed = checkArgumentsForThis(psiNewExpression); + if (thisExposed == null) { + return; + } + + final PsiJavaCodeReferenceElement refElement = psiNewExpression.getClassReference(); + if (refElement != null) { + final PsiClass constructorClass = (PsiClass) refElement.resolve(); + + if (constructorClass != null) { + // Skips inner classes and containing classes (as well as top level package class with file-named class) + if (constructorClass.getContainingFile().equals(psiNewExpression.getContainingFile())) { + return; + } + } + } + + registerError(thisExposed); + } + + public void visitAssignmentExpression(PsiAssignmentExpression assignment) { + + super.visitAssignmentExpression(assignment); + + final PsiMember methodOrInitializer = checkConstructorOrInstanceInitializer(assignment); + if (methodOrInitializer == null) { + return; + } + + final PsiExpression psiExpression = getLastRightExpression(assignment); + + if (psiExpression == null || + !(psiExpression instanceof PsiThisExpression)) { + return; + } + final PsiThisExpression thisExpression = (PsiThisExpression) psiExpression; + + // Need to confirm that LeftExpression is outside of class relatives + if (!(assignment.getLExpression() instanceof PsiReferenceExpression)) { + return; + } + final PsiReferenceExpression leftExpression = (PsiReferenceExpression) assignment.getLExpression(); + if (!(leftExpression.resolve() instanceof PsiField)) { + return; + } + final PsiField field = (PsiField) leftExpression.resolve(); + + if (field.getContainingFile().equals(assignment.getContainingFile())) { + return; + } + + // Inheritance check + final PsiClass cls = ClassUtils.getContainingClass(assignment); + if (cls.isInheritor(field.getContainingClass(), true)) { + return; + } + + registerError(thisExpression); + } + + public void visitMethodCallExpression(PsiMethodCallExpression call) { + super.visitMethodCallExpression(call); + + final PsiMember methodOrInitializer = checkConstructorOrInstanceInitializer(call); + if (methodOrInitializer == null) { + return; + } + + final PsiReferenceExpression methodExpression = call.getMethodExpression(); + if (methodExpression == null) { + return; + } + final PsiMethod calledMethod = call.resolveMethod(); + if (calledMethod == null) { + return; + } + if (calledMethod.isConstructor()) { + return; + } + + final PsiClass calledMethodClass = calledMethod.getContainingClass(); + final PsiClass methodClass = methodOrInitializer.getContainingClass(); + + if (calledMethodClass.equals(methodClass)) // compares class types statically? + { + return; + } + final PsiThisExpression thisExposed = checkArgumentsForThis(call); + if (thisExposed == null) { + return; + } + + // Methods - static or not - from superclasses don't trigger + if (methodClass.isInheritor(calledMethodClass, true)) { + return; + } + + // Make sure using this with members of self or superclasses doesn't trigger + final PsiExpression qualifier = methodExpression.getQualifierExpression(); + if (!(qualifier instanceof PsiReferenceExpression)) { + return; + } + final PsiReferenceExpression qualifiedExpression = + (PsiReferenceExpression) qualifier; + final PsiElement referent = qualifiedExpression.resolve(); + if (referent instanceof PsiField) { + final PsiField field = (PsiField) referent; + final PsiClass containingClass = field.getContainingClass(); + + if (methodClass.equals(containingClass) || + methodClass.isInheritor(containingClass, true)) { + return; + } + } + + registerError(thisExposed); + } + + // Get rightmost expression of assignment. Used when assignments are chained. Recursive + private static PsiExpression getLastRightExpression(PsiAssignmentExpression assignmentExp) { + + if (assignmentExp == null) { + return null; + } + + final PsiExpression expression = assignmentExp.getRExpression(); + if (expression == null) { + return null; + } + + if (expression instanceof PsiAssignmentExpression) { + return getLastRightExpression((PsiAssignmentExpression) expression); + } + return expression; + } + + /** + * @param call + * @return null unless CallExpression is a Constructor or an Instance + * Initializer. Otherwise it returns the PsiMember representing + * the contructor/initializer + */ + private static PsiMember checkConstructorOrInstanceInitializer(PsiElement call) { + final PsiMethod method = (PsiMethod) PsiTreeUtil.getParentOfType(call, PsiMethod.class); + PsiMember methodOrInitializer = method; + if (method == null) { + final PsiClassInitializer classInitializer = (PsiClassInitializer) PsiTreeUtil.getParentOfType(call, PsiClassInitializer.class); + if (classInitializer == null) { + return null; + } + if (classInitializer.hasModifierProperty(PsiModifier.STATIC)) { + return null; + } + methodOrInitializer = classInitializer; + + } else if (!method.isConstructor()) { + return null; + } + return methodOrInitializer; + } + + // If there are more than two of 'this' as arguments, only marks the first until it is removed. No big deal. + private static PsiThisExpression checkArgumentsForThis(PsiCall call) { + final PsiExpressionList peList = call.getArgumentList(); + if (peList == null) { // array initializer + return null; + } + final PsiExpression[] argExpressions = peList.getExpressions(); + for (int i = 0; i < argExpressions.length; i++) { + final PsiExpression argExpression = argExpressions[i]; + + if (argExpression instanceof PsiThisExpression) { + return (PsiThisExpression) argExpression; + } + } + return null; + } + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/internationalization/CharacterComparisonInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/internationalization/CharacterComparisonInspection.java new file mode 100644 index 000000000000..543495a4dd67 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/internationalization/CharacterComparisonInspection.java @@ -0,0 +1,93 @@ +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 java.util.HashSet; +import java.util.Set; + +public class CharacterComparisonInspection extends ExpressionInspection { + + private static final Set s_comparisonOperators = new HashSet(4); + + static { + s_comparisonOperators.add(">"); + s_comparisonOperators.add("<"); + s_comparisonOperators.add(">="); + s_comparisonOperators.add("<="); + } + + private static boolean isComparison(String operator) { + return s_comparisonOperators.contains(operator); + } + + public String getDisplayName() { + return "Character comparison"; + } + + public String getGroupDisplayName() { + return GroupNames.INTERNATIONALIZATION_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "Character comparison #ref in an internationalized context #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new CharacterComparisonVisitor(this, inspectionManager, onTheFly); + } + + private static class CharacterComparisonVisitor extends BaseInspectionVisitor { + private CharacterComparisonVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitBinaryExpression(PsiBinaryExpression expression) { + super.visitBinaryExpression(expression); + final PsiJavaToken sign = expression.getOperationSign(); + if (sign == null) { + return; + } + final String operand = sign.getText(); + if (!isComparison(operand)) { + return; + } + final PsiExpression lhs = expression.getLOperand(); + if (!isCharacter(lhs)) { + return; + } + final PsiExpression rhs = expression.getROperand(); + if (rhs == null) { + return; + } + final PsiType rhsType = rhs.getType(); + if (rhsType == null) { + return; + } + if (!rhsType.equals(PsiType.CHAR)) { + return; + } + registerError(expression); + + } + } + + private static boolean isCharacter(PsiExpression lhs) { + + if (lhs == null) { + return false; + } + final PsiType lhsType = lhs.getType(); + if (lhsType == null) { + return false; + } + final String text = lhsType.getCanonicalText(); + return "char".equals(text) || + "java.lang.Character".equals(text); + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/internationalization/DateToStringInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/internationalization/DateToStringInspection.java new file mode 100644 index 000000000000..6b84a4556647 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/internationalization/DateToStringInspection.java @@ -0,0 +1,56 @@ +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.MethodCallUtils; +import com.siyeh.ig.psiutils.TypeUtils; + +public class DateToStringInspection extends ExpressionInspection { + + public String getDisplayName() { + return "Call to Date.toString()"; + } + + public String getGroupDisplayName() { + return GroupNames.INTERNATIONALIZATION_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "Date.#ref() used in an internationalized context #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new DateToStringVisitor(this, inspectionManager, onTheFly); + } + + private static class DateToStringVisitor extends BaseInspectionVisitor { + private DateToStringVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitMethodCallExpression(PsiMethodCallExpression expression) { + super.visitMethodCallExpression(expression); + final String methodName = MethodCallUtils.getMethodName(expression); + if (!"toString".equals(methodName)) { + return; + } + final PsiType targetType = MethodCallUtils.getTargetType(expression); + if (!TypeUtils.typeEquals("java.util.Date", targetType)) { + return; + } + final PsiExpressionList argumentList = expression.getArgumentList(); + if (argumentList == null) { + return; + } + if (argumentList.getExpressions().length != 0) { + return; + } + registerMethodCallError(expression); + } + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/internationalization/MagicCharacterInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/internationalization/MagicCharacterInspection.java new file mode 100644 index 000000000000..b95c2b014812 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/internationalization/MagicCharacterInspection.java @@ -0,0 +1,88 @@ +package com.siyeh.ig.internationalization; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.psi.*; +import com.intellij.psi.util.PsiTreeUtil; +import com.siyeh.ig.*; +import com.siyeh.ig.fixes.IntroduceConstantFix; + +import java.util.HashSet; +import java.util.Set; + +public class MagicCharacterInspection extends ExpressionInspection { + + private static final Set s_specialCaseLiterals = new HashSet(1); + private final IntroduceConstantFix fix = new IntroduceConstantFix(); + + static { + s_specialCaseLiterals.add(" "); + } + + public String getDisplayName() { + return "\"Magic character\""; + } + + public String getGroupDisplayName() { + return GroupNames.INTERNATIONALIZATION_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "\"Magic character\" #ref in an internationalized context #loc"; + } + + protected InspectionGadgetsFix buildFix(PsiElement location) { + return fix; + } + + protected boolean buildQuickFixesOnlyForOnTheFlyErrors() { + return true; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new CharacterLiteralsShouldBeExplicitlyDeclaredVisitor(this, inspectionManager, onTheFly); + } + + private static class CharacterLiteralsShouldBeExplicitlyDeclaredVisitor extends BaseInspectionVisitor { + private CharacterLiteralsShouldBeExplicitlyDeclaredVisitor(BaseInspection inspection, + InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitLiteralExpression(PsiLiteralExpression expression) { + super.visitLiteralExpression(expression); + final PsiType type = expression.getType(); + if (type == null) { + return; + } + if (!type.equals(PsiType.CHAR)) { + return; + } + final String text = expression.getText(); + if (text == null) { + return; + } + if (isSpecialCase(text)) { + return; + } + if (isDeclaredConstant(expression)) { + return; + } + registerError(expression); + } + + private static boolean isSpecialCase(String text) { + return s_specialCaseLiterals.contains(text); + } + + private static boolean isDeclaredConstant(PsiLiteralExpression expression) { + final PsiField field = + (PsiField) PsiTreeUtil.getParentOfType(expression, PsiField.class); + if (field == null) { + return false; + } + return field.hasModifierProperty(PsiModifier.STATIC) && + field.hasModifierProperty(PsiModifier.FINAL); + } + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/internationalization/NumericToStringInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/internationalization/NumericToStringInspection.java new file mode 100644 index 000000000000..e6480467810d --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/internationalization/NumericToStringInspection.java @@ -0,0 +1,65 @@ +package com.siyeh.ig.internationalization; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.psi.*; +import com.intellij.psi.util.TypeConversionUtil; +import com.siyeh.ig.BaseInspection; +import com.siyeh.ig.BaseInspectionVisitor; +import com.siyeh.ig.ExpressionInspection; +import com.siyeh.ig.GroupNames; + +public class NumericToStringInspection extends ExpressionInspection { + + public String getDisplayName() { + return "Call to Numeric .toString()"; + } + + public String getGroupDisplayName() { + return GroupNames.INTERNATIONALIZATION_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "Numeric .#ref() called in an internationalized context #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new NumericToStringVisitor(this, inspectionManager, onTheFly); + } + + private static class NumericToStringVisitor extends BaseInspectionVisitor { + private NumericToStringVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitMethodCallExpression(PsiMethodCallExpression expression) { + super.visitMethodCallExpression(expression); + final PsiReferenceExpression methodExpression = expression.getMethodExpression(); + if (methodExpression == null) { + return; + } + final String methodName = methodExpression.getReferenceName(); + if (!"toString".equals(methodName)) { + return; + } + final PsiMethod method = expression.resolveMethod(); + if (method == null) { + return; + } + final PsiParameterList paramList = method.getParameterList(); + if (paramList == null) { + return; + } + final PsiParameter[] parameters = paramList.getParameters(); + if (parameters.length != 0) { + return; + } + final PsiClass aClass = method.getContainingClass(); + final String className = aClass.getQualifiedName(); + if (!TypeConversionUtil.isPrimitiveWrapper(className)) { + return; + } + registerMethodCallError(expression); + } + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/internationalization/StringCompareToInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/internationalization/StringCompareToInspection.java new file mode 100644 index 000000000000..ff0a14ddf3f6 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/internationalization/StringCompareToInspection.java @@ -0,0 +1,86 @@ +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 StringCompareToInspection extends ExpressionInspection { + + public String getDisplayName() { + return "Call to String.compareTo()"; + } + + public String getGroupDisplayName() { + return GroupNames.INTERNATIONALIZATION_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "String.#ref() called in an internationalized context #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new StringCompareToVisitor(this, inspectionManager, onTheFly); + } + + private static class StringCompareToVisitor extends BaseInspectionVisitor { + private StringCompareToVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitMethodCallExpression(PsiMethodCallExpression expression) { + super.visitMethodCallExpression(expression); + final PsiReferenceExpression methodExpression = expression.getMethodExpression(); + if (methodExpression == null) { + return; + } + + if (!isStringCompareTo(expression)) { + return; + } + + registerMethodCallError(expression); + } + + private static boolean isStringCompareTo(PsiMethodCallExpression expression) { + final PsiReferenceExpression methodExpression = expression.getMethodExpression(); + if (methodExpression == null) { + return false; + } + final String methodName = methodExpression.getReferenceName(); + if (!"compareTo".equals(methodName)) { + return false; + } + final PsiMethod method = expression.resolveMethod(); + if (method == null) { + return false; + } + final PsiParameterList paramList = method.getParameterList(); + if (paramList == null) { + return false; + } + final PsiParameter[] parameters = paramList.getParameters(); + if (parameters.length != 1) { + return false; + } + final PsiType parameterType = parameters[0].getType(); + if (!TypeUtils.isJavaLangObject(parameterType) && + !TypeUtils.isJavaLangString(parameterType)) { + return false; + } + final PsiClass aClass = method.getContainingClass(); + if (aClass == null) { + return false; + } + final String className = aClass.getQualifiedName(); + if (!"java.lang.String".equals(className)) { + return false; + } + return true; + } + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/internationalization/StringConcatenationInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/internationalization/StringConcatenationInspection.java new file mode 100644 index 000000000000..66801a3f0479 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/internationalization/StringConcatenationInspection.java @@ -0,0 +1,67 @@ +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 StringConcatenationInspection extends ExpressionInspection { + + public String getDisplayName() { + return "String concatenation"; + } + + public String getGroupDisplayName() { + return GroupNames.INTERNATIONALIZATION_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "String concatenation (#ref) in an internationalized context #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new StringConcatenationVisitor(this, inspectionManager, onTheFly); + } + + private static class StringConcatenationVisitor extends BaseInspectionVisitor { + private StringConcatenationVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitBinaryExpression(PsiBinaryExpression expression) { + super.visitBinaryExpression(expression); + final PsiJavaToken sign = expression.getOperationSign(); + if (sign == null) { + return; + } + if (sign.getTokenType() != JavaTokenType.PLUS) { + return; + } + final PsiExpression lhs = expression.getLOperand(); + if (lhs == null) { + return; + } + final PsiType lhsType = lhs.getType(); + if (TypeUtils.isJavaLangString(lhsType)) { + registerError(sign); + return; + } + + final PsiExpression rhs = expression.getROperand(); + if (rhs == null) { + return; + } + final PsiType rhsType = rhs.getType(); + if (TypeUtils.isJavaLangString(rhsType)) { + registerError(sign); + return; + } + + } + + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/internationalization/StringEqualsIgnoreCaseInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/internationalization/StringEqualsIgnoreCaseInspection.java new file mode 100644 index 000000000000..4f9b47834cf4 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/internationalization/StringEqualsIgnoreCaseInspection.java @@ -0,0 +1,72 @@ +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 StringEqualsIgnoreCaseInspection extends ExpressionInspection { + + public String getDisplayName() { + return "Call to String.equalsIgnoreCase()"; + } + + public String getGroupDisplayName() { + return GroupNames.INTERNATIONALIZATION_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "String.#ref() in an internationalized context #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new StringEqualsIgnoreCaseVisitor(this, inspectionManager, onTheFly); + } + + private static class StringEqualsIgnoreCaseVisitor extends BaseInspectionVisitor { + private StringEqualsIgnoreCaseVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitMethodCallExpression(PsiMethodCallExpression expression) { + super.visitMethodCallExpression(expression); + final PsiReferenceExpression methodExpression = expression.getMethodExpression(); + if (methodExpression == null) { + return; + } + final String methodName = methodExpression.getReferenceName(); + if (!"equalsIgnoreCase".equals(methodName)) { + return; + } + final PsiMethod method = expression.resolveMethod(); + if (method == null) { + return; + } + final PsiParameterList paramList = method.getParameterList(); + if (paramList == null) { + return; + } + final PsiParameter[] parameters = paramList.getParameters(); + if (parameters.length != 1) { + return; + } + final PsiType parameterType = parameters[0].getType(); + if (!TypeUtils.isJavaLangString(parameterType)) { + return; + } + final PsiClass aClass = method.getContainingClass(); + if (aClass == null) { + return; + } + final String className = aClass.getQualifiedName(); + if (!"java.lang.String".equals(className)) { + return; + } + registerMethodCallError(expression); + } + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/internationalization/StringEqualsInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/internationalization/StringEqualsInspection.java new file mode 100644 index 000000000000..8056d6007e74 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/internationalization/StringEqualsInspection.java @@ -0,0 +1,69 @@ +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 StringEqualsInspection extends ExpressionInspection { + + public String getDisplayName() { + return "Call to String.equals()"; + } + + public String getGroupDisplayName() { + return GroupNames.INTERNATIONALIZATION_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "String.#ref() in an internationalized context #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new StringEqualsVisitor(this, inspectionManager, onTheFly); + } + + private static class StringEqualsVisitor extends BaseInspectionVisitor { + private StringEqualsVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitMethodCallExpression(PsiMethodCallExpression expression) { + super.visitMethodCallExpression(expression); + final PsiReferenceExpression methodExpression = expression.getMethodExpression(); + if (methodExpression == null) { + return; + } + final String methodName = methodExpression.getReferenceName(); + if (!"equals".equals(methodName)) { + return; + } + final PsiMethod method = expression.resolveMethod(); + if (method == null) { + return; + } + final PsiParameterList paramList = method.getParameterList(); + if (paramList == null) { + return; + } + final PsiParameter[] parameters = paramList.getParameters(); + if (parameters.length != 1) { + return; + } + final PsiType parameterType = parameters[0].getType(); + if (!TypeUtils.isJavaLangObject(parameterType)) { + return; + } + final PsiClass aClass = method.getContainingClass(); + final String className = aClass.getQualifiedName(); + if (!"java.lang.String".equals(className)) { + return; + } + registerMethodCallError(expression); + } + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/internationalization/StringToUpperWithoutLocaleInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/internationalization/StringToUpperWithoutLocaleInspection.java new file mode 100644 index 000000000000..37481749e35a --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/internationalization/StringToUpperWithoutLocaleInspection.java @@ -0,0 +1,69 @@ +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; + +public class StringToUpperWithoutLocaleInspection extends ExpressionInspection { + + public String getDisplayName() { + return "Call to String.toUpperCase() or .toLowerCase() without a Locale"; + } + + public String getGroupDisplayName() { + return GroupNames.INTERNATIONALIZATION_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "String.#ref() called without specifying a Locale in an internationalized context #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new StringToUpperWithoutLocaleVisitor(this, inspectionManager, onTheFly); + } + + private static class StringToUpperWithoutLocaleVisitor extends BaseInspectionVisitor { + private StringToUpperWithoutLocaleVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitMethodCallExpression(PsiMethodCallExpression expression) { + super.visitMethodCallExpression(expression); + final PsiReferenceExpression methodExpression = expression.getMethodExpression(); + if (methodExpression == null) { + return; + } + final String methodName = methodExpression.getReferenceName(); + if (!"toUpperCase".equals(methodName) && !"toLowerCase".equals(methodName)) { + return; + } + final PsiMethod method = expression.resolveMethod(); + if (method == null) { + return; + } + final PsiParameterList paramList = method.getParameterList(); + if (paramList == null) { + return; + } + final PsiParameter[] parameters = paramList.getParameters(); + if (parameters.length == 1) { + return; + } + final PsiClass containingClass = method.getContainingClass(); + if(containingClass == null) + { + return; + } + final String className = containingClass.getQualifiedName(); + if(!"java.lang.String".equals(className)) + { + return; + } + registerMethodCallError(expression); + } + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/internationalization/StringTokenizerInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/internationalization/StringTokenizerInspection.java new file mode 100644 index 000000000000..8e78413c820f --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/internationalization/StringTokenizerInspection.java @@ -0,0 +1,53 @@ +package com.siyeh.ig.internationalization; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiType; +import com.intellij.psi.PsiTypeElement; +import com.intellij.psi.PsiVariable; +import com.siyeh.ig.BaseInspection; +import com.siyeh.ig.BaseInspectionVisitor; +import com.siyeh.ig.GroupNames; +import com.siyeh.ig.VariableInspection; +import com.siyeh.ig.psiutils.TypeUtils; + +public class StringTokenizerInspection extends VariableInspection { + + public String getDisplayName() { + return "Use of StringTokenizer"; + } + + public String getGroupDisplayName() { + return GroupNames.INTERNATIONALIZATION_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "#ref in an internationalized context #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new StringTokenizerVisitor(this, inspectionManager, onTheFly); + } + + private static class StringTokenizerVisitor extends BaseInspectionVisitor { + private StringTokenizerVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitVariable(PsiVariable variable) { + super.visitVariable(variable); + final PsiType type = variable.getType(); + if (type == null) { + return; + } + final PsiType deepComponentType = type.getDeepComponentType(); + if (!TypeUtils.typeEquals("java.util.StringTokenizer", deepComponentType)) { + return; + } + final PsiTypeElement typeElement = variable.getTypeElement(); + registerError(typeElement); + } + + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/internationalization/TimeToStringInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/internationalization/TimeToStringInspection.java new file mode 100644 index 000000000000..8e8bb3da5325 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/internationalization/TimeToStringInspection.java @@ -0,0 +1,67 @@ +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; + +public class TimeToStringInspection extends ExpressionInspection { + + public String getDisplayName() { + return "Call to Time.toString()"; + } + + public String getGroupDisplayName() { + return GroupNames.INTERNATIONALIZATION_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "Time.#ref() in an internationalized context #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new TimeToStringVisitor(this, inspectionManager, onTheFly); + } + + private static class TimeToStringVisitor extends BaseInspectionVisitor { + private TimeToStringVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitMethodCallExpression(PsiMethodCallExpression expression) { + super.visitMethodCallExpression(expression); + final PsiReferenceExpression methodExpression = expression.getMethodExpression(); + if (methodExpression == null) { + return; + } + final String methodName = methodExpression.getReferenceName(); + if (!"toString".equals(methodName)) { + return; + } + final PsiMethod method = expression.resolveMethod(); + if (method == null) { + return; + } + final PsiParameterList paramList = method.getParameterList(); + if (paramList == null) { + return; + } + final PsiParameter[] parameters = paramList.getParameters(); + if (parameters.length != 0) { + return; + } + final PsiClass aClass = method.getContainingClass(); + if (aClass == null) { + return; + } + final String className = aClass.getQualifiedName(); + if (!"java.sql.Time".equals(className)) { + return; + } + registerMethodCallError(expression); + } + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/junit/AssertsWithoutMessagesInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/junit/AssertsWithoutMessagesInspection.java new file mode 100644 index 000000000000..bd89baa0851e --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/junit/AssertsWithoutMessagesInspection.java @@ -0,0 +1,107 @@ +package com.siyeh.ig.junit; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.openapi.project.Project; +import com.intellij.psi.*; +import com.intellij.psi.search.GlobalSearchScope; +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.ClassUtils; + +import java.util.HashSet; +import java.util.Set; + +public class AssertsWithoutMessagesInspection extends ExpressionInspection { + + private static final Set s_assertMethods = new HashSet(10); + + static { + s_assertMethods.add("assertTrue"); + s_assertMethods.add("assertFalse"); + s_assertMethods.add("assertEquals"); + s_assertMethods.add("assertNull"); + s_assertMethods.add("assertNotNull"); + s_assertMethods.add("assertSame"); + s_assertMethods.add("assertNotSame"); + } + + public String getDisplayName() { + return "Missing message on JUnit assertion"; + } + + public String getGroupDisplayName() { + return GroupNames.JUNIT_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "JUnit #ref() without message #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new AssertionsWithoutMessagesVisitor(this, inspectionManager, onTheFly); + } + + private static class AssertionsWithoutMessagesVisitor extends BaseInspectionVisitor { + + private AssertionsWithoutMessagesVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitMethodCallExpression(PsiMethodCallExpression expression) { + super.visitMethodCallExpression(expression); + if (!isJUnitAssertion(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(); + if (parameters.length < 2) { + registerMethodCallError(expression); + return; + } + 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(); + if (paramType1.equals(stringType)) { + if (parameters.length == 2) { + final PsiType paramType2 = parameters[1].getType(); + if (paramType2.equals(stringType)) { + registerMethodCallError(expression); + } + } + } else { + registerMethodCallError(expression); + } + } + + private static boolean isJUnitAssertion(PsiMethodCallExpression expression) { + final PsiReferenceExpression methodExpression = expression.getMethodExpression(); + final String methodName = methodExpression.getReferenceName(); + if (!s_assertMethods.contains(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/CallToSuperSetupVisitor.java b/plugins/InspectionGadgets/src/com/siyeh/ig/junit/CallToSuperSetupVisitor.java new file mode 100644 index 000000000000..3caf1680e1d4 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/junit/CallToSuperSetupVisitor.java @@ -0,0 +1,42 @@ +package com.siyeh.ig.junit; + +import com.intellij.psi.*; + +class CallToSuperSetupVisitor extends PsiRecursiveElementVisitor { + private boolean m_callToSuperSetupFound = false; + + public void visitMethodCallExpression(PsiMethodCallExpression expression) { + super.visitMethodCallExpression(expression); + final PsiReferenceExpression methodExpression = expression.getMethodExpression(); + if (methodExpression == null) { + return; + } + final PsiExpression target = methodExpression.getQualifierExpression(); + if (target == null) { + return; + } + if (!(target instanceof PsiSuperExpression)) { + return; + } + final String methodName = methodExpression.getReferenceName(); + if (!"setUp".equals(methodName)) { + return; + } + m_callToSuperSetupFound = true; + } + + 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 boolean isCallToSuperSetupFound() { + return m_callToSuperSetupFound; + } +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/junit/CallToSuperTeardownVisitor.java b/plugins/InspectionGadgets/src/com/siyeh/ig/junit/CallToSuperTeardownVisitor.java new file mode 100644 index 000000000000..e9c261e30d17 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/junit/CallToSuperTeardownVisitor.java @@ -0,0 +1,42 @@ +package com.siyeh.ig.junit; + +import com.intellij.psi.*; + +class CallToSuperTeardownVisitor extends PsiRecursiveElementVisitor { + private boolean m_callToSuperTeardownFound = false; + + public void visitMethodCallExpression(PsiMethodCallExpression expression) { + super.visitMethodCallExpression(expression); + final PsiReferenceExpression methodExpression = expression.getMethodExpression(); + if (methodExpression == null) { + return; + } + final PsiExpression target = methodExpression.getQualifierExpression(); + if (target == null) { + return; + } + if (!(target instanceof PsiSuperExpression)) { + return; + } + final String methodName = methodExpression.getReferenceName(); + if (!"tearDown".equals(methodName)) { + return; + } + m_callToSuperTeardownFound = true; + } + + 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 boolean isCallToSuperTeardownFound() { + return m_callToSuperTeardownFound; + } +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/junit/ContainsAssertionVisitor.java b/plugins/InspectionGadgets/src/com/siyeh/ig/junit/ContainsAssertionVisitor.java new file mode 100644 index 000000000000..a57bf47c2ab5 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/junit/ContainsAssertionVisitor.java @@ -0,0 +1,28 @@ +package com.siyeh.ig.junit; + +import com.intellij.psi.PsiRecursiveElementVisitor; +import com.intellij.psi.PsiMethodCallExpression; +import com.intellij.psi.PsiReferenceExpression; + +public class ContainsAssertionVisitor extends PsiRecursiveElementVisitor { + private boolean containsAssertion = false; + + public void visitMethodCallExpression(PsiMethodCallExpression call) { + super.visitMethodCallExpression(call); + final PsiReferenceExpression methodExpression = call.getMethodExpression(); + if(methodExpression == null) + { + return; + } + final String methodName = methodExpression.getReferenceName(); + if(methodName.startsWith("assert") ||methodName.startsWith("fail")) + { + containsAssertion = true; + } + } + + public boolean containsAssertion() { + return containsAssertion; + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/junit/MisspelledSetUpInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/junit/MisspelledSetUpInspection.java new file mode 100644 index 000000000000..f3c83aefccd1 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/junit/MisspelledSetUpInspection.java @@ -0,0 +1,62 @@ +package com.siyeh.ig.junit; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.psi.PsiClass; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiMethod; +import com.siyeh.ig.*; +import com.siyeh.ig.fixes.RenameFix; +import com.siyeh.ig.psiutils.ClassUtils; + +public class MisspelledSetUpInspection extends MethodInspection { + + public String getDisplayName() { + return "'setup()' instead of 'setUp()'"; + } + + protected InspectionGadgetsFix buildFix(PsiElement location) { + return new RenameFix("setUp"); + } + + public String getGroupDisplayName() { + return GroupNames.JUNIT_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "#ref() probably be setUp() #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new MisspelledSetUpVisitor(this, inspectionManager, onTheFly); + } + + protected boolean buildQuickFixesOnlyForOnTheFlyErrors() { + return true; + } + + private static class MisspelledSetUpVisitor extends BaseInspectionVisitor { + + private MisspelledSetUpVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitMethod(PsiMethod method) { + //note: no call to super + final PsiClass aClass = method.getContainingClass(); + if (aClass == null) { + return; + } + if (!ClassUtils.isSubclass(aClass, "junit.framework.TestCase")) { + return; + } + final String methodName = method.getName(); + if (!"setup".equals(methodName)) { + return; + } + registerMethodError(method); + } + + + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/junit/MisspelledTearDownInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/junit/MisspelledTearDownInspection.java new file mode 100644 index 000000000000..9198e13901ef --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/junit/MisspelledTearDownInspection.java @@ -0,0 +1,61 @@ +package com.siyeh.ig.junit; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.psi.PsiClass; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiMethod; +import com.siyeh.ig.*; +import com.siyeh.ig.fixes.RenameFix; +import com.siyeh.ig.psiutils.ClassUtils; + +public class MisspelledTearDownInspection extends MethodInspection { + + public String getDisplayName() { + return "'teardown()' instead of 'tearDown()'"; + } + + protected InspectionGadgetsFix buildFix(PsiElement location) { + return new RenameFix("tearDown"); + } + + public String getGroupDisplayName() { + return GroupNames.JUNIT_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "#ref() method should probably be tearDown() #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new MisspelledSetUpVisitor(this, inspectionManager, onTheFly); + } + + protected boolean buildQuickFixesOnlyForOnTheFlyErrors() { + return true; + } + + private static class MisspelledSetUpVisitor extends BaseInspectionVisitor { + + private MisspelledSetUpVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitMethod(PsiMethod method) { + // note: no call to super + final PsiClass aClass = method.getContainingClass(); + if (aClass == null) { + return; + } + if (!ClassUtils.isSubclass(aClass, "junit.framework.TestCase")) { + return; + } + final String methodName = method.getName(); + if (!"teardown".equals(methodName)) { + return; + } + registerMethodError(method); + } + + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/junit/SetupCallsSuperSetupInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/junit/SetupCallsSuperSetupInspection.java new file mode 100644 index 000000000000..a6e696ce00ac --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/junit/SetupCallsSuperSetupInspection.java @@ -0,0 +1,62 @@ +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.GroupNames; +import com.siyeh.ig.MethodInspection; +import com.siyeh.ig.psiutils.ClassUtils; + +public class SetupCallsSuperSetupInspection extends MethodInspection { + + public String getDisplayName() { + return "setUp() doesn't call super.setUp()"; + } + + public String getGroupDisplayName() { + return GroupNames.JUNIT_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "#ref() doesn't call super.setUp()"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new SetupCallsSuperSetupVisitor(this, inspectionManager, onTheFly); + } + + private static class SetupCallsSuperSetupVisitor extends BaseInspectionVisitor { + private SetupCallsSuperSetupVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitMethod(PsiMethod method) { + //note: no call to super; + final String methodName = method.getName(); + if (!"setUp".equals(methodName)) { + return; + } + final PsiParameterList parameterList = method.getParameterList(); + if (parameterList == null) { + return; + } + if (parameterList.getParameters().length != 0) { + return; + } + + final PsiClass targetClass = method.getContainingClass(); + if (!ClassUtils.isSubclass(targetClass, "junit.framework.TestCase")) { + return; + } + final CallToSuperSetupVisitor visitor = new CallToSuperSetupVisitor(); + method.accept(visitor); + if (visitor.isCallToSuperSetupFound()) { + return; + } + registerMethodError(method); + } + + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/junit/SetupIsPublicVoidNoArgInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/junit/SetupIsPublicVoidNoArgInspection.java new file mode 100644 index 000000000000..10abcb809937 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/junit/SetupIsPublicVoidNoArgInspection.java @@ -0,0 +1,67 @@ +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.GroupNames; +import com.siyeh.ig.MethodInspection; +import com.siyeh.ig.psiutils.ClassUtils; + +public class SetupIsPublicVoidNoArgInspection extends MethodInspection { + + public String getDisplayName() { + return "setUp() with incorrect signature"; + } + + public String getGroupDisplayName() { + return GroupNames.JUNIT_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "#ref() has incorrect signature"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new SetupIsPublicVoidNoArgVisitor(this, inspectionManager, onTheFly); + } + + private static class SetupIsPublicVoidNoArgVisitor extends BaseInspectionVisitor { + private SetupIsPublicVoidNoArgVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitMethod(PsiMethod method) { + //note: no call to super; + final String methodName = method.getName(); + if (!"setUp".equals(methodName)) { + return; + } + final PsiType returnType = method.getReturnType(); + if (returnType == null) { + return; + } + final PsiClass targetClass = method.getContainingClass(); + if (!ClassUtils.isSubclass(targetClass, "junit.framework.TestCase")) { + return; + } + final PsiParameterList parameterList = method.getParameterList(); + if (parameterList == null) { + return; + } + final PsiParameter[] parameters = parameterList.getParameters(); + if (parameters == null) { + return; + } + if (parameters.length != 0) { + registerMethodError(method); + } else if (!returnType.equals(PsiType.VOID)) { + registerMethodError(method); + } else if (!method.hasModifierProperty(PsiModifier.PUBLIC) && !method.hasModifierProperty(PsiModifier.PROTECTED)) { + registerMethodError(method); + } + } + + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/junit/StaticSuiteInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/junit/StaticSuiteInspection.java new file mode 100644 index 000000000000..cfce74904d8f --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/junit/StaticSuiteInspection.java @@ -0,0 +1,63 @@ +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.GroupNames; +import com.siyeh.ig.MethodInspection; +import com.siyeh.ig.psiutils.ClassUtils; + +public class StaticSuiteInspection extends MethodInspection { + + public String getDisplayName() { + return "'suite()' method not declared 'static'"; + } + + public String getGroupDisplayName() { + return GroupNames.JUNIT_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "JUnit #ref() methods not declared 'static' #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new StaticSuiteVisitor(this, inspectionManager, onTheFly); + } + + private static class StaticSuiteVisitor extends BaseInspectionVisitor { + + private StaticSuiteVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitMethod(PsiMethod method) { + //note: no call to super + final PsiClass aClass = method.getContainingClass(); + if (aClass == null) { + return; + } + if (!ClassUtils.isSubclass(aClass, "junit.framework.TestCase")) { + return; + } + final String methodName = method.getName(); + if (!"suite".equals(methodName)) { + return; + } + final PsiParameterList parameterList = method.getParameterList(); + if (parameterList == null) { + return; + } + if (parameterList.getParameters().length != 0) { + return; + } + if (method.hasModifierProperty(PsiModifier.STATIC)) { + return; + } + registerMethodError(method); + } + + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/junit/TeardownCallsSuperTeardownInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/junit/TeardownCallsSuperTeardownInspection.java new file mode 100644 index 000000000000..072fb1fac7b5 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/junit/TeardownCallsSuperTeardownInspection.java @@ -0,0 +1,62 @@ +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.GroupNames; +import com.siyeh.ig.MethodInspection; +import com.siyeh.ig.psiutils.ClassUtils; + +public class TeardownCallsSuperTeardownInspection extends MethodInspection { + + public String getDisplayName() { + return "tearDown() doesn't call super.tearDown()"; + } + + public String getGroupDisplayName() { + return GroupNames.JUNIT_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "#ref() doesn't call super.tearDown()"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new TeardownCallsSuperTeardownVisitor(this, inspectionManager, onTheFly); + } + + private static class TeardownCallsSuperTeardownVisitor extends BaseInspectionVisitor { + private TeardownCallsSuperTeardownVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitMethod(PsiMethod method) { + //note: no call to super; + final String methodName = method.getName(); + if (!"tearDown".equals(methodName)) { + return; + } + final PsiParameterList parameterList = method.getParameterList(); + if (parameterList == null) { + return; + } + if (parameterList.getParameters().length != 0) { + return; + } + + final PsiClass targetClass = method.getContainingClass(); + if (!ClassUtils.isSubclass(targetClass, "junit.framework.TestCase")) { + return; + } + final CallToSuperTeardownVisitor visitor = new CallToSuperTeardownVisitor(); + method.accept(visitor); + if (visitor.isCallToSuperTeardownFound()) { + return; + } + registerMethodError(method); + } + + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/junit/TeardownIsPublicVoidNoArgInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/junit/TeardownIsPublicVoidNoArgInspection.java new file mode 100644 index 000000000000..b176c18e7297 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/junit/TeardownIsPublicVoidNoArgInspection.java @@ -0,0 +1,68 @@ +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.GroupNames; +import com.siyeh.ig.MethodInspection; +import com.siyeh.ig.psiutils.ClassUtils; + +public class TeardownIsPublicVoidNoArgInspection extends MethodInspection { + + public String getDisplayName() { + return "tearDown() with incorrect signature"; + } + + public String getGroupDisplayName() { + return GroupNames.JUNIT_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "#ref() has incorrect signature"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new TeardownIsPublicVoidNoArgVisitor(this, inspectionManager, onTheFly); + } + + private static class TeardownIsPublicVoidNoArgVisitor extends BaseInspectionVisitor { + private TeardownIsPublicVoidNoArgVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitMethod(PsiMethod method) { + //note: no call to super; + final String methodName = method.getName(); + if (!"tearDown".equals(methodName)) { + return; + } + final PsiType returnType = method.getReturnType(); + if (returnType == null) { + return; + } + final PsiClass targetClass = method.getContainingClass(); + if (!ClassUtils.isSubclass(targetClass, "junit.framework.TestCase")) { + return; + } + final PsiParameterList parameterList = method.getParameterList(); + if (parameterList == null) { + return; + } + final PsiParameter[] parameters = parameterList.getParameters(); + if (parameters == null) { + return; + } + if (parameters.length != 0) { + registerMethodError(method); + } else if (!returnType.equals(PsiType.VOID)) { + registerMethodError(method); + } else if (!method.hasModifierProperty(PsiModifier.PUBLIC) && + !method.hasModifierProperty(PsiModifier.PROTECTED)) { + registerMethodError(method); + } + } + + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/junit/TestCaseWithConstructorInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/junit/TestCaseWithConstructorInspection.java new file mode 100644 index 000000000000..adc4a9b75a1e --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/junit/TestCaseWithConstructorInspection.java @@ -0,0 +1,86 @@ +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 TestCaseWithConstructorInspection extends ClassInspection { + + public String getDisplayName() { + return "JUnit TestCase with non-trivial constructors"; + } + + public String getGroupDisplayName() { + return GroupNames.JUNIT_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "Initialization logic in constructor #ref() instead of setUp()"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new TestCaseWithConstructorVisitor(this, inspectionManager, onTheFly); + } + + private static class TestCaseWithConstructorVisitor extends BaseInspectionVisitor { + + private TestCaseWithConstructorVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitMethod(PsiMethod method) { + // note: no call to super + if (!method.isConstructor()) { + return; + } + final PsiClass aClass = method.getContainingClass(); + if (!ClassUtils.isSubclass(aClass, "junit.framework.TestCase")) { + return; + } + if (isTrivial(method)) { + return; + } + registerMethodError(method); + } + + private static boolean isTrivial(PsiMethod method) { + final PsiCodeBlock body = method.getBody(); + if (body == null) { + return true; + } + final PsiStatement[] statements = body.getStatements(); + if (statements.length == 0) { + return true; + } + if (statements.length > 1) { + return false; + } + final PsiStatement statement = statements[0]; + if (!(statement instanceof PsiExpressionStatement)) { + return false; + } + final PsiExpression expression = + ((PsiExpressionStatement) statement).getExpression(); + if (expression == null) { + return false; + } + if (!(expression instanceof PsiMethodCallExpression)) { + return false; + } + final PsiMethodCallExpression call = + (PsiMethodCallExpression) expression; + final PsiReferenceExpression ref = call.getMethodExpression(); + if (ref == null) { + return false; + } + final String text = ref.getText(); + return "super".equals(text); + } + + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/junit/TestCaseWithNoTestMethodsInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/junit/TestCaseWithNoTestMethodsInspection.java new file mode 100644 index 000000000000..8b76592fd74d --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/junit/TestCaseWithNoTestMethodsInspection.java @@ -0,0 +1,77 @@ +package com.siyeh.ig.junit; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.psi.*; +import com.siyeh.ig.*; +import com.siyeh.ig.psiutils.ClassUtils; + +public class TestCaseWithNoTestMethodsInspection extends ClassInspection { + + public String getDisplayName() { + return "JUnit test case with no tests"; + } + + public String getGroupDisplayName() { + return GroupNames.JUNIT_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "JUnit test case #ref has no tests"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new TestCaseWithNoTestMethodsVisitor(this, inspectionManager, onTheFly); + } + + private static class TestCaseWithNoTestMethodsVisitor extends BaseInspectionVisitor { + private TestCaseWithNoTestMethodsVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitClass(PsiClass aClass) { + super.visitClass(aClass); + if (aClass.isInterface() + || aClass.isEnum() + || aClass.isAnnotationType() + || aClass.hasModifierProperty(PsiModifier.ABSTRACT)) { + return; + } + if (!ClassUtils.isSubclass(aClass, "junit.framework.TestCase")) { + return; + } + final PsiMethod[] methods = aClass.getMethods(); + for (int i = 0; i < methods.length; i++) { + final PsiMethod method = methods[i]; + if (isTest(method)) { + return; + } + } + registerClassError(aClass); + } + + private boolean isTest(PsiMethod method) { + if (!method.hasModifierProperty(PsiModifier.PUBLIC)) { + return false; + } + if (method.hasModifierProperty(PsiModifier.STATIC)) { + return false; + } + final String name = method.getName(); + if (!name.startsWith("test")) { + return false; + } + final PsiType returnType = method.getReturnType(); + if (!PsiType.VOID.equals(returnType)) { + return false; + } + final PsiParameterList parameterList = method.getParameterList(); + final PsiParameter[] parameters = parameterList.getParameters(); + if (parameters.length != 0) { + return false; + } + return true; + } + + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/junit/TestMethodIsPublicVoidNoArgInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/junit/TestMethodIsPublicVoidNoArgInspection.java new file mode 100644 index 000000000000..129b7d8f1284 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/junit/TestMethodIsPublicVoidNoArgInspection.java @@ -0,0 +1,66 @@ +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.GroupNames; +import com.siyeh.ig.MethodInspection; +import com.siyeh.ig.psiutils.ClassUtils; + +public class TestMethodIsPublicVoidNoArgInspection extends MethodInspection { + + public String getDisplayName() { + return "Test method with incorrect signature"; + } + + public String getGroupDisplayName() { + return GroupNames.JUNIT_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "#ref() is not declared 'public void " + location.getText() + "()"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new TestMethodIsPublicVoidNoArgVisitor(this, inspectionManager, onTheFly); + } + + private static class TestMethodIsPublicVoidNoArgVisitor extends BaseInspectionVisitor { + private TestMethodIsPublicVoidNoArgVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitMethod(PsiMethod method) { + //note: no call to super; + final String methodName = method.getName(); + if (!methodName.startsWith("test")) { + return; + } + final PsiType returnType = method.getReturnType(); + if (returnType == null) { + return; + } + final PsiParameterList parameterList = method.getParameterList(); + if (parameterList == null) { + return; + } + final PsiParameter[] parameters = parameterList.getParameters(); + if (parameters == null) { + return; + } + if (parameters.length == 0 + && returnType.equals(PsiType.VOID) + && method.hasModifierProperty(PsiModifier.PUBLIC)) { + return; + } + final PsiClass targetClass = method.getContainingClass(); + if (!ClassUtils.isSubclass(targetClass, "junit.framework.TestCase")) { + return; + } + registerMethodError(method); + } + + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/junit/TestMethodWithoutAssertionInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/junit/TestMethodWithoutAssertionInspection.java new file mode 100644 index 000000000000..6296dc81c4bf --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/junit/TestMethodWithoutAssertionInspection.java @@ -0,0 +1,78 @@ +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.ExpressionInspection; +import com.siyeh.ig.GroupNames; +import com.siyeh.ig.psiutils.ClassUtils; + +public class TestMethodWithoutAssertionInspection extends ExpressionInspection { + + + public String getDisplayName() { + return "JUnit test method without any assertions"; + } + + public String getGroupDisplayName() { + return GroupNames.JUNIT_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "JUnit test method #ref() contains no assertions #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new TestMethodWithoutAssertionVisitor(this, inspectionManager, onTheFly); + } + + private static class TestMethodWithoutAssertionVisitor extends BaseInspectionVisitor { + + private TestMethodWithoutAssertionVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitMethod(PsiMethod method) { + super.visitMethod(method); + final String methodName = method.getName(); + if (method.hasModifierProperty(PsiModifier.ABSTRACT)) { + return; + } + if (!methodName.startsWith("test")) { + return; + } + final PsiType returnType = method.getReturnType(); + if (returnType == null) { + return; + } + final PsiParameterList parameterList = method.getParameterList(); + if (parameterList == null) { + return; + } + final PsiParameter[] parameters = parameterList.getParameters(); + if (parameters == null) { + return; + } + if (parameters.length != 0 + ||! returnType.equals(PsiType.VOID) + || !method.hasModifierProperty(PsiModifier.PUBLIC)) { + return; + } + final PsiClass targetClass = method.getContainingClass(); + if (!ClassUtils.isSubclass(targetClass, "junit.framework.TestCase")) { + return; + } + final ContainsAssertionVisitor visitor = new ContainsAssertionVisitor(); + method.accept(visitor); + if (visitor.containsAssertion()) { + return; + } + registerMethodError(method); + } + + + + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/logging/ClassWithMultipleLoggersInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/logging/ClassWithMultipleLoggersInspection.java new file mode 100644 index 000000000000..75163326cddf --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/logging/ClassWithMultipleLoggersInspection.java @@ -0,0 +1,125 @@ +package com.siyeh.ig.logging; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.psi.PsiClass; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiField; +import com.intellij.psi.PsiType; +import com.siyeh.ig.*; + +import javax.swing.*; +import javax.swing.event.DocumentEvent; +import javax.swing.event.DocumentListener; +import javax.swing.text.Document; +import java.awt.*; + +public class ClassWithMultipleLoggersInspection extends ClassInspection { + + public String loggerClassName = "java.util.logging.Logger"; + + public String getDisplayName() { + return "Class with multiple loggers"; + } + + public String getGroupDisplayName() { + return GroupNames.LOGGING_GROUP_NAME; + } + + + public JComponent createOptionsPanel() { + final GridBagLayout layout = new GridBagLayout(); + final JPanel panel = new JPanel(layout); + + final JLabel classNameLabel = new JLabel("Logger class name:"); + classNameLabel.setHorizontalAlignment(SwingConstants.TRAILING); + + final JTextField loggerClassNameField = new JTextField(); + final Font panelFont = panel.getFont(); + loggerClassNameField.setFont(panelFont); + loggerClassNameField.setText(loggerClassName); + loggerClassNameField.setColumns(100); + loggerClassNameField.setInputVerifier(new RegExInputVerifier()); + + final DocumentListener listener = new DocumentListener() { + public void changedUpdate(DocumentEvent e) { + textChanged(); + } + + public void insertUpdate(DocumentEvent e) { + textChanged(); + } + + public void removeUpdate(DocumentEvent e) { + textChanged(); + } + + private void textChanged() { + loggerClassName = loggerClassNameField.getText(); + } + }; + final Document loggerClassNameDocument = loggerClassNameField.getDocument(); + loggerClassNameDocument.addDocumentListener(listener); + + final GridBagConstraints constraints = new GridBagConstraints(); + constraints.gridx = 0; + constraints.gridy = 0; + constraints.weightx = 1.0; + constraints.anchor = GridBagConstraints.EAST; + constraints.fill = GridBagConstraints.HORIZONTAL; + panel.add(classNameLabel, constraints); + + constraints.gridx = 1; + constraints.gridy = 0; + constraints.anchor = GridBagConstraints.WEST; + panel.add(loggerClassNameField, constraints); + + return panel; + } + + public String buildErrorString(PsiElement location) { + return "Class #ref declares multiple loggers #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new ClassWithoutLoggerVisitor(this, inspectionManager, onTheFly); + } + + private class ClassWithoutLoggerVisitor extends BaseInspectionVisitor { + + private ClassWithoutLoggerVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitClass(PsiClass aClass) { + //no recursion to avoid drilldown + if (aClass.isInterface() || aClass.isEnum() || aClass.isInterface()) { + return; + } + if (aClass.getContainingClass() != null) { + return; + } + int numLoggers = 0; + final PsiField[] fields = aClass.getFields(); + for (int i = 0; i < fields.length; i++) { + if (isLogger(fields[i])) { + numLoggers++; + } + } + if (numLoggers <= 1) { + return; + } + registerClassError(aClass); + } + + private boolean isLogger(PsiField field) { + final PsiType type = field.getType(); + if (type == null) { + return false; + } + final String text = type.getCanonicalText(); + return text.equals(loggerClassName); + } + + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/logging/ClassWithoutLoggerInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/logging/ClassWithoutLoggerInspection.java new file mode 100644 index 000000000000..bb0ec160444b --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/logging/ClassWithoutLoggerInspection.java @@ -0,0 +1,130 @@ +package com.siyeh.ig.logging; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.psi.PsiClass; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiField; +import com.intellij.psi.PsiType; +import com.siyeh.ig.*; + +import javax.swing.*; +import javax.swing.event.DocumentEvent; +import javax.swing.event.DocumentListener; +import javax.swing.text.Document; +import java.awt.*; +import java.text.NumberFormat; + +public class ClassWithoutLoggerInspection extends ClassInspection { + + public String loggerClassName = "java.util.logging.Logger"; + + public String getDisplayName() { + return "Class without logger"; + } + + public String getGroupDisplayName() { + return GroupNames.LOGGING_GROUP_NAME; + } + + + public JComponent createOptionsPanel() { + final GridBagLayout layout = new GridBagLayout(); + final JPanel panel = new JPanel(layout); + + final JLabel classNameLabel = new JLabel("Logger class name:"); + classNameLabel.setHorizontalAlignment(SwingConstants.TRAILING); + + final NumberFormat numberFormat = NumberFormat.getIntegerInstance(); + numberFormat.setParseIntegerOnly(true); + numberFormat.setMinimumIntegerDigits(1); + numberFormat.setMaximumIntegerDigits(2); + + final JTextField loggerClassNameField = new JTextField(); + final Font panelFont = panel.getFont(); + loggerClassNameField.setFont(panelFont); + loggerClassNameField.setText(loggerClassName); + loggerClassNameField.setColumns(100); + loggerClassNameField.setInputVerifier(new RegExInputVerifier()); + + final DocumentListener listener = new DocumentListener() { + public void changedUpdate(DocumentEvent e) { + textChanged(); + } + + public void insertUpdate(DocumentEvent e) { + textChanged(); + } + + public void removeUpdate(DocumentEvent e) { + textChanged(); + } + + private void textChanged() { + loggerClassName = loggerClassNameField.getText(); + } + }; + final Document loggerClassNameDocument = loggerClassNameField.getDocument(); + loggerClassNameDocument.addDocumentListener(listener); + + final GridBagConstraints constraints = new GridBagConstraints(); + constraints.gridx = 0; + constraints.gridy = 0; + constraints.weightx = 1.0; + constraints.anchor = GridBagConstraints.EAST; + constraints.fill = GridBagConstraints.HORIZONTAL; + panel.add(classNameLabel, constraints); + + constraints.gridx = 1; + constraints.gridy = 0; + constraints.anchor = GridBagConstraints.WEST; + panel.add(loggerClassNameField, constraints); + + return panel; + } + public String buildErrorString(PsiElement location) { + return "Class #ref does not declare a logger #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new ClassWithoutLoggerVisitor(this, inspectionManager, onTheFly); + } + + private class ClassWithoutLoggerVisitor extends BaseInspectionVisitor { + + private ClassWithoutLoggerVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitClass(PsiClass aClass) { + //no recursion to avoid drilldown + if(aClass.isInterface() || aClass.isEnum()|| aClass.isInterface()) + { + return; + } + if(aClass.getContainingClass()!=null) + { + return; + } + final PsiField[] fields = aClass.getFields(); + for (int i = 0; i < fields.length; i++) { + if(isLogger(fields[i])) + { + return; + } + } + registerClassError(aClass); + } + + private boolean isLogger(PsiField field) { + final PsiType type = field.getType(); + if(type == null) + { + return false; + } + final String text = type.getCanonicalText(); + return text.equals(loggerClassName); + } + + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/logging/NonStaticFinalLoggerInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/logging/NonStaticFinalLoggerInspection.java new file mode 100644 index 000000000000..5cb36db3471b --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/logging/NonStaticFinalLoggerInspection.java @@ -0,0 +1,128 @@ +package com.siyeh.ig.logging; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.psi.*; +import com.siyeh.ig.*; + +import javax.swing.*; +import javax.swing.event.DocumentEvent; +import javax.swing.event.DocumentListener; +import javax.swing.text.Document; +import java.awt.*; +import java.text.NumberFormat; + +public class NonStaticFinalLoggerInspection extends ClassInspection { + + public String loggerClassName = "java.util.logging.Logger"; + + public String getDisplayName() { + return "Non-constant logger"; + } + + public String getGroupDisplayName() { + return GroupNames.LOGGING_GROUP_NAME; + } + + + public JComponent createOptionsPanel() { + final GridBagLayout layout = new GridBagLayout(); + final JPanel panel = new JPanel(layout); + + final JLabel classNameLabel = new JLabel("Logger class name:"); + classNameLabel.setHorizontalAlignment(SwingConstants.TRAILING); + + final NumberFormat numberFormat = NumberFormat.getIntegerInstance(); + numberFormat.setParseIntegerOnly(true); + numberFormat.setMinimumIntegerDigits(1); + numberFormat.setMaximumIntegerDigits(2); + + final JTextField loggerClassNameField = new JTextField(); + final Font panelFont = panel.getFont(); + loggerClassNameField.setFont(panelFont); + loggerClassNameField.setText(loggerClassName); + loggerClassNameField.setColumns(100); + loggerClassNameField.setInputVerifier(new RegExInputVerifier()); + + final DocumentListener listener = new DocumentListener() { + public void changedUpdate(DocumentEvent e) { + textChanged(); + } + + public void insertUpdate(DocumentEvent e) { + textChanged(); + } + + public void removeUpdate(DocumentEvent e) { + textChanged(); + } + + private void textChanged() { + loggerClassName = loggerClassNameField.getText(); + } + }; + final Document loggerClassNameDocument = loggerClassNameField.getDocument(); + loggerClassNameDocument.addDocumentListener(listener); + + final GridBagConstraints constraints = new GridBagConstraints(); + constraints.gridx = 0; + constraints.gridy = 0; + constraints.weightx = 1.0; + constraints.anchor = GridBagConstraints.EAST; + constraints.fill = GridBagConstraints.HORIZONTAL; + panel.add(classNameLabel, constraints); + + constraints.gridx = 1; + constraints.gridy = 0; + constraints.anchor = GridBagConstraints.WEST; + panel.add(loggerClassNameField, constraints); + + return panel; + } + + public String buildErrorString(PsiElement location) { + return "Non-constant logger field #ref #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new ClassWithoutLoggerVisitor(this, inspectionManager, onTheFly); + } + + private class ClassWithoutLoggerVisitor extends BaseInspectionVisitor { + + private ClassWithoutLoggerVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitClass(PsiClass aClass) { + //no recursion to avoid drilldown + if (aClass.isInterface() || aClass.isEnum() || aClass.isInterface()) { + return; + } + if (aClass.getContainingClass() != null) { + return; + } + final PsiField[] fields = aClass.getFields(); + for (int i = 0; i < fields.length; i++) { + final PsiField field = fields[i]; + if (isLogger(field)) { + if(!field.hasModifierProperty(PsiModifier.STATIC)|| + !field.hasModifierProperty(PsiModifier.FINAL)) + { + registerFieldError(field); + } + } + } + } + + private boolean isLogger(PsiField field) { + final PsiType type = field.getType(); + if (type == null) { + return false; + } + final String text = type.getCanonicalText(); + return text.equals(loggerClassName); + } + + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/maturity/ClassWithoutToStringInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/maturity/ClassWithoutToStringInspection.java new file mode 100644 index 000000000000..6d555545c601 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/maturity/ClassWithoutToStringInspection.java @@ -0,0 +1,59 @@ +package com.siyeh.ig.maturity; + +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.UtilityClassUtil; + +public class ClassWithoutToStringInspection extends ClassInspection { + + public String getDisplayName() { + return "Class without toString()"; + } + + public String getGroupDisplayName() { + return GroupNames.MATURITY_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "Class #ref should probably implement .toString(), for debugging purposes"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new ClassWithoutToStringVisitor(this, inspectionManager, onTheFly); + } + + private static class ClassWithoutToStringVisitor extends BaseInspectionVisitor { + private ClassWithoutToStringVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitClass(PsiClass aClass) { + //don't call super, to prevent drilldown + if (aClass.isInterface() || aClass.isAnnotationType() || aClass.isEnum()) { + return; + } + if (aClass.hasModifierProperty(PsiModifier.ABSTRACT)) { + return; + } + if (UtilityClassUtil.isUtilityClass(aClass)) { + return; + } + final PsiMethod[] methods = aClass.getMethods(); + for (int i = 0; i < methods.length; i++) { + final PsiMethod method = methods[i]; + final String methodName = method.getName(); + final PsiParameterList paramList = method.getParameterList(); + final PsiParameter[] parameters = paramList.getParameters(); + if ("toString".equals(methodName) && parameters.length == 0) { + return; + } + } + registerClassError(aClass); + } + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/maturity/ObsoleteCollectionInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/maturity/ObsoleteCollectionInspection.java new file mode 100644 index 000000000000..4412aeddcab7 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/maturity/ObsoleteCollectionInspection.java @@ -0,0 +1,77 @@ +package com.siyeh.ig.maturity; + +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.VariableInspection; + +import java.util.HashSet; +import java.util.Set; + +public class ObsoleteCollectionInspection extends VariableInspection { + + private static final Set s_obsoleteCollectionTypes = new HashSet(2); + + static { + s_obsoleteCollectionTypes.add("java.util.Vector"); + s_obsoleteCollectionTypes.add("java.util.Hashtable"); + } + + public String getDisplayName() { + return "Use of obsolete collection type"; + } + + public String getGroupDisplayName() { + return GroupNames.MATURITY_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "Obsolete collection type #ref used #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new ObsoleteCollectionVisitor(this, inspectionManager, onTheFly); + } + + private static class ObsoleteCollectionVisitor extends BaseInspectionVisitor { + private ObsoleteCollectionVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitVariable(PsiVariable variable) { + super.visitVariable(variable); + final PsiType type = variable.getType(); + if (type == null) { + return; + } + final PsiType deepComponentType = type.getDeepComponentType(); + if (deepComponentType == null) { + return; + } + final String typeName = deepComponentType.getCanonicalText(); + if (!s_obsoleteCollectionTypes.contains(typeName)) { + return; + } + final PsiTypeElement typeElement = variable.getTypeElement(); + registerError(typeElement); + } + + public void visitNewExpression(PsiNewExpression newExpression) { + super.visitNewExpression(newExpression); + final PsiType type = newExpression.getType(); + if (type == null) { + return; + } + final String typeName = type.getCanonicalText(); + if (!s_obsoleteCollectionTypes.contains(typeName)) { + return; + } + final PsiJavaCodeReferenceElement classNameElement = newExpression.getClassReference(); + registerError(classNameElement); + } + + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/maturity/SystemOutErrInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/maturity/SystemOutErrInspection.java new file mode 100644 index 000000000000..a9771732d9aa --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/maturity/SystemOutErrInspection.java @@ -0,0 +1,50 @@ +package com.siyeh.ig.maturity; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiReferenceExpression; +import com.siyeh.ig.BaseInspection; +import com.siyeh.ig.BaseInspectionVisitor; +import com.siyeh.ig.ExpressionInspection; +import com.siyeh.ig.GroupNames; + +public class SystemOutErrInspection extends ExpressionInspection { + + public String getDisplayName() { + return "Use of System.out or System.err"; + } + + public String getGroupDisplayName() { + return GroupNames.MATURITY_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "Uses of #ref should probably be replaced with more robust logging #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new SystemOutErrVisitor(this, inspectionManager, onTheFly); + } + + private static class SystemOutErrVisitor extends BaseInspectionVisitor { + private SystemOutErrVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitReferenceExpression(PsiReferenceExpression expression) { + super.visitReferenceExpression(expression); + + final String text = expression.getText(); + if (text == null) { + return; + } + if (!"System.out".equals(text) && + !"System.err".equals(text)) { + return; + } + registerError(expression); + } + + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/maturity/ThreadDumpStackInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/maturity/ThreadDumpStackInspection.java new file mode 100644 index 000000000000..e9f728f3fc87 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/maturity/ThreadDumpStackInspection.java @@ -0,0 +1,66 @@ +package com.siyeh.ig.maturity; + +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.MethodCallUtils; + +public class ThreadDumpStackInspection extends ExpressionInspection { + + public String getDisplayName() { + return "Call to Thread.dumpStack()"; + } + + public String getGroupDisplayName() { + return GroupNames.MATURITY_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "Call to Thread.#ref() should probably be replaced with more robust logging #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new ThreadDumpStackVisitor(this, inspectionManager, onTheFly); + } + + private static class ThreadDumpStackVisitor extends BaseInspectionVisitor { + private ThreadDumpStackVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitMethodCallExpression(PsiMethodCallExpression expression) { + super.visitMethodCallExpression(expression); + final String methodName = MethodCallUtils.getMethodName(expression); + if (!"dumpStack".equals(methodName)) { + return; + } + final PsiExpressionList argumentList = expression.getArgumentList(); + if (argumentList == null) { + return; + } + if (argumentList.getExpressions().length != 0) { + return; + } + final PsiReferenceExpression methodExpression = expression.getMethodExpression(); + if (methodExpression == null) { + return; + } + final PsiElement element = methodExpression.resolve(); + if (!(element instanceof PsiMethod)) { + return; + } + final PsiMethod method = (PsiMethod) element; + final PsiClass aClass = method.getContainingClass(); + final String qualifiedName = aClass.getQualifiedName(); + if (!"java.lang.Thread".equals(qualifiedName)) { + return; + } + registerMethodCallError(expression); + } + + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/maturity/ThrowablePrintStackTraceInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/maturity/ThrowablePrintStackTraceInspection.java new file mode 100644 index 000000000000..2a386e0b45ae --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/maturity/ThrowablePrintStackTraceInspection.java @@ -0,0 +1,59 @@ +package com.siyeh.ig.maturity; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiMethodCallExpression; +import com.intellij.psi.PsiReferenceExpression; +import com.intellij.psi.PsiExpressionList; +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.MethodCallUtils; + +public class ThrowablePrintStackTraceInspection extends ExpressionInspection { + + public String getDisplayName() { + return "Call to printStackTrace()"; + } + + public String getGroupDisplayName() { + return GroupNames.MATURITY_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "Call to #ref() should probably be replaced with more robust logging #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new ThrowablePrintStackTraceVisitor(this, inspectionManager, onTheFly); + } + + private static class ThrowablePrintStackTraceVisitor extends BaseInspectionVisitor { + private ThrowablePrintStackTraceVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitMethodCallExpression(PsiMethodCallExpression expression) { + super.visitMethodCallExpression(expression); + final String methodName = MethodCallUtils.getMethodName(expression); + if (!"printStackTrace".equals(methodName)) { + return; + } + final PsiExpressionList argumentList = expression.getArgumentList(); + if (argumentList == null) { + return; + } + if (argumentList.getExpressions().length != 0) { + return; + } + final PsiReferenceExpression methodExpression = expression.getMethodExpression(); + if (methodExpression == null) { + return; + } + registerMethodCallError(expression); + } + + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/methodmetrics/CouplingVisitor.java b/plugins/InspectionGadgets/src/com/siyeh/ig/methodmetrics/CouplingVisitor.java new file mode 100644 index 000000000000..3045bf0c5ac4 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/methodmetrics/CouplingVisitor.java @@ -0,0 +1,175 @@ +package com.siyeh.ig.methodmetrics; + +import com.intellij.psi.*; +import com.intellij.psi.search.GlobalSearchScope; +import com.intellij.openapi.project.Project; +import com.siyeh.ig.psiutils.LibraryUtil; + +import java.util.HashSet; +import java.util.Set; + +class CouplingVisitor extends PsiRecursiveElementVisitor { + private static final Set s_primitiveTypes = new HashSet(8); + private boolean m_inClass = false; + + static { + s_primitiveTypes.add("boolean"); + s_primitiveTypes.add("byte"); + s_primitiveTypes.add("char"); + s_primitiveTypes.add("short"); + s_primitiveTypes.add("int"); + s_primitiveTypes.add("long"); + s_primitiveTypes.add("float"); + s_primitiveTypes.add("double"); + } + + private static boolean isPrimitiveType(String typeName) { + return s_primitiveTypes.contains(typeName); + } + + private final PsiMethod m_method; + private final boolean m_includeJavaClasses; + private final boolean m_includeLibraryClasses; + private final Set m_dependencies = new HashSet(10); + + CouplingVisitor(PsiMethod method, boolean includeJavaClasses, + boolean includeLibraryClasses) { + super(); + m_method = method; + m_includeJavaClasses = includeJavaClasses; + m_includeLibraryClasses = includeLibraryClasses; + } + + public void visitVariable(PsiVariable variable) { + super.visitVariable(variable); + final PsiType type = variable.getType(); + addDependency(type); + } + + public void visitMethod(PsiMethod method) { + super.visitMethod(method); + final PsiType returnType = method.getReturnType(); + addDependency(returnType); + addDependenciesForThrowsList(method); + } + + private void addDependenciesForThrowsList(PsiMethod method) { + final PsiReferenceList throwsList = method.getThrowsList(); + if (throwsList == null) { + return; + } + final PsiClassType[] throwsTypes = throwsList.getReferencedTypes(); + for (int i = 0; i < throwsTypes.length; i++) { + addDependency(throwsTypes[i]); + } + } + + public void visitNewExpression(PsiNewExpression exp) { + super.visitNewExpression(exp); + final PsiType classType = exp.getType(); + addDependency(classType); + } + + public void visitClassObjectAccessExpression(PsiClassObjectAccessExpression exp) { + super.visitClassObjectAccessExpression(exp); + final PsiTypeElement operand = exp.getOperand(); + addDependency(operand); + } + + public void visitClass(PsiClass aClass) { + final boolean wasInClass = m_inClass; + if (!m_inClass) { + + m_inClass = true; + super.visitClass(aClass); + } + m_inClass = wasInClass; + final PsiType[] superTypes = aClass.getSuperTypes(); + for (int i = 0; i < superTypes.length; i++) { + addDependency(superTypes[i]); + } + } + + 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 visitTryStatement(PsiTryStatement statement) { + super.visitTryStatement(statement); + final PsiParameter[] catchBlockParameters = statement.getCatchBlockParameters(); + for (int i = 0; i < catchBlockParameters.length; i++) { + final PsiType catchType = catchBlockParameters[i].getType(); + addDependency(catchType); + } + } + + public void visitInstanceOfExpression(PsiInstanceOfExpression exp) { + super.visitInstanceOfExpression(exp); + final PsiTypeElement checkType = exp.getCheckType(); + addDependency(checkType); + } + + public void visitTypeCastExpression(PsiTypeCastExpression exp) { + super.visitTypeCastExpression(exp); + final PsiTypeElement castType = exp.getCastType(); + addDependency(castType); + } + + private void addDependency(PsiTypeElement typeElement) { + if (typeElement == null) { + return; + } + final PsiType type = typeElement.getType(); + addDependency(type); + } + + private void addDependency(PsiType type) { + if (type == null) { + return; + } + final PsiType baseType = type.getDeepComponentType(); + final String baseTypeName = baseType.getCanonicalText(); + if (isPrimitiveType(baseTypeName)) { + return; + } + final PsiClass containingClass = m_method.getContainingClass(); + final String qualifiedName = containingClass.getQualifiedName(); + if (baseTypeName.equals(qualifiedName)) { + return; + } + if (baseTypeName.startsWith(qualifiedName + '.')) { + return; + } + if (!m_includeJavaClasses && + (baseTypeName.startsWith("java.") || + baseTypeName.startsWith("javax."))) { + return; + } + if (!m_includeLibraryClasses) { + final PsiManager manager = m_method.getManager(); + final Project project = manager.getProject(); + final GlobalSearchScope searchScope = GlobalSearchScope.allScope(project); + final PsiClass aClass = manager.findClass(baseTypeName, + searchScope); + if (aClass == null) { + return; + } + if (LibraryUtil.classIsInLibrary(aClass)) { + return; + } + } + m_dependencies.add(baseTypeName); + } + + public int getNumDependencies() { + return m_dependencies.size(); + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/methodmetrics/CyclomaticComplexityInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/methodmetrics/CyclomaticComplexityInspection.java new file mode 100644 index 000000000000..68a859a17e0b --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/methodmetrics/CyclomaticComplexityInspection.java @@ -0,0 +1,59 @@ +package com.siyeh.ig.methodmetrics; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiMethod; +import com.siyeh.ig.BaseInspection; +import com.siyeh.ig.BaseInspectionVisitor; +import com.siyeh.ig.GroupNames; + +public class CyclomaticComplexityInspection + extends MethodMetricInspection { + + public String getDisplayName() { + return "Overly complex method"; + } + + public String getGroupDisplayName() { + return GroupNames.METHODMETRICS_GROUP_NAME; + } + + protected int getDefaultLimit() { + return 10; + } + + protected String getConfigurationLabel() { + return "Method complexity limit:"; + } + + public String buildErrorString(PsiElement location) { + final PsiMethod method = (PsiMethod) location.getParent(); + final CyclomaticComplexityVisitor visitor = new CyclomaticComplexityVisitor(); + method.accept(visitor); + final int coupling = visitor.getComplexity(); + return "#ref is overly complex (cyclomatic complexity = " + coupling + ") #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new MethodComplexityVisitor(this, inspectionManager, onTheFly); + } + + private class MethodComplexityVisitor extends BaseInspectionVisitor { + private MethodComplexityVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitMethod(PsiMethod method) { + // note: no call to super + final CyclomaticComplexityVisitor visitor = new CyclomaticComplexityVisitor(); + method.accept(visitor); + final int complexity = visitor.getComplexity(); + + if (complexity <= getLimit()) { + return; + } + registerMethodError(method); + } + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/methodmetrics/CyclomaticComplexityVisitor.java b/plugins/InspectionGadgets/src/com/siyeh/ig/methodmetrics/CyclomaticComplexityVisitor.java new file mode 100644 index 000000000000..d988a807c64f --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/methodmetrics/CyclomaticComplexityVisitor.java @@ -0,0 +1,76 @@ +package com.siyeh.ig.methodmetrics; + +import com.intellij.psi.*; + +class CyclomaticComplexityVisitor extends PsiRecursiveElementVisitor { + private int m_complexity = 1; + + 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 visitAnonymousClass(PsiAnonymousClass aClass) { + // to call to super, to keep this from drilling down + } + + public void visitForStatement(PsiForStatement statement) { + super.visitForStatement(statement); + m_complexity++; + } + + public void visitForeachStatement(PsiForeachStatement statement) { + super.visitForeachStatement(statement); + m_complexity++; + } + + public void visitIfStatement(PsiIfStatement statement) { + super.visitIfStatement(statement); + m_complexity++; + } + + public void visitDoWhileStatement(PsiDoWhileStatement statement) { + super.visitDoWhileStatement(statement); + m_complexity++; + } + + public void visitConditionalExpression(PsiConditionalExpression expression) { + super.visitConditionalExpression(expression); + m_complexity++; + } + + public void visitSwitchStatement(PsiSwitchStatement statement) { + super.visitSwitchStatement(statement); + final PsiCodeBlock body = statement.getBody(); + if (body == null) { + return; + } + final PsiStatement[] statements = body.getStatements(); + boolean pendingLabel = false; + for (int i = 0; i < statements.length; i++) { + final PsiStatement child = statements[i]; + if (child instanceof PsiSwitchLabelStatement) { + if (!pendingLabel) { + m_complexity++; + } + pendingLabel = true; + } else { + pendingLabel = false; + } + } + } + + public void visitWhileStatement(PsiWhileStatement statement) { + super.visitWhileStatement(statement); + m_complexity++; + } + + public int getComplexity() { + return m_complexity; + } +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/methodmetrics/LoopCountVisitor.java b/plugins/InspectionGadgets/src/com/siyeh/ig/methodmetrics/LoopCountVisitor.java new file mode 100644 index 000000000000..883d40773b6d --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/methodmetrics/LoopCountVisitor.java @@ -0,0 +1,46 @@ +package com.siyeh.ig.methodmetrics; + +import com.intellij.psi.*; + +class LoopCountVisitor extends PsiRecursiveElementVisitor { + private int m_count = 0; + + 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 visitForStatement(PsiForStatement psiForStatement) { + super.visitForStatement(psiForStatement); + m_count++; + } + + public void visitForeachStatement(PsiForeachStatement psiForStatement) { + super.visitForeachStatement(psiForStatement); + m_count++; + } + + public void visitWhileStatement(PsiWhileStatement psiWhileStatement) { + super.visitWhileStatement(psiWhileStatement); + m_count++; + } + + public void visitDoWhileStatement(PsiDoWhileStatement psiDoWhileStatement) { + super.visitDoWhileStatement(psiDoWhileStatement); + m_count++; + } + + public void visitAnonymousClass(PsiAnonymousClass aClass) { + // no call to super, to keep it from drilling into anonymous classes + } + + public int getCount() { + return m_count; + } +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/methodmetrics/MethodCouplingInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/methodmetrics/MethodCouplingInspection.java new file mode 100644 index 000000000000..c5b81a98ae3e --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/methodmetrics/MethodCouplingInspection.java @@ -0,0 +1,144 @@ +package com.siyeh.ig.methodmetrics; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiMethod; +import com.siyeh.ig.BaseInspection; +import com.siyeh.ig.BaseInspectionVisitor; +import com.siyeh.ig.GroupNames; + +import javax.swing.*; +import javax.swing.event.ChangeEvent; +import javax.swing.event.ChangeListener; +import javax.swing.event.DocumentEvent; +import javax.swing.event.DocumentListener; +import javax.swing.text.Document; +import java.awt.*; +import java.text.NumberFormat; + +public class MethodCouplingInspection + extends MethodMetricInspection { + public boolean m_includeJavaClasses = false; + public boolean m_includeLibraryClasses = true; + + public String getDisplayName() { + return "Overly coupled method"; + } + + public String getGroupDisplayName() { + return GroupNames.METHODMETRICS_GROUP_NAME; + } + + protected int getDefaultLimit() { + return 10; + } + + protected String getConfigurationLabel() { + return "Method coupling limit:"; + } + + + public JComponent createOptionsPanel() { + final JPanel panel = new JPanel(new GridBagLayout()); + final String configurationLabel = getConfigurationLabel(); + final JLabel label = new JLabel(configurationLabel); + final NumberFormat formatter = NumberFormat.getIntegerInstance(); + formatter.setParseIntegerOnly(true); + final JFormattedTextField valueField = new JFormattedTextField(formatter); + valueField.setValue(new Integer(m_limit)); + valueField.setColumns(4); + final Document document = valueField.getDocument(); + document.addDocumentListener(new DocumentListener() { + public void changedUpdate(DocumentEvent e) { + textChanged(); + } + + public void insertUpdate(DocumentEvent e) { + textChanged(); + } + + public void removeUpdate(DocumentEvent e) { + textChanged(); + } + + private void textChanged() { + m_limit = ((Number) valueField.getValue()).intValue(); + } + }); + + final GridBagConstraints constraints = new GridBagConstraints(); + constraints.gridx = 0; + constraints.gridy = 0; + constraints.weightx = 1.0; + constraints.anchor = GridBagConstraints.WEST; + constraints.fill = GridBagConstraints.NONE; + panel.add(label, constraints); + constraints.gridx = 1; + constraints.gridy = 0; + constraints.weightx = 1.0; + constraints.anchor = GridBagConstraints.WEST; + constraints.fill = GridBagConstraints.NONE; + panel.add(valueField, constraints); + + final JCheckBox arrayCheckBox = new JCheckBox("Include couplings to java system classes", + m_includeJavaClasses); + final ButtonModel arrayModel = arrayCheckBox.getModel(); + arrayModel.addChangeListener(new ChangeListener() { + + public void stateChanged(ChangeEvent e) { + m_includeJavaClasses = arrayModel.isSelected(); + } + }); + final JCheckBox objectCheckBox = new JCheckBox("Include couplings to library classes", + m_includeLibraryClasses); + final ButtonModel model = objectCheckBox.getModel(); + model.addChangeListener(new ChangeListener() { + + public void stateChanged(ChangeEvent e) { + m_includeLibraryClasses = model.isSelected(); + } + }); + constraints.gridx = 0; + constraints.gridy = 1; + constraints.gridwidth = 2; + constraints.fill = GridBagConstraints.HORIZONTAL; + panel.add(arrayCheckBox, constraints); + + constraints.gridx = 0; + constraints.gridy = 2; + constraints.gridwidth = 2; + panel.add(objectCheckBox, constraints); + return panel; + } + + public String buildErrorString(PsiElement location) { + final PsiMethod method = (PsiMethod) location.getParent(); + final CouplingVisitor visitor = new CouplingVisitor(method, m_includeJavaClasses, m_includeLibraryClasses); + method.accept(visitor); + final int coupling = visitor.getNumDependencies(); + return "#ref is overly coupled (# referenced classes = " + coupling + ") #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new MethodCouplingVisitor(this, inspectionManager, onTheFly); + } + + private class MethodCouplingVisitor extends BaseInspectionVisitor { + private MethodCouplingVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitMethod(PsiMethod method) { + // note: no call to super + final CouplingVisitor visitor = new CouplingVisitor(method, m_includeJavaClasses, m_includeLibraryClasses); + method.accept(visitor); + final int coupling = visitor.getNumDependencies(); + + if (coupling <= getLimit()) { + return; + } + registerMethodError(method); + } + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/methodmetrics/MethodMetricInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/methodmetrics/MethodMetricInspection.java new file mode 100644 index 000000000000..eb5eba005653 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/methodmetrics/MethodMetricInspection.java @@ -0,0 +1,23 @@ +package com.siyeh.ig.methodmetrics; + +import com.siyeh.ig.MethodInspection; +import com.siyeh.ig.ui.SingleIntegerFieldOptionsPanel; + +import javax.swing.*; + +public abstract class MethodMetricInspection extends MethodInspection { + public int m_limit = getDefaultLimit(); //this is public for the DefaultJDOMSerialization thingy + + protected abstract int getDefaultLimit(); + + protected abstract String getConfigurationLabel(); + + protected int getLimit() { + return m_limit; + } + + public JComponent createOptionsPanel() { + return new SingleIntegerFieldOptionsPanel(getConfigurationLabel(), + this, "m_limit"); + } +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/methodmetrics/MethodWithMultipleLoopsInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/methodmetrics/MethodWithMultipleLoopsInspection.java new file mode 100644 index 000000000000..a940f44b48c2 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/methodmetrics/MethodWithMultipleLoopsInspection.java @@ -0,0 +1,50 @@ +package com.siyeh.ig.methodmetrics; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiMethod; +import com.siyeh.ig.BaseInspection; +import com.siyeh.ig.BaseInspectionVisitor; +import com.siyeh.ig.GroupNames; +import com.siyeh.ig.MethodInspection; + +public class MethodWithMultipleLoopsInspection extends MethodInspection { + + public String getDisplayName() { + return "Method with multiple loops"; + } + + public String getGroupDisplayName() { + return GroupNames.METHODMETRICS_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + final PsiMethod method = (PsiMethod) location.getParent(); + final LoopCountVisitor visitor = new LoopCountVisitor(); + method.accept(visitor); + final int negationCount = visitor.getCount(); + return "#ref contains " + negationCount + " loops #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new MethodWithMultipleLoopsVisitor(this, inspectionManager, onTheFly); + } + + private static class MethodWithMultipleLoopsVisitor extends BaseInspectionVisitor { + private MethodWithMultipleLoopsVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitMethod(PsiMethod method) { + // note: no call to super + final LoopCountVisitor visitor = new LoopCountVisitor(); + method.accept(visitor); + final int negationCount = visitor.getCount(); + if (negationCount <= 1) { + return; + } + registerMethodError(method); + } + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/methodmetrics/MultipleReturnPointsPerMethodInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/methodmetrics/MultipleReturnPointsPerMethodInspection.java new file mode 100644 index 000000000000..a2dd88ae7d86 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/methodmetrics/MultipleReturnPointsPerMethodInspection.java @@ -0,0 +1,84 @@ +package com.siyeh.ig.methodmetrics; + +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.psiutils.ControlFlowUtils; + +public class MultipleReturnPointsPerMethodInspection extends MethodMetricInspection { + + public String getDisplayName() { + return "Method with multiple return points."; + } + + public String getGroupDisplayName() { + return GroupNames.METHODMETRICS_GROUP_NAME; + } + + protected int getDefaultLimit() { + return 1; + } + + protected String getConfigurationLabel() { + return "Return point limit:"; + } + + public String buildErrorString(PsiElement location) { + final PsiMethod parent = (PsiMethod) location.getParent(); + final int numReturnPoints = calculateNumReturnPoints(parent); + return "#ref has " + numReturnPoints + " return points #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new MultipleReturnPointsVisitor(this, inspectionManager, onTheFly); + } + + private class MultipleReturnPointsVisitor extends BaseInspectionVisitor { + private MultipleReturnPointsVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitMethod(PsiMethod method) { + // note: no call to super + final int numReturnPoints = calculateNumReturnPoints(method); + if (numReturnPoints <= getLimit()) { + return; + } + registerMethodError(method); + } + + } + + private static int calculateNumReturnPoints(PsiMethod method) { + final ReturnPointCountVisitor visitor = new ReturnPointCountVisitor(); + method.accept(visitor); + final int count = visitor.getCount(); + + if (!mayFallThroughBottom(method)) { + return count; + } + final PsiCodeBlock body = method.getBody(); + if (body == null) { + return count; + } + final PsiStatement[] statements = body.getStatements(); + if (statements.length == 0) { + return count + 1; + } + final PsiStatement lastStatement = statements[statements.length - 1]; + if (ControlFlowUtils.statementMayCompleteNormally(lastStatement)) { + return count + 1; + } + return count; + } + + private static boolean mayFallThroughBottom(PsiMethod method) { + if (method.isConstructor()) { + return true; + } + final PsiType returnType = method.getReturnType(); + return returnType.equals(PsiType.VOID); + } +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/methodmetrics/NCSSVisitor.java b/plugins/InspectionGadgets/src/com/siyeh/ig/methodmetrics/NCSSVisitor.java new file mode 100644 index 000000000000..1b416111caf9 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/methodmetrics/NCSSVisitor.java @@ -0,0 +1,35 @@ +package com.siyeh.ig.methodmetrics; + +import com.intellij.psi.*; + +class NCSSVisitor extends PsiRecursiveElementVisitor { + private int m_statementCount = 0; + + 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 visitAnonymousClass(PsiAnonymousClass aClass) { + // to call to super, to keep this from drilling down + } + + public void visitStatement(PsiStatement statement) { + super.visitStatement(statement); + if (statement instanceof PsiEmptyStatement || + statement instanceof PsiBlockStatement) { + return; + } + m_statementCount++; + } + + public int getStatementCount() { + return m_statementCount; + } +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/methodmetrics/NegationCountVisitor.java b/plugins/InspectionGadgets/src/com/siyeh/ig/methodmetrics/NegationCountVisitor.java new file mode 100644 index 000000000000..841d1ea5d6fb --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/methodmetrics/NegationCountVisitor.java @@ -0,0 +1,48 @@ +package com.siyeh.ig.methodmetrics; + +import com.intellij.psi.*; + +class NegationCountVisitor extends PsiRecursiveElementVisitor { + private int m_count = 0; + + 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 visitBinaryExpression(PsiBinaryExpression expression) { + super.visitBinaryExpression(expression); + final PsiJavaToken sign = expression.getOperationSign(); + if (sign == null) { + return; + } + if (sign.getTokenType() == JavaTokenType.NE) { + m_count++; + } + } + + public void visitAnonymousClass(PsiAnonymousClass aClass) { + // no call to super, to keep it from drilling into anonymous classes + } + + public void visitPrefixExpression(PsiPrefixExpression expression) { + super.visitPrefixExpression(expression); + final PsiJavaToken sign = expression.getOperationSign(); + if (sign == null) { + return; + } + if (sign.getTokenType() == JavaTokenType.EXCL) { + m_count++; + } + } + + public int getCount() { + return m_count; + } +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/methodmetrics/NestingDepthInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/methodmetrics/NestingDepthInspection.java new file mode 100644 index 000000000000..eb36436a9744 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/methodmetrics/NestingDepthInspection.java @@ -0,0 +1,58 @@ +package com.siyeh.ig.methodmetrics; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiMethod; +import com.siyeh.ig.BaseInspection; +import com.siyeh.ig.BaseInspectionVisitor; +import com.siyeh.ig.GroupNames; + +public class NestingDepthInspection extends MethodMetricInspection { + + public String getDisplayName() { + return "Overly nested method "; + } + + public String getGroupDisplayName() { + return GroupNames.METHODMETRICS_GROUP_NAME; + } + + protected int getDefaultLimit() { + return 5; + } + + protected String getConfigurationLabel() { + return "Nesting depth limit:"; + } + + public String buildErrorString(PsiElement location) { + final PsiMethod method = (PsiMethod) location.getParent(); + final NestingDepthVisitor visitor = new NestingDepthVisitor(); + method.accept(visitor); + final int nestingDepth = visitor.getMaximumDepth(); + return "#ref is overly nested (maximum nesting depth = " + nestingDepth + ") #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new NestingDepthMethodVisitor(this, inspectionManager, onTheFly); + } + + private class NestingDepthMethodVisitor extends BaseInspectionVisitor { + private NestingDepthMethodVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitMethod(PsiMethod method) { + // note: no call to super + final NestingDepthVisitor visitor = new NestingDepthVisitor(); + method.accept(visitor); + final int count = visitor.getMaximumDepth(); + + if (count <= getLimit()) { + return; + } + registerMethodError(method); + } + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/methodmetrics/NestingDepthVisitor.java b/plugins/InspectionGadgets/src/com/siyeh/ig/methodmetrics/NestingDepthVisitor.java new file mode 100644 index 000000000000..18e0bd258839 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/methodmetrics/NestingDepthVisitor.java @@ -0,0 +1,106 @@ +package com.siyeh.ig.methodmetrics; + +import com.intellij.psi.*; + +class NestingDepthVisitor extends PsiRecursiveElementVisitor { + private int m_maximumDepth = 0; + private int m_currentDepth = 0; + + 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 visitAnonymousClass(PsiAnonymousClass aClass) { + // to call to super, to keep this from drilling down + } + + public void visitBlockStatement(PsiBlockStatement statement) { + final PsiElement parent = statement.getParent(); + final boolean isAlreadyCounted = parent instanceof PsiDoWhileStatement || + parent instanceof PsiWhileStatement || + parent instanceof PsiForStatement || + parent instanceof PsiIfStatement || + parent instanceof PsiSynchronizedStatement || + parent instanceof PsiTryStatement; + if (!isAlreadyCounted) { + enterScope(); + } + super.visitBlockStatement(statement); + if (!isAlreadyCounted) { + exitScope(); + } + } + + public void visitDoWhileStatement(PsiDoWhileStatement statement) { + enterScope(); + super.visitDoWhileStatement(statement); + exitScope(); + } + + public void visitForStatement(PsiForStatement statement) { + enterScope(); + super.visitForStatement(statement); + exitScope(); + } + + public void visitIfStatement(PsiIfStatement statement) { + boolean isAlreadyCounted = false; + if (statement.getParent() instanceof PsiIfStatement) { + final PsiIfStatement parent = (PsiIfStatement) statement.getParent(); + final PsiStatement elseBranch = parent.getElseBranch(); + if (statement.equals(elseBranch)) { + isAlreadyCounted = true; + } + } + if (!isAlreadyCounted) { + enterScope(); + } + super.visitIfStatement(statement); + if (!isAlreadyCounted) { + exitScope(); + } + } + + public void visitSynchronizedStatement(PsiSynchronizedStatement statement) { + enterScope(); + super.visitSynchronizedStatement(statement); + exitScope(); + } + + public void visitTryStatement(PsiTryStatement statement) { + enterScope(); + super.visitTryStatement(statement); + exitScope(); + } + + public void visitSwitchStatement(PsiSwitchStatement statement) { + enterScope(); + super.visitSwitchStatement(statement); + exitScope(); + } + + public void visitWhileStatement(PsiWhileStatement statement) { + enterScope(); + super.visitWhileStatement(statement); + exitScope(); + } + + private void enterScope() { + m_currentDepth++; + m_maximumDepth = Math.max(m_maximumDepth, m_currentDepth); + } + + private void exitScope() { + m_currentDepth--; + } + + public int getMaximumDepth() { + return m_maximumDepth; + } +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/methodmetrics/NonCommentSourceStatementsInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/methodmetrics/NonCommentSourceStatementsInspection.java new file mode 100644 index 000000000000..762bb2217c4b --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/methodmetrics/NonCommentSourceStatementsInspection.java @@ -0,0 +1,60 @@ +package com.siyeh.ig.methodmetrics; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiMethod; +import com.siyeh.ig.BaseInspection; +import com.siyeh.ig.BaseInspectionVisitor; +import com.siyeh.ig.GroupNames; + +public class NonCommentSourceStatementsInspection extends MethodMetricInspection { + private static final int DEFAULT_LIMIT = 30; + + public String getDisplayName() { + return "Overly long method "; + } + + public String getGroupDisplayName() { + return GroupNames.METHODMETRICS_GROUP_NAME; + } + + protected int getDefaultLimit() { + return DEFAULT_LIMIT; + } + + protected String getConfigurationLabel() { + return "Non-comment source statements limit:"; + } + + public String buildErrorString(PsiElement location) { + final PsiMethod method = (PsiMethod) location.getParent(); + final NCSSVisitor visitor = new NCSSVisitor(); + method.accept(visitor); + final int statementCount = visitor.getStatementCount(); + return "#ref is too long (# Non-comment source statements = " + statementCount + ") #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new NonCommentSourceStatementsMethodVisitor(this, inspectionManager, onTheFly); + } + + private class NonCommentSourceStatementsMethodVisitor extends BaseInspectionVisitor { + + private NonCommentSourceStatementsMethodVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitMethod(PsiMethod method) { + // note: no call to super + final NCSSVisitor visitor = new NCSSVisitor(); + method.accept(visitor); + final int count = visitor.getStatementCount(); + + if (count <= getLimit()) { + return; + } + registerMethodError(method); + } + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/methodmetrics/ParametersPerMethodInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/methodmetrics/ParametersPerMethodInspection.java new file mode 100644 index 000000000000..1d049f7c41b7 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/methodmetrics/ParametersPerMethodInspection.java @@ -0,0 +1,66 @@ +package com.siyeh.ig.methodmetrics; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.psi.*; +import com.intellij.psi.util.PsiSuperMethodUtil; +import com.siyeh.ig.BaseInspection; +import com.siyeh.ig.BaseInspectionVisitor; +import com.siyeh.ig.GroupNames; +import com.siyeh.ig.psiutils.LibraryUtil; +import com.siyeh.ig.psiutils.LibraryUtil; + +public class ParametersPerMethodInspection extends MethodMetricInspection { + + public String getDisplayName() { + return "Method with too many parameters"; + } + + public String getGroupDisplayName() { + return GroupNames.METHODMETRICS_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + final PsiMethod method = (PsiMethod) location.getParent(); + final PsiParameterList parameterList = method.getParameterList(); + final int numParams = parameterList.getParameters().length; + return "#ref has too many parameters (num parameters = " + numParams + ") #loc"; + } + + protected int getDefaultLimit() { + return 5; + } + + protected String getConfigurationLabel() { + return "Parameter limit:"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new ParametersPerMethodVisitor(this, inspectionManager, onTheFly); + } + + private class ParametersPerMethodVisitor extends BaseInspectionVisitor { + private ParametersPerMethodVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitMethod(PsiMethod method) { + // note: no call to super + if (method.getParameterList().getParameters().length <= getLimit()) { + return; + } + + final PsiMethod[] superMethods = PsiSuperMethodUtil.findSuperMethods(method); + for (int i = 0; i < superMethods.length; i++) { + final PsiMethod superMethod = superMethods[i]; + final PsiClass containingClass = superMethod.getContainingClass(); + if (containingClass != null) { + if (LibraryUtil.classIsInLibrary(containingClass)) { + return; + } + } + } + registerMethodError(method); + } + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/methodmetrics/ReturnPointCountVisitor.java b/plugins/InspectionGadgets/src/com/siyeh/ig/methodmetrics/ReturnPointCountVisitor.java new file mode 100644 index 000000000000..07530c2a31eb --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/methodmetrics/ReturnPointCountVisitor.java @@ -0,0 +1,31 @@ +package com.siyeh.ig.methodmetrics; + +import com.intellij.psi.*; + +class ReturnPointCountVisitor extends PsiRecursiveElementVisitor { + private int m_count = 0; + + 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 visitAnonymousClass(PsiAnonymousClass aClass) { + // no call to super, to keep it from drilling into anonymous classes + } + + public void visitReturnStatement(PsiReturnStatement statement) { + super.visitReturnStatement(statement); + m_count++; + } + + public int getCount() { + return m_count; + } +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/methodmetrics/ThreeNegationsPerMethodInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/methodmetrics/ThreeNegationsPerMethodInspection.java new file mode 100644 index 000000000000..60cf197eafc8 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/methodmetrics/ThreeNegationsPerMethodInspection.java @@ -0,0 +1,50 @@ +package com.siyeh.ig.methodmetrics; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiMethod; +import com.siyeh.ig.BaseInspection; +import com.siyeh.ig.BaseInspectionVisitor; +import com.siyeh.ig.GroupNames; +import com.siyeh.ig.MethodInspection; + +public class ThreeNegationsPerMethodInspection extends MethodInspection { + + public String getDisplayName() { + return "Method with more than three negations"; + } + + public String getGroupDisplayName() { + return GroupNames.METHODMETRICS_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + final PsiMethod method = (PsiMethod) location.getParent(); + final NegationCountVisitor visitor = new NegationCountVisitor(); + method.accept(visitor); + final int negationCount = visitor.getCount(); + return "#ref contains " + negationCount + " negations #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new ThreeNegationsPerMethodVisitor(this, inspectionManager, onTheFly); + } + + private static class ThreeNegationsPerMethodVisitor extends BaseInspectionVisitor { + private ThreeNegationsPerMethodVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitMethod(PsiMethod method) { + // note: no call to super + final NegationCountVisitor visitor = new NegationCountVisitor(); + method.accept(visitor); + final int negationCount = visitor.getCount(); + if (negationCount <= 3) { + return; + } + registerMethodError(method); + } + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/naming/ClassNamePrefixedWithPackageNameInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/naming/ClassNamePrefixedWithPackageNameInspection.java new file mode 100644 index 000000000000..74465fba7593 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/naming/ClassNamePrefixedWithPackageNameInspection.java @@ -0,0 +1,79 @@ +package com.siyeh.ig.naming; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.psi.PsiClass; +import com.intellij.psi.PsiElement; +import com.siyeh.ig.*; +import com.siyeh.ig.fixes.RenameFix; + +import java.util.StringTokenizer; + +public class ClassNamePrefixedWithPackageNameInspection extends ClassInspection { + private final RenameFix fix = new RenameFix(); + + public String getDisplayName() { + return "Class name prefixed with package name"; + } + + public String getGroupDisplayName() { + return GroupNames.NAMING_CONVENTIONS_GROUP_NAME; + } + + protected InspectionGadgetsFix buildFix(PsiElement location) { + return fix; + } + + protected boolean buildQuickFixesOnlyForOnTheFlyErrors() { + return true; + } + + public String buildErrorString(PsiElement location) { + return "Class name '#ref' begins with it's package name #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new ClassNameBePrefixedWithPackageNameVisitor(this, inspectionManager, onTheFly); + } + + private static class ClassNameBePrefixedWithPackageNameVisitor extends BaseInspectionVisitor { + private ClassNameBePrefixedWithPackageNameVisitor(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 into inner classes + final String className = aClass.getName(); + final String qualifiedName = aClass.getQualifiedName(); + if (className == null) { + return; + } + if (qualifiedName == null) { + return; + } + if (className.equals(qualifiedName)) { + return; + } + final StringTokenizer tokenizer = new StringTokenizer(qualifiedName, "."); + String currentPackageName = null; + String lastPackageName = null; + while (tokenizer.hasMoreTokens()) { + lastPackageName = currentPackageName; + currentPackageName = tokenizer.nextToken(); + } + + final String packageName = lastPackageName; + if (packageName == null) { + return; + } + final String lowercaseClassName = className.toLowerCase(); + final String lowercasePackageName = packageName.toLowerCase(); + if (!lowercaseClassName.startsWith(lowercasePackageName)) { + return; + } + registerClassError(aClass); + } + + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/naming/ClassNameSameAsAncestorNameInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/naming/ClassNameSameAsAncestorNameInspection.java new file mode 100644 index 000000000000..ae80364493f3 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/naming/ClassNameSameAsAncestorNameInspection.java @@ -0,0 +1,81 @@ +package com.siyeh.ig.naming; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.psi.PsiClass; +import com.intellij.psi.PsiElement; +import com.siyeh.ig.*; +import com.siyeh.ig.fixes.RenameFix; + +import java.util.HashSet; +import java.util.Set; + +public class ClassNameSameAsAncestorNameInspection extends ClassInspection { + private final RenameFix fix = new RenameFix(); + + public String getDisplayName() { + return "Class name same as ancestor name"; + } + + public String getGroupDisplayName() { + return GroupNames.NAMING_CONVENTIONS_GROUP_NAME; + } + + protected InspectionGadgetsFix buildFix(PsiElement location) { + return fix; + } + + protected boolean buildQuickFixesOnlyForOnTheFlyErrors() { + return true; + } + + public String buildErrorString(PsiElement location) { + return "Class name '#ref' is the same as one of it's superclass' names #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new ClassNameSameAsAncestorNameVisitor(this, inspectionManager, onTheFly); + } + + private static class ClassNameSameAsAncestorNameVisitor extends BaseInspectionVisitor { + private ClassNameSameAsAncestorNameVisitor(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 into inner classes + + final String className = aClass.getName(); + + final Set alreadyVisited = new HashSet(8); + final PsiClass[] supers = aClass.getSupers(); + for (int i = 0; i < supers.length; i++) { + final PsiClass aSuper = supers[i]; + if (hasMatchingName(aSuper, className, alreadyVisited)) { + registerClassError(aClass); + } + } + } + + + private static boolean hasMatchingName(PsiClass aSuper, String className, + Set alreadyVisited) { + if (alreadyVisited.contains(aSuper)) { + return false; + } + alreadyVisited.add(aSuper); + final String superName = aSuper.getName(); + if (superName.equals(className)) { + return true; + } + final PsiClass[] supers = aSuper.getSupers(); + for (int i = 0; i < supers.length; i++) { + if (hasMatchingName(supers[i], className, alreadyVisited)) { + return true; + } + } + return false; + } + + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/naming/ClassNamingConventionInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/naming/ClassNamingConventionInspection.java new file mode 100644 index 000000000000..df47a5f3f2b4 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/naming/ClassNamingConventionInspection.java @@ -0,0 +1,91 @@ +package com.siyeh.ig.naming; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.codeInspection.ProblemDescriptor; +import com.intellij.psi.PsiClass; +import com.intellij.psi.PsiElement; +import com.siyeh.ig.*; +import com.siyeh.ig.fixes.RenameFix; + +public class ClassNamingConventionInspection extends ConventionInspection { + private static final int DEFAULT_MIN_LENGTH = 8; + private static final int DEFAULT_MAX_LENGTH = 64; + private final RenameFix fix = new RenameFix(); + + public String getDisplayName() { + return "Class naming convention"; + } + + public String getGroupDisplayName() { + return GroupNames.NAMING_CONVENTIONS_GROUP_NAME; + } + + protected InspectionGadgetsFix buildFix(PsiElement location) { + return fix; + } + + protected boolean buildQuickFixesOnlyForOnTheFlyErrors() { + return true; + } + + public String buildErrorString(PsiElement location) { + final PsiClass aClass = (PsiClass) location.getParent(); + final String className = aClass.getName(); + if (className.length() < getMinLength()) { + return "Class name '#ref' is too short #loc"; + } else if (className.length() > getMaxLength()) { + return "Class name '#ref' is too long #loc"; + } + return "Class name '#ref' doesn't match regex '" + getRegex() + "' #loc"; + } + + protected String getDefaultRegex() { + return "[A-Z][A-Za-z]*"; + } + + protected int getDefaultMinLength() { + return DEFAULT_MIN_LENGTH; + } + + protected int getDefaultMaxLength() { + return DEFAULT_MAX_LENGTH; + } + + protected BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new NamingConventionsVisitor(this, inspectionManager, onTheFly); + } + + public ProblemDescriptor[] checkClass(PsiClass aClass, InspectionManager mgr, boolean isOnTheFly) { + if (!aClass.isPhysical()) { + return super.checkClass(aClass, mgr, isOnTheFly); + } + if (isOnTheFly && !InspectionGadgetsPlugin.isEnabled()) { + return super.checkClass(aClass, mgr, isOnTheFly); + } + + final BaseInspectionVisitor visitor = createVisitor(mgr, isOnTheFly); + aClass.accept(visitor); + return visitor.getErrors(); + } + + private class NamingConventionsVisitor extends BaseInspectionVisitor { + private NamingConventionsVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitClass(PsiClass aClass) { + if (aClass.isInterface() || aClass.isAnnotationType()) { + return; + } + final String name = aClass.getName(); + if (name == null) { + return; + } + if (isValid(name)) { + return; + } + registerClassError(aClass); + } + + } +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/naming/ConfusingMainMethodInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/naming/ConfusingMainMethodInspection.java new file mode 100644 index 000000000000..f74a823938f4 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/naming/ConfusingMainMethodInspection.java @@ -0,0 +1,80 @@ +package com.siyeh.ig.naming; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.psi.*; +import com.siyeh.ig.*; +import com.siyeh.ig.fixes.RenameFix; +import com.siyeh.ig.psiutils.TypeUtils; + +public class ConfusingMainMethodInspection extends MethodInspection { + private final RenameFix fix = new RenameFix(); + + public String getDisplayName() { + return "Confusing 'main()' method"; + } + + public String getGroupDisplayName() { + return GroupNames.NAMING_CONVENTIONS_GROUP_NAME; + } + + protected InspectionGadgetsFix buildFix(PsiElement location) { + return fix; + } + + protected boolean buildQuickFixesOnlyForOnTheFlyErrors() { + return true; + } + + public String buildErrorString(PsiElement location) { + return "Method named '#ref' without signature 'public static void main(String[])' #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new MethodNameSameAsParentClassNameVisitor(this, inspectionManager, onTheFly); + } + + private static class MethodNameSameAsParentClassNameVisitor extends BaseInspectionVisitor { + private MethodNameSameAsParentClassNameVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitMethod(PsiMethod aMethod) { + // no call to super, so it doesn't drill down into inner classes + final String methodName = aMethod.getName(); + if (!"main".equals(methodName)) { + return; + } + if (!aMethod.hasModifierProperty(PsiModifier.PUBLIC)) { + registerMethodError(aMethod); + return; + } + if (!aMethod.hasModifierProperty(PsiModifier.STATIC)) { + registerMethodError(aMethod); + return; + } + final PsiType returnType = aMethod.getReturnType(); + + if (!TypeUtils.typeEquals("void", returnType)) { + registerMethodError(aMethod); + return; + } + + final PsiParameterList paramList = aMethod.getParameterList(); + if (paramList == null) { + return; + } + final PsiParameter[] parameters = paramList.getParameters(); + if (parameters.length != 1) { + registerMethodError(aMethod); + return; + } + final PsiType paramType = parameters[0].getType(); + if (!TypeUtils.typeEquals("java.lang.String[]", paramType)) { + registerMethodError(aMethod); + return; + } + } + + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/naming/ConstantNamingConventionInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/naming/ConstantNamingConventionInspection.java new file mode 100644 index 000000000000..edba1a208b63 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/naming/ConstantNamingConventionInspection.java @@ -0,0 +1,103 @@ +package com.siyeh.ig.naming; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.codeInspection.ProblemDescriptor; +import com.intellij.psi.*; +import com.siyeh.ig.*; +import com.siyeh.ig.fixes.RenameFix; +import com.siyeh.ig.psiutils.ClassUtils; + +public class ConstantNamingConventionInspection extends ConventionInspection { + private static final int DEFAULT_MIN_LENGTH = 5; + private static final int DEFAULT_MAX_LENGTH = 32; + private final RenameFix fix = new RenameFix(); + + public String getDisplayName() { + return "Constant naming convention"; + } + + public String getGroupDisplayName() { + return GroupNames.NAMING_CONVENTIONS_GROUP_NAME; + } + + protected InspectionGadgetsFix buildFix(PsiElement location) { + return fix; + } + + protected boolean buildQuickFixesOnlyForOnTheFlyErrors() { + return true; + } + + public String buildErrorString(PsiElement location) { + final PsiField field = (PsiField) location.getParent(); + final String fieldName = field.getName(); + if (fieldName.length() < getMinLength()) { + return "Constant name '#ref' is too short #loc"; + } else if (fieldName.length() > getMaxLength()) { + return "Constant name '#ref' is too long #loc"; + } + return "Constant '#ref' doesn't match regex '" + getRegex() + "' #loc"; + } + + protected String getDefaultRegex() { + return "[A-Z_]*"; + } + + protected int getDefaultMinLength() { + return DEFAULT_MIN_LENGTH; + } + + protected int getDefaultMaxLength() { + return DEFAULT_MAX_LENGTH; + } + + protected BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new NamingConventionsVisitor(this, inspectionManager, onTheFly); + } + + public ProblemDescriptor[] checkField(PsiField field, InspectionManager mgr, boolean isOnTheFly) { + final PsiClass containingClass = field.getContainingClass(); + if (containingClass == null) { + return super.checkField(field, mgr, isOnTheFly); + } + if (!containingClass.isPhysical()) { + return super.checkField(field, mgr, isOnTheFly); + } + if (isOnTheFly && !InspectionGadgetsPlugin.isEnabled()) { + return super.checkField(field, mgr, isOnTheFly); + } + final BaseInspectionVisitor visitor = createVisitor(mgr, isOnTheFly); + field.accept(visitor); + return visitor.getErrors(); + } + + private class NamingConventionsVisitor extends BaseInspectionVisitor { + private NamingConventionsVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitField(PsiField field) { + super.visitField(field); + if (!field.hasModifierProperty(PsiModifier.STATIC) || + !field.hasModifierProperty(PsiModifier.FINAL)) { + return; + } + final String name = field.getName(); + if (name == null) { + return; + } + final PsiType type = field.getType(); + if (type == null) { + return; + } + if (!ClassUtils.isImmutable(type)) { + return; + } + if (isValid(name)) { + return; + } + registerFieldError(field); + } + + } +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/naming/ConventionInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/naming/ConventionInspection.java new file mode 100644 index 000000000000..f39110015825 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/naming/ConventionInspection.java @@ -0,0 +1,167 @@ +package com.siyeh.ig.naming; + +import com.intellij.openapi.util.InvalidDataException; +import com.siyeh.ig.BaseInspection; +import com.siyeh.ig.RegExFormatter; +import com.siyeh.ig.RegExInputVerifier; +import org.jdom.Element; + +import javax.swing.*; +import javax.swing.event.DocumentEvent; +import javax.swing.event.DocumentListener; +import javax.swing.text.Document; +import javax.swing.text.InternationalFormatter; +import java.awt.*; +import java.text.NumberFormat; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public abstract class ConventionInspection extends BaseInspection { + public String m_regex = getDefaultRegex(); // this is public for the DefaultJDomExternalizer + public int m_minLength = getDefaultMinLength(); // this is public for the DefaultJDomExternalizer + public int m_maxLength = getDefaultMaxLength(); // this is public for the DefaultJDomExternalizer + protected Pattern m_regexPattern = Pattern.compile(m_regex); + + protected abstract String getDefaultRegex(); + + protected abstract int getDefaultMinLength(); + + protected abstract int getDefaultMaxLength(); + + String getRegex() { + return m_regex; + } + + int getMinLength() { + return m_minLength; + } + + int getMaxLength() { + return m_maxLength; + } + + boolean isValid(String name) { + final int length = name.length(); + if (length < m_minLength) { + return false; + } + if (length > m_maxLength) { + return false; + } + if ("serialVersionUID".equals(name)) { + return true; + } + final Matcher matcher = m_regexPattern.matcher(name); + return matcher.matches(); + } + + public void readSettings(Element element) throws InvalidDataException { + super.readSettings(element); + m_regexPattern = Pattern.compile(m_regex); + } + + private static final int REGEX_COLUMN_COUNT = 25; + + public JComponent createOptionsPanel() { + final GridBagLayout layout = new GridBagLayout(); + final JPanel panel = new JPanel(layout); + + final JLabel patternLabel = new JLabel("Pattern:"); + patternLabel.setHorizontalAlignment(SwingConstants.TRAILING); + final JLabel minLengthLabel = new JLabel("Min Length:"); + minLengthLabel.setHorizontalAlignment(SwingConstants.TRAILING); + final JLabel maxLengthLabel = new JLabel("Max Length:"); + maxLengthLabel.setHorizontalAlignment(SwingConstants.TRAILING); + + final NumberFormat numberFormat = NumberFormat.getIntegerInstance(); + numberFormat.setParseIntegerOnly(true); + numberFormat.setMinimumIntegerDigits(1); + numberFormat.setMaximumIntegerDigits(2); + final InternationalFormatter formatter = new InternationalFormatter(numberFormat); + formatter.setAllowsInvalid(false); + formatter.setCommitsOnValidEdit(true); + + final JFormattedTextField minLengthField = new JFormattedTextField(formatter); + final Font panelFont = panel.getFont(); + minLengthField.setFont(panelFont); + minLengthField.setValue(new Integer(m_minLength)); + minLengthField.setColumns(2); + + final JFormattedTextField maxLengthField = new JFormattedTextField(formatter); + maxLengthField.setFont(panelFont); + maxLengthField.setValue(new Integer(m_maxLength)); + maxLengthField.setColumns(2); + + final JFormattedTextField regexField = new JFormattedTextField(new RegExFormatter()); + regexField.setFont(panelFont); + regexField.setValue(m_regexPattern); + regexField.setColumns(REGEX_COLUMN_COUNT); + regexField.setInputVerifier(new RegExInputVerifier()); + regexField.setFocusLostBehavior(JFormattedTextField.COMMIT); + + final DocumentListener listener = new DocumentListener() { + public void changedUpdate(DocumentEvent e) { + textChanged(); + } + + public void insertUpdate(DocumentEvent e) { + textChanged(); + } + + public void removeUpdate(DocumentEvent e) { + textChanged(); + } + + private void textChanged() { + m_regexPattern = (Pattern) regexField.getValue(); + m_regex = m_regexPattern.pattern(); + m_minLength = ((Number) minLengthField.getValue()).intValue(); + m_maxLength = ((Number) maxLengthField.getValue()).intValue(); + } + }; + final Document regexDocument = regexField.getDocument(); + regexDocument.addDocumentListener(listener); + final Document minLengthDocument = minLengthField.getDocument(); + minLengthDocument.addDocumentListener(listener); + final Document maxLengthDocument = maxLengthField.getDocument(); + maxLengthDocument.addDocumentListener(listener); + + final GridBagConstraints constraints = new GridBagConstraints(); + constraints.gridx = 0; + constraints.gridy = 0; + constraints.weightx = 1.0; + constraints.anchor = GridBagConstraints.EAST; + constraints.fill = GridBagConstraints.HORIZONTAL; + panel.add(patternLabel, constraints); + + constraints.gridx = 1; + constraints.gridy = 0; + constraints.gridwidth = 3; + constraints.anchor = GridBagConstraints.WEST; + panel.add(regexField, constraints); + + constraints.gridx = 0; + constraints.gridy = 1; + constraints.gridwidth = 1; + constraints.anchor = GridBagConstraints.EAST; + panel.add(minLengthLabel, constraints); + + constraints.gridx = 1; + constraints.gridy = 1; + constraints.anchor = GridBagConstraints.WEST; + panel.add(minLengthField, constraints); + + constraints.gridx = 2; + constraints.gridy = 1; + constraints.anchor = GridBagConstraints.EAST; + panel.add(maxLengthLabel, constraints); + + constraints.gridx = 3; + constraints.gridy = 1; + constraints.anchor = GridBagConstraints.WEST; + panel.add(maxLengthField, constraints); + + return panel; + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/naming/DollarSignInNameInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/naming/DollarSignInNameInspection.java new file mode 100644 index 000000000000..ff962e235bbf --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/naming/DollarSignInNameInspection.java @@ -0,0 +1,125 @@ +package com.siyeh.ig.naming; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.codeInspection.ProblemDescriptor; +import com.intellij.psi.*; +import com.siyeh.ig.*; +import com.siyeh.ig.fixes.RenameFix; + +public class DollarSignInNameInspection extends BaseInspection { + private final RenameFix fix = new RenameFix(); + + public String getDisplayName() { + return "Use of '$' in identifier"; + } + + public String getGroupDisplayName() { + return GroupNames.NAMING_CONVENTIONS_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "identifer '#ref' contains $ #loc"; + } + + protected InspectionGadgetsFix buildFix(PsiElement location) { + return fix; + } + + public ProblemDescriptor[] checkClass(PsiClass aClass, InspectionManager mgr, boolean isOnTheFly) { + if (isOnTheFly && !InspectionGadgetsPlugin.isEnabled()) { + return super.checkClass(aClass, mgr, isOnTheFly); + } + if (aClass instanceof PsiAnonymousClass) { + return super.checkClass(aClass, mgr, isOnTheFly); + } + final BaseInspectionVisitor visitor = createVisitor(mgr, isOnTheFly); + aClass.accept(visitor); + return visitor.getErrors(); + } + + public ProblemDescriptor[] checkMethod(PsiMethod method, InspectionManager mgr, boolean isOnTheFly) { + final PsiClass containingClass = method.getContainingClass(); + if (containingClass == null) { + return super.checkMethod(method, mgr, isOnTheFly); + } + if (!containingClass.isPhysical()) { + return super.checkMethod(method, mgr, isOnTheFly); + } + if (isOnTheFly && !InspectionGadgetsPlugin.isEnabled()) { + return super.checkMethod(method, mgr, isOnTheFly); + } + + if (containingClass instanceof PsiAnonymousClass) { + return super.checkClass(containingClass, mgr, isOnTheFly); + } + final BaseInspectionVisitor visitor = createVisitor(mgr, isOnTheFly); + method.accept(visitor); + return visitor.getErrors(); + } + + public ProblemDescriptor[] checkField(PsiField field, InspectionManager mgr, boolean isOnTheFly) { + final PsiClass containingClass = field.getContainingClass(); + if (containingClass == null) { + return super.checkField(field, mgr, isOnTheFly); + } + if (!containingClass.isPhysical()) { + return super.checkField(field, mgr, isOnTheFly); + } + if (containingClass instanceof PsiAnonymousClass) { + return super.checkClass(containingClass, mgr, isOnTheFly); + } + if (isOnTheFly && !InspectionGadgetsPlugin.isEnabled()) { + return super.checkField(field, mgr, isOnTheFly); + } + final BaseInspectionVisitor visitor = createVisitor(mgr, isOnTheFly); + field.accept(visitor); + return visitor.getErrors(); + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new DollarSignInNameVisitor(this, inspectionManager, onTheFly); + } + + private static class DollarSignInNameVisitor extends BaseInspectionVisitor { + private DollarSignInNameVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitVariable(PsiVariable variable) { + super.visitVariable(variable); + final String name = variable.getName(); + if (name == null) { + return; + } + if (name.indexOf((int) '$') < 0) { + return; + } + registerVariableError(variable); + } + + public void visitMethod(PsiMethod method) { + super.visitMethod(method); + final String name = method.getName(); + if (name == null) { + return; + } + if (name.indexOf((int) '$') < 0) { + return; + } + registerMethodError(method); + } + + public void visitClass(PsiClass aClass) { + //note: no call to super, to avoid drill-down + final String name = aClass.getName(); + if (name == null) { + return; + } + if (name.indexOf((int) '$') < 0) { + return; + } + registerClassError(aClass); + } + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/naming/ExceptionNameDoesntEndWithExceptionInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/naming/ExceptionNameDoesntEndWithExceptionInspection.java new file mode 100644 index 000000000000..0a8c8a7e1e35 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/naming/ExceptionNameDoesntEndWithExceptionInspection.java @@ -0,0 +1,60 @@ +package com.siyeh.ig.naming; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.psi.PsiClass; +import com.intellij.psi.PsiElement; +import com.siyeh.ig.*; +import com.siyeh.ig.fixes.RenameFix; +import com.siyeh.ig.psiutils.ClassUtils; + +public class ExceptionNameDoesntEndWithExceptionInspection extends ClassInspection { + private final RenameFix fix = new RenameFix(); + + public String getDisplayName() { + return "Exception class name doesn't end with Exception"; + } + + public String getGroupDisplayName() { + return GroupNames.NAMING_CONVENTIONS_GROUP_NAME; + } + + protected InspectionGadgetsFix buildFix(PsiElement location) { + return fix; + } + + protected boolean buildQuickFixesOnlyForOnTheFlyErrors() { + return true; + } + + public String buildErrorString(PsiElement location) { + return "Exception class name '#ref' doesn't end with 'Exception' #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new ExceptionNameDoesntEndWithExceptionVisitor(this, inspectionManager, onTheFly); + } + + private static class ExceptionNameDoesntEndWithExceptionVisitor extends BaseInspectionVisitor { + private ExceptionNameDoesntEndWithExceptionVisitor(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 into inner classes + final String className = aClass.getName(); + if (className == null) { + return; + } + if (className.endsWith("Exception")) { + return; + } + if (!ClassUtils.isSubclass(aClass, "java.lang.Exception")) { + return; + } + registerClassError(aClass); + } + + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/naming/InstanceMethodNamingConventionInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/naming/InstanceMethodNamingConventionInspection.java new file mode 100644 index 000000000000..e8dd4b292db6 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/naming/InstanceMethodNamingConventionInspection.java @@ -0,0 +1,116 @@ +package com.siyeh.ig.naming; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.codeInspection.ProblemDescriptor; +import com.intellij.psi.*; +import com.intellij.psi.util.PsiSuperMethodUtil; +import com.siyeh.ig.*; +import com.siyeh.ig.fixes.RenameFix; +import com.siyeh.ig.psiutils.LibraryUtil; + +public class InstanceMethodNamingConventionInspection extends ConventionInspection { + private static final int DEFAULT_MIN_LENGTH = 4; + private static final int DEFAULT_MAX_LENGTH = 32; + private final RenameFix fix = new RenameFix(); + + public String getDisplayName() { + return "Instance method naming convention"; + } + + public String getGroupDisplayName() { + return GroupNames.NAMING_CONVENTIONS_GROUP_NAME; + } + + protected InspectionGadgetsFix buildFix(PsiElement location) { + return fix; + } + + protected boolean buildQuickFixesOnlyForOnTheFlyErrors() { + return true; + } + + public String buildErrorString(PsiElement location) { + final PsiMethod method = (PsiMethod) location.getParent(); + final String methodName = method.getName(); + if (methodName.length() < getMinLength()) { + return "Instance method name '#ref' is too short #loc"; + } else if (methodName.length() > getMaxLength()) { + return "Instance method name '#ref' is too long #loc"; + } + return "Instance method name '#ref' doesn't match regex '" + getRegex() + "' #loc"; + } + + protected String getDefaultRegex() { + return "[a-z][A-Za-z]*"; + } + + protected int getDefaultMinLength() { + return DEFAULT_MIN_LENGTH; + } + + protected int getDefaultMaxLength() { + return DEFAULT_MAX_LENGTH; + } + + protected BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new NamingConventionsVisitor(this, inspectionManager, onTheFly); + } + + public ProblemDescriptor[] checkMethod(PsiMethod method, InspectionManager mgr, boolean isOnTheFly) { + final PsiClass containingClass = method.getContainingClass(); + if (containingClass == null) { + return super.checkMethod(method, mgr, isOnTheFly); + } + if (!containingClass.isPhysical()) { + return super.checkMethod(method, mgr, isOnTheFly); + } + if (isOnTheFly && !InspectionGadgetsPlugin.isEnabled()) { + return super.checkMethod(method, mgr, isOnTheFly); + } + final BaseInspectionVisitor visitor = createVisitor(mgr, isOnTheFly); + method.accept(visitor); + return visitor.getErrors(); + } + + private class NamingConventionsVisitor extends BaseInspectionVisitor { + private NamingConventionsVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitMethod(PsiMethod method) { + super.visitMethod(method); + if (method.isConstructor()) { + return; + } + if (method.hasModifierProperty(PsiModifier.STATIC)) { + return; + } + final String name = method.getName(); + if (name == null) { + return; + } + if (isValid(name)) { + return; + } + if (isOverrideOfLibraryMethod(method)) { + return; + } + registerMethodError(method); + } + + private boolean isOverrideOfLibraryMethod(PsiMethod method) { + final PsiMethod[] superMethods = PsiSuperMethodUtil.findSuperMethods(method); + + for (int i = 0; i < superMethods.length; i++) { + final PsiClass containingClass = + superMethods[i].getContainingClass(); + if (containingClass != null && + LibraryUtil.classIsInLibrary(containingClass)) { + return true; + } + } + return false; + } + + } +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/naming/InstanceVariableNamingConventionInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/naming/InstanceVariableNamingConventionInspection.java new file mode 100644 index 000000000000..715f629b1bc7 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/naming/InstanceVariableNamingConventionInspection.java @@ -0,0 +1,95 @@ +package com.siyeh.ig.naming; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.codeInspection.ProblemDescriptor; +import com.intellij.psi.*; +import com.siyeh.ig.*; +import com.siyeh.ig.fixes.RenameFix; + +public class InstanceVariableNamingConventionInspection extends ConventionInspection { + private static final int DEFAULT_MIN_LENGTH = 5; + private static final int DEFAULT_MAX_LENGTH = 32; + private final RenameFix fix = new RenameFix(); + + public String getDisplayName() { + return "Instance variable naming convention"; + } + + public String getGroupDisplayName() { + return GroupNames.NAMING_CONVENTIONS_GROUP_NAME; + } + + protected InspectionGadgetsFix buildFix(PsiElement location) { + return fix; + } + + protected boolean buildQuickFixesOnlyForOnTheFlyErrors() { + return true; + } + + public String buildErrorString(PsiElement location) { + final PsiField field = (PsiField) location.getParent(); + final String fieldName = field.getName(); + if (fieldName.length() < getMinLength()) { + return "Instance variable name '#ref' is too short #loc"; + } else if (fieldName.length() > getMaxLength()) { + return "Instance variable name '#ref' is too long #loc"; + } + return "Instance variable '#ref' doesn't match regex '" + getRegex() + "' #loc"; + } + + protected String getDefaultRegex() { + return "m_[a-z][A-Za-z]*"; + } + + protected int getDefaultMinLength() { + return DEFAULT_MIN_LENGTH; + } + + protected int getDefaultMaxLength() { + return DEFAULT_MAX_LENGTH; + } + + protected BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new NamingConventionsVisitor(this, inspectionManager, onTheFly); + } + + public ProblemDescriptor[] checkField(PsiField field, InspectionManager mgr, boolean isOnTheFly) { + final PsiClass containingClass = field.getContainingClass(); + if (containingClass == null) { + return super.checkField(field, mgr, isOnTheFly); + } + if (!containingClass.isPhysical()) { + return super.checkField(field, mgr, isOnTheFly); + } + if (isOnTheFly && !InspectionGadgetsPlugin.isEnabled()) { + return super.checkField(field, mgr, isOnTheFly); + } + final BaseInspectionVisitor visitor = createVisitor(mgr, isOnTheFly); + field.accept(visitor); + return visitor.getErrors(); + } + + private class NamingConventionsVisitor extends BaseInspectionVisitor { + private NamingConventionsVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitField(PsiField field) { + super.visitField(field); + if (field.hasModifierProperty(PsiModifier.STATIC)) { + return; + } + final String name = field.getName(); + if (name == null) { + return; + } + if (isValid(name)) { + return; + } + registerFieldError(field); + } + + + } +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/naming/InterfaceNamingConventionInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/naming/InterfaceNamingConventionInspection.java new file mode 100644 index 000000000000..8c29d35becbd --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/naming/InterfaceNamingConventionInspection.java @@ -0,0 +1,92 @@ +package com.siyeh.ig.naming; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.codeInspection.ProblemDescriptor; +import com.intellij.psi.PsiClass; +import com.intellij.psi.PsiElement; +import com.siyeh.ig.*; +import com.siyeh.ig.fixes.RenameFix; + +public class InterfaceNamingConventionInspection extends ConventionInspection { + private static final int DEFAULT_MIN_LENGTH = 8; + private static final int DEFAULT_MAX_LENGTH = 64; + private final RenameFix fix = new RenameFix(); + + public String getDisplayName() { + return "Interface naming convention"; + } + + public String getGroupDisplayName() { + return GroupNames.NAMING_CONVENTIONS_GROUP_NAME; + } + + protected InspectionGadgetsFix buildFix(PsiElement location) { + return fix; + } + + protected boolean buildQuickFixesOnlyForOnTheFlyErrors() { + return true; + } + + public String buildErrorString(PsiElement location) { + final PsiClass aClass = (PsiClass) location.getParent(); + final String className = aClass.getName(); + if (className.length() < getMinLength()) { + return "Interface name '#ref' is too short #loc"; + } else if (className.length() > getMaxLength()) { + return "Interface name '#ref' is too long #loc"; + } + return "Interface name '#ref' doesn't match regex '" + getRegex() + "' #loc"; + } + + protected String getDefaultRegex() { + return "[A-Z][A-Za-z]*"; + } + + protected int getDefaultMinLength() { + return DEFAULT_MIN_LENGTH; + } + + protected int getDefaultMaxLength() { + return DEFAULT_MAX_LENGTH; + } + + protected BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new NamingConventionsVisitor(this, inspectionManager, onTheFly); + } + + public ProblemDescriptor[] checkClass(PsiClass aClass, InspectionManager mgr, boolean isOnTheFly) { + + if (!aClass.isPhysical()) { + return super.checkClass(aClass, mgr, isOnTheFly); + } + if (isOnTheFly && !InspectionGadgetsPlugin.isEnabled()) { + return super.checkClass(aClass, mgr, isOnTheFly); + } + final BaseInspectionVisitor visitor = createVisitor(mgr, isOnTheFly); + aClass.accept(visitor); + + return visitor.getErrors(); + } + + private class NamingConventionsVisitor extends BaseInspectionVisitor { + private NamingConventionsVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitClass(PsiClass aClass) { + if (!aClass.isInterface() || aClass.isAnnotationType()) { + return; + } + final String name = aClass.getName(); + if (name == null) { + return; + } + if (isValid(name)) { + return; + } + registerClassError(aClass); + } + + } +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/naming/LocalVariableNamingConventionInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/naming/LocalVariableNamingConventionInspection.java new file mode 100644 index 000000000000..175ce137cef7 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/naming/LocalVariableNamingConventionInspection.java @@ -0,0 +1,267 @@ +package com.siyeh.ig.naming; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.codeInspection.ProblemDescriptor; +import com.intellij.psi.*; +import com.siyeh.ig.*; +import com.siyeh.ig.fixes.RenameFix; + +import javax.swing.*; +import javax.swing.event.ChangeEvent; +import javax.swing.event.ChangeListener; +import javax.swing.event.DocumentEvent; +import javax.swing.event.DocumentListener; +import javax.swing.text.Document; +import javax.swing.text.InternationalFormatter; +import java.awt.*; +import java.text.NumberFormat; +import java.util.regex.Pattern; + +public class LocalVariableNamingConventionInspection extends ConventionInspection { + public boolean m_ignoreForLoopParameters = false; + public boolean m_ignoreCatchParameters = false; + + private static final int DEFAULT_MIN_LENGTH = 1; + private static final int DEFAULT_MAX_LENGTH = 20; + private final RenameFix fix = new RenameFix(); + + public String getDisplayName() { + return "Local Variable naming convention"; + } + + public String getGroupDisplayName() { + return GroupNames.NAMING_CONVENTIONS_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + final PsiVariable var = (PsiVariable) location.getParent(); + final String varName = var.getName(); + if (varName.length() < getMinLength()) { + return "Local variable name '#ref' is too short #loc"; + } else if (varName.length() > getMaxLength()) { + return "Local variable name '#ref' is too long #loc"; + } else { + return "Local variable name '#ref' doesn't match regex '" + getRegex() + "' #loc"; + } + } + + protected InspectionGadgetsFix buildFix(PsiElement location) { + return fix; + } + + protected boolean buildQuickFixesOnlyForOnTheFlyErrors() { + return true; + } + + protected String getDefaultRegex() { + return "[a-z][A-Za-z]*"; + } + + protected int getDefaultMinLength() { + return DEFAULT_MIN_LENGTH; + } + + protected int getDefaultMaxLength() { + return DEFAULT_MAX_LENGTH; + } + + protected BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new NamingConventionsVisitor(this, inspectionManager, onTheFly); + } + + public ProblemDescriptor[] checkMethod(PsiMethod method, InspectionManager mgr, boolean isOnTheFly) { + final PsiClass containingClass = method.getContainingClass(); + if (containingClass == null) { + return super.checkMethod(method, mgr, isOnTheFly); + } + if (!containingClass.isPhysical()) { + return super.checkMethod(method, mgr, isOnTheFly); + } + if (isOnTheFly && !InspectionGadgetsPlugin.isEnabled()) { + return super.checkMethod(method, mgr, isOnTheFly); + } + final BaseInspectionVisitor visitor = createVisitor(mgr, isOnTheFly); + method.accept(visitor); + return visitor.getErrors(); + } + + private class NamingConventionsVisitor extends BaseInspectionVisitor { + private NamingConventionsVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitLocalVariable(PsiLocalVariable variable) { + super.visitLocalVariable(variable); + if (m_ignoreForLoopParameters) { + final PsiElement declStatement = variable.getParent(); + if (declStatement.getParent() instanceof PsiForStatement) { + final PsiForStatement forLoop = (PsiForStatement) declStatement.getParent(); + final PsiStatement initialization = forLoop.getInitialization(); + if (declStatement.equals(initialization)) { + return; + } + } + } + final String name = variable.getName(); + if (name == null) { + return; + } + if (isValid(name)) { + return; + } + registerVariableError(variable); + } + + public void visitParameter(PsiParameter variable) { + final boolean isCatchParameter = + variable.getParent() instanceof PsiTryStatement; + if (!isCatchParameter) { + return; + } + if (m_ignoreCatchParameters && isCatchParameter) { + return; + } + final String name = variable.getName(); + if (name == null) { + return; + } + if (isValid(name)) { + return; + } + registerVariableError(variable); + } + + } + + private static final int LOCAL_REGEX_COLUMN_COUNT = 25; + + public JComponent createOptionsPanel() { + final GridBagLayout layout = new GridBagLayout(); + final JPanel panel = new JPanel(layout); + + final JLabel patternLabel = new JLabel("Pattern:"); + patternLabel.setHorizontalAlignment(SwingConstants.TRAILING); + final JLabel minLengthLabel = new JLabel("Min Length:"); + minLengthLabel.setHorizontalAlignment(SwingConstants.TRAILING); + final JLabel maxLengthLabel = new JLabel("Max Length:"); + maxLengthLabel.setHorizontalAlignment(SwingConstants.TRAILING); + + final JCheckBox forLoopCheckBox = new JCheckBox("Ignore for-loop parameters", m_ignoreForLoopParameters); + final ButtonModel forLoopModel = forLoopCheckBox.getModel(); + forLoopModel.addChangeListener(new ChangeListener() { + public void stateChanged(ChangeEvent e) { + m_ignoreForLoopParameters = forLoopModel.isSelected(); + } + }); + final JCheckBox catchCheckBox = new JCheckBox("Ignore catch block parameters", m_ignoreCatchParameters); + final ButtonModel catchBlockModel = catchCheckBox.getModel(); + catchBlockModel.addChangeListener(new ChangeListener() { + public void stateChanged(ChangeEvent e) { + m_ignoreCatchParameters = catchBlockModel.isSelected(); + } + }); + + final NumberFormat format = NumberFormat.getIntegerInstance(); + format.setParseIntegerOnly(true); + format.setMinimumIntegerDigits(1); + format.setMaximumIntegerDigits(2); + final InternationalFormatter formatter = new InternationalFormatter(format); + formatter.setAllowsInvalid(false); + formatter.setCommitsOnValidEdit(true); + + final JFormattedTextField minLengthField = new JFormattedTextField(formatter); + final Font panelFont = panel.getFont(); + minLengthField.setFont(panelFont); + minLengthField.setValue(new Integer(m_minLength)); + minLengthField.setColumns(2); + + final JFormattedTextField maxLengthField = new JFormattedTextField(formatter); + maxLengthField.setFont(panelFont); + maxLengthField.setValue(new Integer(m_maxLength)); + maxLengthField.setColumns(2); + + final JFormattedTextField regexField = new JFormattedTextField(new RegExFormatter()); + regexField.setFont(panelFont); + regexField.setValue(m_regexPattern); + regexField.setColumns(LOCAL_REGEX_COLUMN_COUNT); + regexField.setInputVerifier(new RegExInputVerifier()); + regexField.setFocusLostBehavior(JFormattedTextField.COMMIT); + + final DocumentListener listener = new DocumentListener() { + public void changedUpdate(DocumentEvent e) { + textChanged(); + } + + public void insertUpdate(DocumentEvent e) { + textChanged(); + } + + public void removeUpdate(DocumentEvent e) { + textChanged(); + } + + private void textChanged() { + m_regexPattern = (Pattern) regexField.getValue(); + m_regex = m_regexPattern.pattern(); + m_minLength = ((Number) minLengthField.getValue()).intValue(); + m_maxLength = ((Number) maxLengthField.getValue()).intValue(); + } + }; + final Document regexDocument = regexField.getDocument(); + regexDocument.addDocumentListener(listener); + final Document minLengthDocument = minLengthField.getDocument(); + minLengthDocument.addDocumentListener(listener); + final Document maxLengthDocument = maxLengthField.getDocument(); + maxLengthDocument.addDocumentListener(listener); + + final GridBagConstraints constraints = new GridBagConstraints(); + constraints.gridx = 0; + constraints.gridy = 0; + constraints.weightx = 1.0; + constraints.anchor = GridBagConstraints.EAST; + constraints.fill = GridBagConstraints.HORIZONTAL; + panel.add(patternLabel, constraints); + + constraints.gridx = 1; + constraints.gridy = 0; + constraints.gridwidth = 3; + constraints.anchor = GridBagConstraints.WEST; + panel.add(regexField, constraints); + + constraints.gridx = 0; + constraints.gridy = 1; + constraints.gridwidth = 1; + constraints.anchor = GridBagConstraints.EAST; + panel.add(minLengthLabel, constraints); + + constraints.gridx = 1; + constraints.gridy = 1; + constraints.anchor = GridBagConstraints.WEST; + panel.add(minLengthField, constraints); + + constraints.gridx = 2; + constraints.gridy = 1; + constraints.anchor = GridBagConstraints.EAST; + panel.add(maxLengthLabel, constraints); + + constraints.gridx = 3; + constraints.gridy = 1; + constraints.anchor = GridBagConstraints.WEST; + panel.add(maxLengthField, constraints); + + constraints.gridx = 1; + constraints.gridy = 2; + constraints.gridwidth = 3; + constraints.anchor = GridBagConstraints.WEST; + panel.add(forLoopCheckBox, constraints); + + constraints.gridx = 1; + constraints.gridy = 3; + constraints.gridwidth = 3; + constraints.anchor = GridBagConstraints.WEST; + panel.add(catchCheckBox, constraints); + + return panel; + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/naming/MethodNameSameAsClassNameInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/naming/MethodNameSameAsClassNameInspection.java new file mode 100644 index 000000000000..ac2a6228b390 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/naming/MethodNameSameAsClassNameInspection.java @@ -0,0 +1,67 @@ +package com.siyeh.ig.naming; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.psi.PsiClass; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiMethod; +import com.siyeh.ig.*; +import com.siyeh.ig.fixes.RenameFix; + +public class MethodNameSameAsClassNameInspection extends MethodInspection { + + public String getDisplayName() { + return "Method name same as class name"; + } + + public String getGroupDisplayName() { + return GroupNames.NAMING_CONVENTIONS_GROUP_NAME; + } + + protected InspectionGadgetsFix buildFix(PsiElement location) { + final RenameFix fix = new RenameFix(); + return fix; + } + + protected boolean buildQuickFixesOnlyForOnTheFlyErrors() { + return true; + } + + public String buildErrorString(PsiElement location) { + return "Method name '#ref' is the same as it's class name #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new MethodNameSameAsClassNameVisitor(this, inspectionManager, onTheFly); + } + + private static class MethodNameSameAsClassNameVisitor extends BaseInspectionVisitor { + private MethodNameSameAsClassNameVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitMethod(PsiMethod method) { + // no call to super, so it doesn't drill down into inner classes + if (method.isConstructor()) { + return; + } + final String methodName = method.getName(); + if (methodName == null) { + return; + } + final PsiClass containingClass = method.getContainingClass(); + if (containingClass == null) { + return; + } + final String className = containingClass.getName(); + if (className == null) { + return; + } + if (!methodName.equals(className)) { + return; + } + registerMethodError(method); + } + + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/naming/MethodNameSameAsParentNameInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/naming/MethodNameSameAsParentNameInspection.java new file mode 100644 index 000000000000..958735fabfd4 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/naming/MethodNameSameAsParentNameInspection.java @@ -0,0 +1,69 @@ +package com.siyeh.ig.naming; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.psi.PsiClass; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiMethod; +import com.siyeh.ig.*; +import com.siyeh.ig.fixes.RenameFix; + +public class MethodNameSameAsParentNameInspection extends MethodInspection { + private final RenameFix fix = new RenameFix(); + + public String getDisplayName() { + return "Method name same as parent class name"; + } + + public String getGroupDisplayName() { + return GroupNames.NAMING_CONVENTIONS_GROUP_NAME; + } + + protected InspectionGadgetsFix buildFix(PsiElement location) { + return fix; + } + + protected boolean buildQuickFixesOnlyForOnTheFlyErrors() { + return true; + } + + public String buildErrorString(PsiElement location) { + return "Method name '#ref' is the same as it's parent class name #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new MethodNameSameAsParentClassNameVisitor(this, inspectionManager, onTheFly); + } + + private static class MethodNameSameAsParentClassNameVisitor extends BaseInspectionVisitor { + private MethodNameSameAsParentClassNameVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitMethod(PsiMethod method) { + // no call to super, so it doesn't drill down into inner classes + final String methodName = method.getName(); + if (methodName == null) { + return; + } + + final PsiClass containingClass = method.getContainingClass(); + if (containingClass == null) { + return; + } + final PsiClass parent = containingClass.getSuperClass(); + if (parent == null) { + return; + } + final String parentName = parent.getName(); + if (parentName == null) { + return; + } + if (!methodName.equals(parentName)) { + return; + } + registerMethodError(method); + } + + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/naming/NonExceptionNameEndsWithExceptionInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/naming/NonExceptionNameEndsWithExceptionInspection.java new file mode 100644 index 000000000000..32648ccdd691 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/naming/NonExceptionNameEndsWithExceptionInspection.java @@ -0,0 +1,60 @@ +package com.siyeh.ig.naming; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.psi.PsiClass; +import com.intellij.psi.PsiElement; +import com.siyeh.ig.*; +import com.siyeh.ig.fixes.RenameFix; +import com.siyeh.ig.psiutils.ClassUtils; + +public class NonExceptionNameEndsWithExceptionInspection extends ClassInspection { + private final RenameFix fix = new RenameFix(); + + public String getDisplayName() { + return "Non-exception class name ends with 'Exception'"; + } + + public String getGroupDisplayName() { + return GroupNames.NAMING_CONVENTIONS_GROUP_NAME; + } + + protected InspectionGadgetsFix buildFix(PsiElement location) { + return fix; + } + + protected boolean buildQuickFixesOnlyForOnTheFlyErrors() { + return true; + } + + public String buildErrorString(PsiElement location) { + return "Non-exception class name '#ref' ends with 'Exception' #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new NonExceptionNameEndsWithExceptionVisitor(this, inspectionManager, onTheFly); + } + + private static class NonExceptionNameEndsWithExceptionVisitor extends BaseInspectionVisitor { + private NonExceptionNameEndsWithExceptionVisitor(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 into inner classes + final String className = aClass.getName(); + if (className == null) { + return; + } + if (!className.endsWith("Exception")) { + return; + } + if (ClassUtils.isSubclass(aClass, "java.lang.Exception")) { + return; + } + registerClassError(aClass); + } + + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/naming/ParameterNamingConventionInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/naming/ParameterNamingConventionInspection.java new file mode 100644 index 000000000000..00d969bb332e --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/naming/ParameterNamingConventionInspection.java @@ -0,0 +1,94 @@ +package com.siyeh.ig.naming; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.codeInspection.ProblemDescriptor; +import com.intellij.psi.*; +import com.siyeh.ig.*; +import com.siyeh.ig.fixes.RenameFix; + +public class ParameterNamingConventionInspection extends ConventionInspection { + private static final int DEFAULT_MIN_LENGTH = 1; + private static final int DEFAULT_MAX_LENGTH = 20; + private final RenameFix fix = new RenameFix(); + + public String getDisplayName() { + return "Method parameter naming convention"; + } + + public String getGroupDisplayName() { + return GroupNames.NAMING_CONVENTIONS_GROUP_NAME; + } + + protected InspectionGadgetsFix buildFix(PsiElement location) { + return fix; + } + + protected boolean buildQuickFixesOnlyForOnTheFlyErrors() { + return true; + } + + public String buildErrorString(PsiElement location) { + final PsiParameter param = (PsiParameter) location.getParent(); + final String paramName = param.getName(); + if (paramName.length() < getMinLength()) { + return "Parameter name '#ref' is too short #loc"; + } else if (paramName.length() > getMaxLength()) { + return "Parameter name '#ref' is too long #loc"; + } else { + return "Parameter name '#ref' doesn't match regex '" + getRegex() + "' #loc"; + } + } + + protected String getDefaultRegex() { + return "[a-z][A-Za-z]*"; + } + + protected int getDefaultMinLength() { + return DEFAULT_MIN_LENGTH; + } + + protected int getDefaultMaxLength() { + return DEFAULT_MAX_LENGTH; + } + + protected BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new NamingConventionsVisitor(this, inspectionManager, onTheFly); + } + + public ProblemDescriptor[] checkMethod(PsiMethod method, InspectionManager mgr, boolean isOnTheFly) { + final PsiClass containingClass = method.getContainingClass(); + if (containingClass == null) { + return super.checkMethod(method, mgr, isOnTheFly); + } + if (!containingClass.isPhysical()) { + return super.checkMethod(method, mgr, isOnTheFly); + } + if (isOnTheFly && !InspectionGadgetsPlugin.isEnabled()) { + return super.checkMethod(method, mgr, isOnTheFly); + } + final BaseInspectionVisitor visitor = createVisitor(mgr, isOnTheFly); + method.accept(visitor); + return visitor.getErrors(); + } + + private class NamingConventionsVisitor extends BaseInspectionVisitor { + private NamingConventionsVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitParameter(PsiParameter variable) { + if (variable.getParent() instanceof PsiTryStatement) { + return; + } + final String name = variable.getName(); + if (name == null) { + return; + } + if (isValid(name)) { + return; + } + registerVariableError(variable); + } + + } +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/naming/StandardVariableNamesInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/naming/StandardVariableNamesInspection.java new file mode 100644 index 000000000000..42ec8efaa123 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/naming/StandardVariableNamesInspection.java @@ -0,0 +1,87 @@ +package com.siyeh.ig.naming; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiType; +import com.intellij.psi.PsiVariable; +import com.siyeh.ig.*; +import com.siyeh.ig.fixes.RenameFix; + +import java.util.HashMap; +import java.util.Map; + +public class StandardVariableNamesInspection extends VariableInspection { + + private static final Map s_expectedTypes = new HashMap(10); + private final RenameFix fix = new RenameFix(); + + static { + s_expectedTypes.put("b", "byte"); + s_expectedTypes.put("c", "char"); + s_expectedTypes.put("ch", "char"); + s_expectedTypes.put("d", "double"); + s_expectedTypes.put("f", "float"); + s_expectedTypes.put("i", "int"); + s_expectedTypes.put("j", "int"); + s_expectedTypes.put("k", "int"); + s_expectedTypes.put("m", "int"); + s_expectedTypes.put("n", "int"); + s_expectedTypes.put("l", "long"); + s_expectedTypes.put("s", "java.lang.String"); + s_expectedTypes.put("str", "java.lang.String"); + } + + public String getDisplayName() { + return "Standard variable names"; + } + + protected InspectionGadgetsFix buildFix(PsiElement location) { + return fix; + } + + protected boolean buildQuickFixesOnlyForOnTheFlyErrors() { + return true; + } + + public String getGroupDisplayName() { + return GroupNames.NAMING_CONVENTIONS_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + final String variableName = location.getText(); + final String expectedType = (String) s_expectedTypes.get(variableName); + return "Variable name '#ref' doesn't have type " + expectedType + " #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new ExceptionNameDoesntEndWithExceptionVisitor(this, inspectionManager, onTheFly); + } + + private static class ExceptionNameDoesntEndWithExceptionVisitor extends BaseInspectionVisitor { + private ExceptionNameDoesntEndWithExceptionVisitor(BaseInspection inspection, + InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitVariable(PsiVariable var) { + super.visitVariable(var); + final String variableName = var.getName(); + final String expectedType = (String) s_expectedTypes.get(variableName); + if (expectedType == null) { + return; + } + final PsiType type = var.getType(); + if (type == null) { + return; + } + final String typeText = type.getCanonicalText(); + if (typeText.equals(expectedType)) { + return; + } + registerVariableError(var); + } + + + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/naming/StaticMethodNamingConventionInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/naming/StaticMethodNamingConventionInspection.java new file mode 100644 index 000000000000..fa6328e5d832 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/naming/StaticMethodNamingConventionInspection.java @@ -0,0 +1,94 @@ +package com.siyeh.ig.naming; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.codeInspection.ProblemDescriptor; +import com.intellij.psi.*; +import com.siyeh.ig.*; +import com.siyeh.ig.fixes.RenameFix; + +public class StaticMethodNamingConventionInspection extends ConventionInspection { + private static final int DEFAULT_MIN_LENGTH = 4; + private static final int DEFAULT_MAX_LENGTH = 32; + private final RenameFix fix = new RenameFix(); + + public String getDisplayName() { + return "Static method naming convention"; + } + + protected InspectionGadgetsFix buildFix(PsiElement location) { + return fix; + } + + protected boolean buildQuickFixesOnlyForOnTheFlyErrors() { + return true; + } + + public String getGroupDisplayName() { + return GroupNames.NAMING_CONVENTIONS_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + final PsiMethod method = (PsiMethod) location.getParent(); + final String methodName = method.getName(); + if (methodName.length() < getMinLength()) { + return "Static method name '#ref' is too short #loc"; + } else if (methodName.length() > getMaxLength()) { + return "Static method name '#ref' is too long #loc"; + } + return "Static method name '#ref' doesn't match regex '" + getRegex() + "' #loc"; + } + + protected String getDefaultRegex() { + return "[a-z][A-Za-z]*"; + } + + protected int getDefaultMinLength() { + return DEFAULT_MIN_LENGTH; + } + + protected int getDefaultMaxLength() { + return DEFAULT_MAX_LENGTH; + } + + protected BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new NamingConventionsVisitor(this, inspectionManager, onTheFly); + } + + public ProblemDescriptor[] checkMethod(PsiMethod method, InspectionManager mgr, boolean isOnTheFly) { + final PsiClass containingClass = method.getContainingClass(); + if (containingClass == null) { + return super.checkMethod(method, mgr, isOnTheFly); + } + if (!containingClass.isPhysical()) { + return super.checkMethod(method, mgr, isOnTheFly); + } + if (isOnTheFly && !InspectionGadgetsPlugin.isEnabled()) { + return super.checkMethod(method, mgr, isOnTheFly); + } + final BaseInspectionVisitor visitor = createVisitor(mgr, isOnTheFly); + method.accept(visitor); + return visitor.getErrors(); + } + + private class NamingConventionsVisitor extends BaseInspectionVisitor { + private NamingConventionsVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitMethod(PsiMethod method) { + super.visitMethod(method); + if (!method.hasModifierProperty(PsiModifier.STATIC)) { + return; + } + final String name = method.getName(); + if (name == null) { + return; + } + if (isValid(name)) { + return; + } + registerMethodError(method); + } + + } +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/naming/StaticVariableNamingConventionInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/naming/StaticVariableNamingConventionInspection.java new file mode 100644 index 000000000000..cf6759875c49 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/naming/StaticVariableNamingConventionInspection.java @@ -0,0 +1,105 @@ +package com.siyeh.ig.naming; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.codeInspection.ProblemDescriptor; +import com.intellij.psi.*; +import com.siyeh.ig.*; +import com.siyeh.ig.fixes.RenameFix; +import com.siyeh.ig.psiutils.ClassUtils; + +public class StaticVariableNamingConventionInspection extends ConventionInspection { + private static final int DEFAULT_MIN_LENGTH = 5; + private static final int DEFAULT_MAX_LENGTH = 32; + private final RenameFix fix = new RenameFix(); + + public String getDisplayName() { + return "Static variable naming convention"; + } + + public String getGroupDisplayName() { + return GroupNames.NAMING_CONVENTIONS_GROUP_NAME; + } + + protected InspectionGadgetsFix buildFix(PsiElement location) { + return fix; + } + + protected boolean buildQuickFixesOnlyForOnTheFlyErrors() { + return true; + } + + public String buildErrorString(PsiElement location) { + final PsiField field = (PsiField) location.getParent(); + final String fieldName = field.getName(); + if (fieldName.length() < getMinLength()) { + return "Static variable name '#ref' is too short #loc"; + } else if (fieldName.length() > getMaxLength()) { + return "Static variable name '#ref' is too long #loc"; + } + return "Static variable '#ref' doesn't match regex '" + getRegex() + "' #loc"; + } + + protected String getDefaultRegex() { + return "s_[a-z][A-Za-z]*"; + } + + protected int getDefaultMinLength() { + return DEFAULT_MIN_LENGTH; + } + + protected int getDefaultMaxLength() { + return DEFAULT_MAX_LENGTH; + } + + protected BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new NamingConventionsVisitor(this, inspectionManager, onTheFly); + } + + public ProblemDescriptor[] checkField(PsiField field, InspectionManager mgr, boolean isOnTheFly) { + final PsiClass containingClass = field.getContainingClass(); + if (containingClass == null) { + return super.checkField(field, mgr, isOnTheFly); + } + if (!containingClass.isPhysical()) { + return super.checkField(field, mgr, isOnTheFly); + } + if (isOnTheFly && !InspectionGadgetsPlugin.isEnabled()) { + return super.checkField(field, mgr, isOnTheFly); + } + final BaseInspectionVisitor visitor = createVisitor(mgr, isOnTheFly); + field.accept(visitor); + return visitor.getErrors(); + } + + private class NamingConventionsVisitor extends BaseInspectionVisitor { + private NamingConventionsVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitField(PsiField field) { + if (!field.hasModifierProperty(PsiModifier.STATIC)) { + return; + } + if (field.hasModifierProperty(PsiModifier.FINAL)) { + return; + } + final String name = field.getName(); + if (name == null) { + return; + } + + final PsiType type = field.getType(); + if (type == null) { + return; + } + if (!ClassUtils.isImmutable(type)) { + return; + } + if (isValid(name)) { + return; + } + registerFieldError(field); + } + + } +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/naming/UpperCaseFieldNameNotConstantInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/naming/UpperCaseFieldNameNotConstantInspection.java new file mode 100644 index 000000000000..e21aa4657e66 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/naming/UpperCaseFieldNameNotConstantInspection.java @@ -0,0 +1,61 @@ +package com.siyeh.ig.naming; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiField; +import com.intellij.psi.PsiModifier; +import com.siyeh.ig.*; +import com.siyeh.ig.fixes.RenameFix; + +public class UpperCaseFieldNameNotConstantInspection extends FieldInspection { + private final RenameFix fix = new RenameFix(); + + + public String getDisplayName() { + return "Non-constant field with upper-case name"; + } + + protected InspectionGadgetsFix buildFix(PsiElement location) { + return fix; + } + + protected boolean buildQuickFixesOnlyForOnTheFlyErrors() { + return true; + } + + public String getGroupDisplayName() { + return GroupNames.NAMING_CONVENTIONS_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "Non-constant field '#ref' with constant-style name #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new ExceptionNameDoesntEndWithExceptionVisitor(this, inspectionManager, onTheFly); + } + + private static class ExceptionNameDoesntEndWithExceptionVisitor extends BaseInspectionVisitor { + private ExceptionNameDoesntEndWithExceptionVisitor(BaseInspection inspection, + InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitField(PsiField field) { + super.visitField(field); + if(field.hasModifierProperty(PsiModifier.STATIC) && + field.hasModifierProperty(PsiModifier.FINAL)) + { + return; + } + final String fieldName = field.getName(); + if(!fieldName.toUpperCase().equals(fieldName)) + { + return; + } + registerFieldError(field); + } + + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/performance/BooleanConstructorInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/performance/BooleanConstructorInspection.java new file mode 100644 index 000000000000..746295f6fa4c --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/performance/BooleanConstructorInspection.java @@ -0,0 +1,70 @@ +package com.siyeh.ig.performance; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.codeInspection.ProblemDescriptor; +import com.intellij.openapi.project.Project; +import com.intellij.psi.*; +import com.siyeh.ig.*; +import com.siyeh.ig.psiutils.TypeUtils; + +public class BooleanConstructorInspection extends ExpressionInspection { + private final BooleanConstructorFix fix = new BooleanConstructorFix(); + + public String getDisplayName() { + return "Boolean constructor call"; + } + + public String getGroupDisplayName() { + return GroupNames.PERFORMANCE_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "Boolean constructor call #ref #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new BooleanConstructorVisitor(this, inspectionManager, onTheFly); + } + + public InspectionGadgetsFix buildFix(PsiElement location) { + return fix; + } + + private static class BooleanConstructorFix extends InspectionGadgetsFix { + public String getName() { + return "Simplify"; + } + + public void applyFix(Project project, ProblemDescriptor descriptor) { + final PsiNewExpression expression = (PsiNewExpression) descriptor.getPsiElement(); + final PsiExpressionList argList = expression.getArgumentList(); + final PsiExpression[] args = argList.getExpressions(); + final String text = args[0].getText(); + final String newExpression; + if ("true".equals(text)) { + newExpression = "Boolean.TRUE"; + } else if ("false".equals(text)) { + newExpression = "Boolean.FALSE"; + } else { + newExpression = "Boolean.valueOf(" + text + ')'; + } + replaceExpression(project, expression, newExpression); + } + } + + private static class BooleanConstructorVisitor extends BaseInspectionVisitor { + private BooleanConstructorVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitNewExpression(PsiNewExpression expression) { + super.visitNewExpression(expression); + final PsiType type = expression.getType(); + if (!TypeUtils.typeEquals("java.lang.Boolean", type)) { + return; + } + registerError(expression); + } + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/performance/CanBeStaticVisitor.java b/plugins/InspectionGadgets/src/com/siyeh/ig/performance/CanBeStaticVisitor.java new file mode 100644 index 000000000000..cc0eaf70ef24 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/performance/CanBeStaticVisitor.java @@ -0,0 +1,33 @@ +package com.siyeh.ig.performance; + +import com.intellij.psi.*; + +class CanBeStaticVisitor extends PsiRecursiveElementVisitor { + private boolean m_canBeStatic = true; + + CanBeStaticVisitor() { + super(); + } + + 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 element = ref.resolve(); + if (element instanceof PsiField) { + final PsiField field = (PsiField) element; + if (!field.hasModifierProperty(PsiModifier.STATIC)) { + m_canBeStatic = false; + } + } + } + + public boolean canBeStatic() { + return m_canBeStatic; + } +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/performance/CollectionsMustHaveInitialCapacityInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/performance/CollectionsMustHaveInitialCapacityInspection.java new file mode 100644 index 000000000000..8aeee8c7070f --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/performance/CollectionsMustHaveInitialCapacityInspection.java @@ -0,0 +1,56 @@ +package com.siyeh.ig.performance; + +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.CollectionUtils; + +public class CollectionsMustHaveInitialCapacityInspection extends ExpressionInspection { + + public String getDisplayName() { + return "Collection without initial capacity"; + } + + public String getGroupDisplayName() { + return GroupNames.PERFORMANCE_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "#ref without initial capacity #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new CollectionInitialCapacityVisitor(this, inspectionManager, onTheFly); + } + + private static class CollectionInitialCapacityVisitor extends BaseInspectionVisitor { + private CollectionInitialCapacityVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitNewExpression(PsiNewExpression expression) { + super.visitNewExpression(expression); + final PsiType type = expression.getType(); + + if (type == null) { + return; + } + if (!CollectionUtils.isCollectionWithInitialCapacity(type)) { + return; + } + final PsiExpressionList argumentList = expression.getArgumentList(); + if (argumentList == null) { + return; + } + final PsiExpression[] parameters = argumentList.getExpressions(); + if (parameters.length != 0) { + return; + } + registerError(expression); + } + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/performance/FieldMayBeStaticInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/performance/FieldMayBeStaticInspection.java new file mode 100644 index 000000000000..d4f0121b724a --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/performance/FieldMayBeStaticInspection.java @@ -0,0 +1,93 @@ +package com.siyeh.ig.performance; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.codeInspection.ProblemDescriptor; +import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.project.Project; +import com.intellij.psi.*; +import com.intellij.util.IncorrectOperationException; +import com.siyeh.ig.*; +import com.siyeh.ig.psiutils.ClassUtils; +import com.siyeh.ig.psiutils.SideEffectChecker; + +public class FieldMayBeStaticInspection extends FieldInspection { + private static final Logger s_logger = Logger.getInstance("FieldMayBeStaticInspection"); + private final MakeStaticFix fix = new MakeStaticFix(); + + public String getDisplayName() { + return "Field may be 'static'"; + } + + public String getGroupDisplayName() { + return GroupNames.PERFORMANCE_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "Field #ref may be 'static' #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new FieldMayBeStaticVisitor(this, inspectionManager, onTheFly); + } + + public InspectionGadgetsFix buildFix(PsiElement location) { + return fix; + } + + private static class MakeStaticFix extends InspectionGadgetsFix { + public String getName() { + return "Make static"; + } + + public void applyFix(Project project, ProblemDescriptor descriptor) { + final PsiJavaToken m_fieldNameToken = (PsiJavaToken) descriptor.getPsiElement(); + try { + final PsiField field = (PsiField) m_fieldNameToken.getParent(); + final PsiModifierList modifiers = field.getModifierList(); + modifiers.setModifierProperty(PsiModifier.STATIC, true); + } catch (IncorrectOperationException e) { + s_logger.error(e); + } + } + } + + private static class FieldMayBeStaticVisitor extends BaseInspectionVisitor { + private FieldMayBeStaticVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitField(PsiField field) { + if (field.hasModifierProperty(PsiModifier.STATIC)) { + return; + } + if (!field.hasModifierProperty(PsiModifier.FINAL)) { + return; + } + final PsiExpression initializer = field.getInitializer(); + if (initializer == null) { + return; + } + if (SideEffectChecker.mayHaveSideEffects(initializer)) { + return; + } + if (!canBeStatic(initializer)) { + return; + } + final PsiType type = field.getType(); + if (type == null) { + return; + } + + if (!ClassUtils.isImmutable(type)) { + return; + } + registerFieldError(field); + } + + private static boolean canBeStatic(PsiExpression initializer) { + final CanBeStaticVisitor canBeStaticVisitor = new CanBeStaticVisitor(); + initializer.accept(canBeStaticVisitor); + return canBeStaticVisitor.canBeStatic(); + } + } +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/performance/FieldRepeatedlyAccessedInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/performance/FieldRepeatedlyAccessedInspection.java new file mode 100644 index 000000000000..fd0ed895b9d5 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/performance/FieldRepeatedlyAccessedInspection.java @@ -0,0 +1,65 @@ +package com.siyeh.ig.performance; + +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.MethodInspection; +import com.siyeh.ig.ui.SingleCheckboxOptionsPanel; + +import javax.swing.*; +import java.util.Iterator; +import java.util.Set; + +public class FieldRepeatedlyAccessedInspection extends MethodInspection { + public boolean m_ignoreFinalFields = false; + + public String getDisplayName() { + return "Field repeatedly accessed in method"; + } + + public String getGroupDisplayName() { + return GroupNames.PERFORMANCE_GROUP_NAME; + } + + public String buildErrorString(Object arg) { + final String fieldName = ((PsiNamedElement) arg).getName(); + return "Field " + fieldName + " accessed repeatedly in method #ref #loc"; + } + + public JComponent createOptionsPanel() { + return new SingleCheckboxOptionsPanel("Ignore final fields", + this, "m_ignoreFinalFields"); + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new InstanceVariableRepeatedlyAccessedVisitor(this, inspectionManager, onTheFly); + } + + private class InstanceVariableRepeatedlyAccessedVisitor extends BaseInspectionVisitor { + private InstanceVariableRepeatedlyAccessedVisitor(BaseInspection inspection, + InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitMethod(PsiMethod method) { + final PsiIdentifier nameIdentifier = method.getNameIdentifier(); + if (nameIdentifier == null) { + return; + } + final VariableAccessVisitor visitor = new VariableAccessVisitor(); + method.accept(visitor); + final Set fields = visitor.getOveraccessedFields(); + for (Iterator iterator = fields.iterator(); iterator.hasNext();) { + final PsiField field = (PsiField) iterator.next(); + if (!m_ignoreFinalFields || + !field.hasModifierProperty(PsiModifier.FINAL)) { + registerError(nameIdentifier, field); + } + } + } + + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/performance/InnerClassMayBeStaticInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/performance/InnerClassMayBeStaticInspection.java new file mode 100644 index 000000000000..640ab29adefc --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/performance/InnerClassMayBeStaticInspection.java @@ -0,0 +1,96 @@ +package com.siyeh.ig.performance; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.codeInspection.ProblemDescriptor; +import com.intellij.psi.*; +import com.intellij.psi.search.PsiSearchHelper; +import com.intellij.psi.search.GlobalSearchScope; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.diagnostic.Logger; +import com.intellij.util.IncorrectOperationException; +import com.siyeh.ig.*; + +public class InnerClassMayBeStaticInspection extends ClassInspection { + private final InnerClassMayBeStaticFix fix = new InnerClassMayBeStaticFix(); + + public String getDisplayName() { + return "Inner class may be 'static'"; + } + + public String getGroupDisplayName() { + return GroupNames.PERFORMANCE_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "Inner class #ref may be 'static' #loc"; + } + + protected InspectionGadgetsFix buildFix(PsiElement location) { + return fix; + } + + private static class InnerClassMayBeStaticFix extends InspectionGadgetsFix { + public String getName() { + return "Make static"; + } + + public void applyFix(Project project, ProblemDescriptor descriptor) { + final PsiJavaToken classNameToken = (PsiJavaToken) descriptor.getPsiElement(); + try { + final PsiClass innerClass = (PsiClass) classNameToken.getParent(); + final PsiManager manager = innerClass.getManager(); + final PsiSearchHelper searchHelper = manager.getSearchHelper(); + final GlobalSearchScope useScope = innerClass.getUseScope(); + final PsiReference[] references = searchHelper.findReferences(innerClass, useScope, false); + for (int i = 0; i < references.length; i++) { + final PsiReference reference = references[i]; + final PsiElement element = reference.getElement(); + final PsiElement parent = element.getParent(); + if (parent instanceof PsiNewExpression) { + final PsiNewExpression newExpression = (PsiNewExpression) parent; + final PsiExpression qualifier = newExpression.getQualifier(); + if (qualifier != null) { + qualifier.delete(); + } + } + } + final PsiModifierList modifiers = innerClass.getModifierList(); + modifiers.setModifierProperty(PsiModifier.STATIC, true); + } catch (IncorrectOperationException e) { + final Class aClass = getClass(); + final String className = aClass.getName(); + final Logger logger = Logger.getInstance(className); + logger.error(e); + } + } + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new InnerClassCanBeStaticVisitor(this, inspectionManager, + onTheFly); + } + + private static class InnerClassCanBeStaticVisitor + extends BaseInspectionVisitor { + private InnerClassCanBeStaticVisitor(BaseInspection inspection, + InspectionManager inspectionManager, + boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitClass(PsiClass aClass) { + // no call to super, so that it doesn't drill down to inner classes + final PsiClass[] innerClasses = aClass.getInnerClasses(); + for (int i = 0; i < innerClasses.length; i++) { + final PsiClass innerClass = innerClasses[i]; + if (!innerClass.hasModifierProperty(PsiModifier.STATIC)) { + final InnerClassReferenceVisitor visitor = new InnerClassReferenceVisitor(innerClass); + innerClass.accept(visitor); + if (visitor.areReferenceStaticallyAccessible()) { + registerClassError(innerClass); + } + } + } + } + } +} \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/performance/InnerClassReferenceVisitor.java b/plugins/InspectionGadgets/src/com/siyeh/ig/performance/InnerClassReferenceVisitor.java new file mode 100644 index 000000000000..d8219ffeb847 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/performance/InnerClassReferenceVisitor.java @@ -0,0 +1,89 @@ +package com.siyeh.ig.performance; + +import com.intellij.psi.*; +import com.intellij.psi.util.InheritanceUtil; + +class InnerClassReferenceVisitor extends PsiRecursiveElementVisitor { + private PsiClass m_innerClass; + private boolean m_referencesStaticallyAccessible = true; + + InnerClassReferenceVisitor(PsiClass innerClass) { + super(); + m_innerClass = innerClass; + } + + public boolean areReferenceStaticallyAccessible() { + return m_referencesStaticallyAccessible; + } + + private boolean isClassStaticallyAccessible(PsiClass aClass) { + if (aClass.hasModifierProperty(PsiModifier.STATIC)) { + return true; + } + if (InheritanceUtil.isInheritorOrSelf(m_innerClass, aClass, true)) { + return true; + } + PsiClass classScope = aClass; + final PsiClass outerClass = (PsiClass) m_innerClass.getContext(); + while (classScope != null) { + if (InheritanceUtil.isInheritorOrSelf(outerClass, classScope, true)) { + return false; + } + final PsiElement scope = classScope.getScope(); + if (scope instanceof PsiClass) { + classScope = (PsiClass) scope; + } else { + classScope = null; + } + } + return true; + } + + public void visitReferenceElement(PsiJavaCodeReferenceElement referenceElement) { + super.visitReferenceElement(referenceElement); + final PsiElement element = referenceElement.resolve(); + if (!(element instanceof PsiClass)) { + return; + } + final PsiClass aClass = (PsiClass) element; + final PsiElement scope = aClass.getScope(); + if (!(scope instanceof PsiClass)) { + return; + } + m_referencesStaticallyAccessible &= + aClass.hasModifierProperty(PsiModifier.STATIC); + } + + public void visitReferenceExpression(PsiReferenceExpression referenceExpression) { + final PsiExpression qualifier = referenceExpression.getQualifierExpression(); + if (qualifier != null) { + qualifier.accept(this); + } + final PsiReferenceParameterList typeParameters = referenceExpression.getParameterList(); + if (typeParameters != null) { + typeParameters.accept(this); + } + + if (qualifier instanceof PsiSuperExpression) { + return; + } + if (qualifier instanceof PsiReferenceExpression) { + final PsiReferenceExpression expression = (PsiReferenceExpression) qualifier; + final PsiElement resolvedExpression = expression.resolve(); + if (!(resolvedExpression instanceof PsiField) && + !(resolvedExpression instanceof PsiMethod)) { + return; + } + } + final PsiElement element = referenceExpression.resolve(); + if (element instanceof PsiMethod || element instanceof PsiField) { + final PsiMember member = (PsiMember) element; + if (member.hasModifierProperty(PsiModifier.STATIC)) { + return; + } + final PsiClass containingClass = member.getContainingClass(); + m_referencesStaticallyAccessible &= + isClassStaticallyAccessible(containingClass); + } + } +} \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/performance/JavaLangReflectInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/performance/JavaLangReflectInspection.java new file mode 100644 index 000000000000..25489f5b954d --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/performance/JavaLangReflectInspection.java @@ -0,0 +1,53 @@ +package com.siyeh.ig.performance; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiType; +import com.intellij.psi.PsiTypeElement; +import com.intellij.psi.PsiVariable; +import com.siyeh.ig.BaseInspection; +import com.siyeh.ig.BaseInspectionVisitor; +import com.siyeh.ig.GroupNames; +import com.siyeh.ig.VariableInspection; + +public class JavaLangReflectInspection extends VariableInspection { + + public String getDisplayName() { + return "Use of java.lang.reflect"; + } + + public String getGroupDisplayName() { + return GroupNames.PERFORMANCE_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "Use of type #ref from java.lang.reflect #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new JavaLangReflectVisitor(this, inspectionManager, onTheFly); + } + + private static class JavaLangReflectVisitor extends BaseInspectionVisitor { + private JavaLangReflectVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitVariable(PsiVariable variable) { + super.visitVariable(variable); + final PsiType type = variable.getType(); + if (type == null) { + return; + } + final PsiType componentType = type.getDeepComponentType(); + final String typeName = componentType.getCanonicalText(); + if (!typeName.startsWith("java.lang.reflect.")) { + return; + } + final PsiTypeElement typeElement = variable.getTypeElement(); + registerError(typeElement); + } + + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/performance/LengthOneStringsInConcatenationInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/performance/LengthOneStringsInConcatenationInspection.java new file mode 100644 index 000000000000..b94ee604686e --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/performance/LengthOneStringsInConcatenationInspection.java @@ -0,0 +1,151 @@ +package com.siyeh.ig.performance; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.codeInspection.ProblemDescriptor; +import com.intellij.openapi.project.Project; +import com.intellij.psi.*; +import com.siyeh.ig.*; +import com.siyeh.ig.psiutils.TypeUtils; + +public class LengthOneStringsInConcatenationInspection extends ExpressionInspection { + private final ReplaceStringsWithCharsFix fix = new ReplaceStringsWithCharsFix(); + + public String getDisplayName() { + return "Single character string concatenation"; + } + + public String getGroupDisplayName() { + return GroupNames.PERFORMANCE_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + final String text = location.getText(); + final int length = text.length(); + final String transformedText = '\'' + text.substring(1, length - 1) + '\''; + return "#ref can be replaced by " + transformedText + " #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new LengthOneStringsInConcatenationVisitor(this, inspectionManager, onTheFly); + } + + public InspectionGadgetsFix buildFix(PsiElement location) { + return fix; + } + + private static class ReplaceStringsWithCharsFix extends InspectionGadgetsFix { + public String getName() { + return "Replace with character"; + } + + public void applyFix(Project project, ProblemDescriptor descriptor) { + final PsiExpression expression = (PsiExpression) descriptor.getPsiElement(); + final String text = expression.getText(); + final int length = text.length(); + final String character = text.substring(1, length - 1); + final String charLiteral; + if ("\'".equals(character)) { + charLiteral = "'\\''"; + } else { + charLiteral = '\'' + character + '\''; + } + replaceExpression(project, expression, charLiteral); + } + } + + private static class LengthOneStringsInConcatenationVisitor extends BaseInspectionVisitor { + private LengthOneStringsInConcatenationVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitLiteralExpression(PsiLiteralExpression expression) { + super.visitLiteralExpression(expression); + final PsiType type = expression.getType(); + if (!TypeUtils.isJavaLangString(type)) { + return; + } + final String value = (String) expression.getValue(); + if (value == null) { + return; + } + if (value.length() != 1) { + return; + } + if (!isArgumentOfConcatenation(expression) && + !isArgumentOfStringAppend(expression)) { + return; + } + registerError(expression); + } + + private static boolean isArgumentOfConcatenation(PsiExpression expression) { + final PsiElement parent = expression.getParent(); + if (!(parent instanceof PsiBinaryExpression)) { + return false; + } + final PsiBinaryExpression binaryExp = (PsiBinaryExpression) parent; + final PsiJavaToken sign = binaryExp.getOperationSign(); + if (sign == null) { + return false; + } + if (sign.getTokenType() != JavaTokenType.PLUS) { + return false; + } + final PsiExpression sibling; + final PsiExpression lhs = binaryExp.getLOperand(); + if (lhs.equals(expression)) { + sibling = binaryExp.getROperand(); + } else { + sibling = lhs; + } + if (sibling == null) { + return false; + } + final PsiType siblingType = sibling.getType(); + if (!TypeUtils.isJavaLangString(siblingType)) { + return false; + } + return true; + } + + static boolean isArgumentOfStringAppend(PsiExpression expression) { + final PsiElement parent = expression.getParent(); + if (parent == null) { + return false; + } + if (!(parent instanceof PsiExpressionList)) { + return false; + } + final PsiExpressionList paramList = (PsiExpressionList) parent; + final PsiExpression[] parameters = paramList.getExpressions(); + if (parameters == null) { + return false; + } + if (parameters.length != 1) { + return false; + } + final PsiElement grandparent = parent.getParent(); + if (!(grandparent instanceof PsiMethodCallExpression)) { + return false; + } + final PsiMethodCallExpression call = (PsiMethodCallExpression) grandparent; + final PsiReferenceExpression methodExpression = call.getMethodExpression(); + final String name = methodExpression.getReferenceName(); + if (!"append".equals(name)) { + return false; + } + final PsiMethod method = call.resolveMethod(); + if (method == null) { + return false; + } + final PsiClass methodClass = method.getContainingClass(); + if (methodClass == null) { + return false; + } + final String className = methodClass.getQualifiedName(); + return "java.lang.StringBuffer".equals(className) || + "java.lang.StringBuilder".equals(className); + } + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/performance/ManualArrayCopyInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/performance/ManualArrayCopyInspection.java new file mode 100644 index 000000000000..2904e02d2a21 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/performance/ManualArrayCopyInspection.java @@ -0,0 +1,321 @@ +package com.siyeh.ig.performance; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.codeInspection.ProblemDescriptor; +import com.intellij.openapi.project.Project; +import com.intellij.psi.*; +import com.intellij.psi.tree.IElementType; +import com.siyeh.ig.*; +import com.siyeh.ig.psiutils.ParenthesesUtils; +import com.siyeh.ig.psiutils.SideEffectChecker; + +public class ManualArrayCopyInspection extends ExpressionInspection { + private final ManualArrayCopyFix fix = new ManualArrayCopyFix(); + + public String getDisplayName() { + return "Manual array copy"; + } + + public String getGroupDisplayName() { + return GroupNames.PERFORMANCE_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "Manual array copy #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new ManualArrayCopyVisitor(this, inspectionManager, onTheFly); + } + + public InspectionGadgetsFix buildFix(PsiElement location) { + return fix; + } + + private static class ManualArrayCopyFix extends InspectionGadgetsFix { + public String getName() { + return "Replace with System.arrayCopy()"; + } + + public void applyFix(Project project, ProblemDescriptor descriptor) { + final PsiElement forElement = descriptor.getPsiElement(); + final PsiForStatement forStatement = (PsiForStatement) forElement.getParent(); + final String newExpression = getSystemArrayCopyText(forStatement); + replaceStatement(project, forStatement, newExpression); + } + + private static String getSystemArrayCopyText(PsiForStatement forStatement) { + final PsiBinaryExpression condition = (PsiBinaryExpression) forStatement.getCondition(); + final PsiExpression limit = condition.getROperand(); + final String lengthText = limit.getText(); + final PsiExpressionStatement body = getBody(forStatement); + final PsiAssignmentExpression assignment = (PsiAssignmentExpression) body.getExpression(); + final PsiArrayAccessExpression lhs = (PsiArrayAccessExpression) assignment.getLExpression(); + final PsiExpression lArray = lhs.getArrayExpression(); + final String toArrayText = lArray.getText(); + final PsiArrayAccessExpression rhs = (PsiArrayAccessExpression) assignment.getRExpression(); + final PsiExpression rArray = rhs.getArrayExpression(); + final String fromArrayText = rArray.getText(); + final PsiExpression rhsIndex = rhs.getIndexExpression(); + final String fromOffsetText = getOffsetText(rhsIndex); + final PsiExpression lhsIndex = lhs.getIndexExpression(); + final String toOffsetText = getOffsetText(lhsIndex); + final StringBuffer buffer = new StringBuffer(25 + fromArrayText.length() + toArrayText.length() + lengthText.length()); + buffer.append("System.arraycopy("); + buffer.append(fromArrayText); + buffer.append(", "); + buffer.append(fromOffsetText); + buffer.append(", "); + buffer.append(toArrayText); + buffer.append(", "); + buffer.append(toOffsetText); + buffer.append(", "); + buffer.append(lengthText); + buffer.append(");"); + return buffer.toString(); + } + + private static String getOffsetText(PsiExpression indexExpression) { + if (indexExpression instanceof PsiBinaryExpression) { + final PsiBinaryExpression binaryExp = (PsiBinaryExpression) indexExpression; + final PsiExpression rhs = binaryExp.getROperand(); + final String rhsText = rhs.getText(); + final PsiJavaToken sign = binaryExp.getOperationSign(); + if (sign.getTokenType() == JavaTokenType.MINUS) { + return '-' + rhsText; + } else { + return rhsText; + } + } else { + return "0"; + } + } + + private static PsiExpressionStatement getBody(PsiForStatement forStatement) { + PsiStatement body = forStatement.getBody(); + while (body instanceof PsiBlockStatement) { + final PsiCodeBlock codeBlock = ((PsiBlockStatement) body).getCodeBlock(); + final PsiStatement[] statements = codeBlock.getStatements(); + body = statements[0]; + } + return (PsiExpressionStatement) body; + } + } + + private static class ManualArrayCopyVisitor extends BaseInspectionVisitor { + private ManualArrayCopyVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitForStatement(PsiForStatement forStatement) { + super.visitForStatement(forStatement); + final PsiStatement initialization = forStatement.getInitialization(); + if (!(initialization instanceof PsiDeclarationStatement)) { + return; + } + final PsiDeclarationStatement declaration = (PsiDeclarationStatement) initialization; + if (declaration.getDeclaredElements().length > 1) { + return; + } + final PsiLocalVariable var = (PsiLocalVariable) declaration.getDeclaredElements()[0]; + final PsiExpression initialValue = var.getInitializer(); + if (initialValue != null) { + final String initializerText = initialValue.getText(); + if (!"0".equals(initializerText)) { + return; + } + } + final PsiExpression condition = forStatement.getCondition(); + if (!isComparison(condition, var)) { + return; + } + final PsiStatement update = forStatement.getUpdate(); + if (!isIncrement(update, var)) { + return; + } + final PsiStatement body = forStatement.getBody(); + if (!bodyIsArrayMove(body, var)) { + return; + } + registerStatementError(forStatement); + } + + private boolean bodyIsArrayMove(PsiStatement body, PsiLocalVariable var) { + if (body instanceof PsiExpressionStatement) { + final PsiExpressionStatement exp = (PsiExpressionStatement) body; + final PsiExpression expression = exp.getExpression(); + if (expression == null) { + return false; + } + return expressionIsArrayMove(expression, var); + } else if (body instanceof PsiBlockStatement) { + final PsiCodeBlock codeBlock = ((PsiBlockStatement) body).getCodeBlock(); + if (codeBlock == null) { + return false; + } + final PsiStatement[] statements = codeBlock.getStatements(); + if (statements == null) { + return false; + } + if (statements.length != 1) { + return false; + } + return bodyIsArrayMove(statements[0], var); + } + return false; + } + + private static boolean expressionIsArrayMove(PsiExpression exp, PsiLocalVariable var) { + final PsiExpression strippedExpression = ParenthesesUtils.stripParentheses(exp); + if (strippedExpression == null) { + return false; + } + if (!(strippedExpression instanceof PsiAssignmentExpression)) { + return false; + } + final PsiAssignmentExpression assignment = (PsiAssignmentExpression) strippedExpression; + final PsiJavaToken sign = assignment.getOperationSign(); + if (sign == null) { + return false; + } + if (sign.getTokenType() != JavaTokenType.EQ) { + return false; + } + final PsiExpression lhs = assignment.getLExpression(); + if (lhs == null) { + return false; + } + if (SideEffectChecker.mayHaveSideEffects(lhs)) { + return false; + } + if (!isOffsetArrayAccess(lhs, var)) { + return false; + } + final PsiExpression rhs = assignment.getRExpression(); + if (rhs == null) { + return false; + } + if (SideEffectChecker.mayHaveSideEffects(rhs)) { + return false; + } + if (!isOffsetArrayAccess(rhs, var)) { + return false; + } + return true; + } + + private static boolean isOffsetArrayAccess(PsiExpression expression, PsiLocalVariable var) { + final PsiExpression strippedExpression = ParenthesesUtils.stripParentheses(expression); + if (!(strippedExpression instanceof PsiArrayAccessExpression)) { + return false; + } + final PsiArrayAccessExpression arrayExp = (PsiArrayAccessExpression) strippedExpression; + final PsiExpression index = arrayExp.getIndexExpression(); + if (index == null) { + return false; + } + if (!expressionIsOffsetVariableLookup(index, var)) { + return false; + } + return true; + } + + private static boolean isIncrement(PsiStatement statement, PsiLocalVariable var) { + if (!(statement instanceof PsiExpressionStatement)) { + return false; + } + PsiExpression exp = ((PsiExpressionStatement) statement).getExpression(); + exp = ParenthesesUtils.stripParentheses(exp); + if (exp instanceof PsiPrefixExpression) { + final PsiPrefixExpression prefixExp = (PsiPrefixExpression) exp; + final PsiJavaToken sign = prefixExp.getOperationSign(); + if (sign == null) { + return false; + } + final IElementType tokenType = sign.getTokenType(); + if (!tokenType.equals(JavaTokenType.PLUSPLUS)) { + return false; + } + final PsiExpression operand = prefixExp.getOperand(); + if (!expressionIsVariableLookup(operand, var)) { + return false; + } + return true; + } else if (exp instanceof PsiPostfixExpression) { + final PsiPostfixExpression postfixExp = (PsiPostfixExpression) exp; + final PsiJavaToken sign = postfixExp.getOperationSign(); + if (sign == null) { + return false; + } + final IElementType tokenType = sign.getTokenType(); + if (!tokenType.equals(JavaTokenType.PLUSPLUS)) { + return false; + } + final PsiExpression operand = postfixExp.getOperand(); + if (!expressionIsVariableLookup(operand, var)) { + return false; + } + return true; + } + return true; + } + + private static boolean isComparison(PsiExpression condition, PsiLocalVariable var) { + final PsiExpression strippedCondition = ParenthesesUtils.stripParentheses(condition); + + if (!(strippedCondition instanceof PsiBinaryExpression)) { + return false; + } + final PsiBinaryExpression binaryExp = (PsiBinaryExpression) strippedCondition; + final PsiJavaToken sign = binaryExp.getOperationSign(); + if (sign == null) { + return false; + } + if (sign.getTokenType() != JavaTokenType.LT) { + return false; + } + final PsiExpression lhs = binaryExp.getLOperand(); + if (!expressionIsVariableLookup(lhs, var)) { + return false; + } + return true; + } + + private static boolean expressionIsVariableLookup(PsiExpression expression, PsiLocalVariable var) { + final PsiExpression strippedExpression = ParenthesesUtils.stripParentheses(expression); + if (strippedExpression == null) { + return false; + } + final String expressionText = strippedExpression.getText(); + final String varText = var.getName(); + return expressionText.equals(varText); + } + + private static boolean expressionIsOffsetVariableLookup(PsiExpression expression, PsiLocalVariable var) { + final PsiExpression strippedExpression = ParenthesesUtils.stripParentheses(expression); + + if (expressionIsVariableLookup(strippedExpression, var)) { + return true; + } + if (!(strippedExpression instanceof PsiBinaryExpression)) { + return false; + } + final PsiBinaryExpression binaryExp = (PsiBinaryExpression) strippedExpression; + final PsiExpression lhs = binaryExp.getLOperand(); + if (!expressionIsVariableLookup(lhs, var)) { + return false; + } + final PsiJavaToken sign = binaryExp.getOperationSign(); + if (sign == null) { + return false; + } + final IElementType tokenType = sign.getTokenType(); + if (!tokenType.equals(JavaTokenType.PLUS) && !tokenType.equals(JavaTokenType.MINUS)) { + return false; + } + return true; + } + + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/performance/MethodMayBeStaticInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/performance/MethodMayBeStaticInspection.java new file mode 100644 index 000000000000..11a1026624eb --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/performance/MethodMayBeStaticInspection.java @@ -0,0 +1,179 @@ +package com.siyeh.ig.performance; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.codeInspection.ProblemDescriptor; +import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.progress.ProgressManager; +import com.intellij.openapi.project.Project; +import com.intellij.psi.*; +import com.intellij.psi.search.GlobalSearchScope; +import com.intellij.psi.search.PsiSearchHelper; +import com.intellij.util.IncorrectOperationException; +import com.siyeh.ig.*; +import com.siyeh.ig.psiutils.ClassUtils; + +import javax.swing.*; +import javax.swing.event.ChangeEvent; +import javax.swing.event.ChangeListener; +import java.awt.*; + +public class MethodMayBeStaticInspection extends MethodInspection { + public boolean m_onlyPrivateOrFinal = false; + public boolean m_ignoreEmptyMethods = true; + private final MethodMayBeStaticFix fix = new MethodMayBeStaticFix(); + + public String getDisplayName() { + return "Method may be 'static'"; + } + + public String getGroupDisplayName() { + return GroupNames.PERFORMANCE_GROUP_NAME; + } + + protected String buildErrorString(PsiElement location) { + return "Method #ref may be 'static' #loc"; + } + + protected InspectionGadgetsFix buildFix(PsiElement location) { + return fix; + } + + private static class MethodMayBeStaticFix extends InspectionGadgetsFix { + public String getName() { + return "Make static"; + } + + public void applyFix(Project project, ProblemDescriptor descriptor) { + final PsiJavaToken classNameToken = (PsiJavaToken) descriptor.getPsiElement(); + try { + final PsiMethod innerClass = (PsiMethod) classNameToken.getParent(); + final PsiModifierList modifiers = innerClass.getModifierList(); + modifiers.setModifierProperty(PsiModifier.STATIC, true); + } catch (IncorrectOperationException e) { + final Class aClass = getClass(); + final String className = aClass.getName(); + final Logger logger = Logger.getInstance(className); + logger.error(e); + } + } + } + + public JComponent createOptionsPanel() { + final JPanel panel = new JPanel(new GridBagLayout()); + final JCheckBox ignoreFieldAccessesCheckBox = new JCheckBox("Only check private or final methods", + m_onlyPrivateOrFinal); + final ButtonModel ignoreFieldAccessesModel = ignoreFieldAccessesCheckBox.getModel(); + ignoreFieldAccessesModel.addChangeListener(new ChangeListener() { + public void stateChanged(ChangeEvent e) { + m_onlyPrivateOrFinal = ignoreFieldAccessesModel.isSelected(); + } + }); + final JCheckBox ignoreEmptyMethodsCheckBox = new JCheckBox("Ignore empty methods", + m_ignoreEmptyMethods); + final ButtonModel ignoreEmptyMethodsModel = ignoreEmptyMethodsCheckBox.getModel(); + ignoreEmptyMethodsModel.addChangeListener(new ChangeListener() { + public void stateChanged(ChangeEvent e) { + m_ignoreEmptyMethods = ignoreEmptyMethodsModel.isSelected(); + } + }); + final GridBagConstraints constraints = new GridBagConstraints(); + constraints.gridx = 0; + constraints.gridy = 0; + constraints.weightx = 1.0; + constraints.anchor = GridBagConstraints.CENTER; + constraints.fill = GridBagConstraints.HORIZONTAL; + panel.add(ignoreFieldAccessesCheckBox, constraints); + constraints.gridy = 1; + panel.add(ignoreEmptyMethodsCheckBox, constraints); + return panel; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new MethodCanBeStaticVisitor(this, inspectionManager, onTheFly); + } + + private class MethodCanBeStaticVisitor extends BaseInspectionVisitor { + private MethodCanBeStaticVisitor(BaseInspection inspection, + InspectionManager inspectionManager, + boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitMethod(PsiMethod method) { + super.visitMethod(method); + if (method.hasModifierProperty(PsiModifier.STATIC)) { + return; + } + if (method.isConstructor()) { + return; + } + if (method.hasModifierProperty(PsiModifier.ABSTRACT)) { + return; + } + if (m_ignoreEmptyMethods) { + final PsiCodeBlock methodBody = method.getBody(); + if (methodBody == null) { + return; + } + final PsiStatement[] methodStatements = methodBody.getStatements(); + if (methodStatements.length == 0) { + return; + } + } + final PsiClass containingClass = ClassUtils.getContainingClass(method); + final PsiElement scope = containingClass.getScope(); + if (!(scope instanceof PsiJavaFile) && + !containingClass.hasModifierProperty(PsiModifier.STATIC)) { + return; + } + if (!method.hasModifierProperty(PsiModifier.PRIVATE) && + !method.hasModifierProperty(PsiModifier.FINAL)) { + if (m_onlyPrivateOrFinal) { + return; + } else { + final PsiMethod[] superMethods = method.findSuperMethods(); + if (superMethods.length > 0) { + return; + } + final OverridingMethodChecker overridingMethodChecker = + new OverridingMethodChecker(method); + if (overridingMethodChecker.hasOverridingMethods()) { + return; + } + } + } + final MethodReferenceVisitor visitor = new MethodReferenceVisitor(method); + method.accept(visitor); + if (!visitor.areReferencesStaticallyAccessible()) { + return; + } + registerMethodError(method); + } + } + + private static class OverridingMethodChecker implements Runnable { + private PsiMethod m_method; + private boolean m_hasOverridingMethods = false; + + OverridingMethodChecker(PsiMethod method) { + super(); + m_method = method; + } + + public boolean hasOverridingMethods() { + final ProgressManager progressManager = ProgressManager.getInstance(); + progressManager.runProcess(this, null); + return m_hasOverridingMethods; + } + + public void run() { + final PsiManager manager = m_method.getManager(); + final PsiSearchHelper searchHelper = manager.getSearchHelper(); + final GlobalSearchScope resolveScope = m_method.getResolveScope(); + final PsiMethod[] overridingMethods = + searchHelper.findOverridingMethods(m_method, + resolveScope, true); + m_hasOverridingMethods = overridingMethods.length > 0; + } + } +} \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/performance/MethodReferenceVisitor.java b/plugins/InspectionGadgets/src/com/siyeh/ig/performance/MethodReferenceVisitor.java new file mode 100644 index 000000000000..08944dc0b146 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/performance/MethodReferenceVisitor.java @@ -0,0 +1,87 @@ +package com.siyeh.ig.performance; + +import com.intellij.psi.*; +import com.intellij.psi.util.InheritanceUtil; +import com.intellij.psi.util.PsiTreeUtil; + +class MethodReferenceVisitor extends PsiRecursiveElementVisitor { + private boolean m_referencesStaticallyAccessible = true; + private PsiMethod m_method; + + MethodReferenceVisitor(PsiMethod method) { + super(); + m_method = method; + } + + public boolean areReferencesStaticallyAccessible() { + return m_referencesStaticallyAccessible; + } + + public void visitReferenceElement(PsiJavaCodeReferenceElement reference) { + super.visitReferenceElement(reference); + final PsiElement parent = + PsiTreeUtil.getParentOfType(reference, PsiNewExpression.class); + if (parent == null) { + return; + } + final PsiElement resolvedElement = reference.resolve(); + if (!(resolvedElement instanceof PsiClass)) { + return; + } + final PsiClass aClass = (PsiClass) resolvedElement; + final PsiElement scope = aClass.getScope(); + if (!(scope instanceof PsiClass)) { + return; + } + m_referencesStaticallyAccessible &= aClass.hasModifierProperty(PsiModifier.STATIC); + } + + public void visitReferenceExpression(PsiReferenceExpression expression) { + final PsiExpression qualifier = expression.getQualifierExpression(); + if (qualifier != null) { + qualifier.accept(this); + } + final PsiReferenceParameterList typeParameters = expression.getParameterList(); + if (typeParameters != null) { + typeParameters.accept(this); + } + final PsiElement element = expression.resolve(); + if (element instanceof PsiField) { + m_referencesStaticallyAccessible &= isFieldStaticallyAccessible((PsiField) element); + } else if (element instanceof PsiMethod) { + m_referencesStaticallyAccessible &= isMethodStaticallyAccessible((PsiMethod) element); + } + } + + public void visitThisExpression(PsiThisExpression expression) { + super.visitThisExpression(expression); + m_referencesStaticallyAccessible = false; + } + + private boolean isMethodStaticallyAccessible(PsiMethod method) { + if (method.hasModifierProperty(PsiModifier.STATIC)) { + return true; + } + if (method.isConstructor()) { + return true; + } + final PsiClass referenceContainingClass = m_method.getContainingClass(); + final PsiClass methodContainingClass = method.getContainingClass(); + if (InheritanceUtil.isInheritorOrSelf(referenceContainingClass, methodContainingClass, true)) { + return false; + } + return true; + } + + boolean isFieldStaticallyAccessible(PsiField field) { + if (field.hasModifierProperty(PsiModifier.STATIC)) { + return true; + } + final PsiClass referenceContainingClass = m_method.getContainingClass(); + final PsiClass fieldContainingClass = field.getContainingClass(); + if (InheritanceUtil.isInheritorOrSelf(referenceContainingClass, fieldContainingClass, true)) { + return false; + } + return true; + } +} \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/performance/MultiplyOrDivideByPowerOfTwoInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/performance/MultiplyOrDivideByPowerOfTwoInspection.java new file mode 100644 index 000000000000..54f07414252a --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/performance/MultiplyOrDivideByPowerOfTwoInspection.java @@ -0,0 +1,129 @@ +package com.siyeh.ig.performance; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.codeInspection.ProblemDescriptor; +import com.intellij.openapi.project.Project; +import com.intellij.psi.*; +import com.siyeh.ig.*; +import com.siyeh.ig.psiutils.ClassUtils; + +public class MultiplyOrDivideByPowerOfTwoInspection extends ExpressionInspection { + private final MultiplyByPowerOfTwoFix fix = new MultiplyByPowerOfTwoFix(); + + public String getDisplayName() { + return "Multiply or divide by power of two"; + } + + public String getGroupDisplayName() { + return GroupNames.PERFORMANCE_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "#ref can be replaced with " + + calculateReplacementShift((PsiExpression) location) + " #loc"; + } + + private static String calculateReplacementShift(PsiExpression expression) { + final PsiExpression lhs; + final PsiExpression rhs; + final String operator; + if (expression instanceof PsiAssignmentExpression) { + final PsiAssignmentExpression exp = (PsiAssignmentExpression) expression; + + final PsiJavaToken sign = exp.getOperationSign(); + lhs = exp.getLExpression(); + rhs = exp.getRExpression(); + if (sign.getTokenType() == JavaTokenType.ASTERISKEQ) { + operator = "<<="; + } else { + operator = ">>="; + } + } else { + final PsiBinaryExpression exp = (PsiBinaryExpression) expression; + final PsiJavaToken sign = exp.getOperationSign(); + lhs = exp.getLOperand(); + rhs = exp.getROperand(); + if (sign.getTokenType() == JavaTokenType.ASTERISK) { + operator = "<<"; + } else { + operator = ">>"; + } + } + final String newExpression = lhs.getText() + ' ' + operator + ' ' + ShiftUtils.getLogBaseTwo(rhs); + return newExpression; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new ConstantShiftVisitor(this, inspectionManager, onTheFly); + } + + public InspectionGadgetsFix buildFix(PsiElement location) { + return fix; + } + + private static class MultiplyByPowerOfTwoFix extends InspectionGadgetsFix { + public String getName() { + return "Replace with shift"; + } + + public void applyFix(Project project, ProblemDescriptor descriptor) { + final PsiExpression expression = (PsiExpression) descriptor.getPsiElement(); + final String newExpression = calculateReplacementShift(expression); + replaceExpression(project, expression, newExpression); + } + + } + + private static class ConstantShiftVisitor extends BaseInspectionVisitor { + private ConstantShiftVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitBinaryExpression(PsiBinaryExpression expression) { + super.visitBinaryExpression(expression); + final PsiJavaToken sign = expression.getOperationSign(); + if (sign == null) { + return; + } + if (sign.getTokenType() != JavaTokenType.ASTERISK && + sign.getTokenType() != JavaTokenType.DIV) { + return; + } + final PsiExpression rhs = expression.getROperand(); + if (!ShiftUtils.isPowerOfTwo(rhs)) { + return; + } + final PsiType type = expression.getType(); + if (type == null) { + return; + } + if (!ClassUtils.isIntegral(type)) { + return; + } + registerError(expression); + } + + public void visitAssignmentExpression(PsiAssignmentExpression expression) { + super.visitAssignmentExpression(expression); + final PsiJavaToken sign = expression.getOperationSign(); + if (sign.getTokenType() != JavaTokenType.ASTERISKEQ && + sign.getTokenType() != JavaTokenType.DIVEQ) { + return; + } + final PsiExpression rhs = expression.getRExpression(); + if (!ShiftUtils.isPowerOfTwo(rhs)) { + return; + } + + final PsiType type = expression.getType(); + if (type == null) { + return; + } + if (!ClassUtils.isIntegral(type)) { + return; + } + registerError(expression); + } + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/performance/ObjectAllocationInLoopInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/performance/ObjectAllocationInLoopInspection.java new file mode 100644 index 000000000000..14684d173798 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/performance/ObjectAllocationInLoopInspection.java @@ -0,0 +1,49 @@ +package com.siyeh.ig.performance; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiNewExpression; +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.ControlFlowUtils; + +public class ObjectAllocationInLoopInspection extends ExpressionInspection { + + public String getDisplayName() { + return "Object allocation in loop"; + } + + public String getGroupDisplayName() { + return GroupNames.PERFORMANCE_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "Object allocation (#ref) in loop #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new ObjectAllocationInLoopsVisitor(this, inspectionManager, onTheFly); + } + + private static class ObjectAllocationInLoopsVisitor extends BaseInspectionVisitor { + private ObjectAllocationInLoopsVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitNewExpression(PsiNewExpression expression) { + super.visitNewExpression(expression); + + if (!ControlFlowUtils.isInLoop(expression)) { + return; + } + if (ControlFlowUtils.isInExitStatement(expression)) { + return; + } + registerError(expression); + } + + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/performance/ShiftUtils.java b/plugins/InspectionGadgets/src/com/siyeh/ig/performance/ShiftUtils.java new file mode 100644 index 000000000000..abdae5df966d --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/performance/ShiftUtils.java @@ -0,0 +1,45 @@ +package com.siyeh.ig.performance; + +import com.intellij.psi.PsiExpression; +import com.intellij.psi.PsiLiteralExpression; + +class ShiftUtils { + private ShiftUtils() { + super(); + } + + public static boolean isPowerOfTwo(PsiExpression rhs) { + if (!(rhs instanceof PsiLiteralExpression)) { + return false; + } + final PsiLiteralExpression literal = (PsiLiteralExpression) rhs; + final Object value = literal.getValue(); + if (!(value instanceof Number)) { + return false; + } + if (value instanceof Double || value instanceof Float) { + return false; + } + int intValue = ((Number) value).intValue(); + if (intValue <= 1) { + return false; + } + while (intValue % 2 == 0) { + intValue >>= 1; + } + return intValue == 1; + } + + public static int getLogBaseTwo(PsiExpression rhs) { + final PsiLiteralExpression literal = (PsiLiteralExpression) rhs; + final Object value = literal.getValue(); + int intValue = ((Number) value).intValue(); + int log = 0; + while (intValue % 2 == 0) { + intValue >>= 1; + log++; + } + return log; + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/performance/SingleCharacterStartsWithInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/performance/SingleCharacterStartsWithInspection.java new file mode 100644 index 000000000000..40fd9c1d8884 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/performance/SingleCharacterStartsWithInspection.java @@ -0,0 +1,84 @@ +package com.siyeh.ig.performance; + +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 SingleCharacterStartsWithInspection extends ExpressionInspection { + + public String getDisplayName() { + return "Single character .startsWith() or .endsWith()"; + } + + public String getGroupDisplayName() { + return GroupNames.PERFORMANCE_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "Single character #ref() should be replaced by .charAt() #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new SingleCharacterStartsWithVisitor(this, inspectionManager, onTheFly); + } + + private static class SingleCharacterStartsWithVisitor extends BaseInspectionVisitor { + private SingleCharacterStartsWithVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitMethodCallExpression(PsiMethodCallExpression call) { + super.visitMethodCallExpression(call); + final PsiReferenceExpression methodExpression = call.getMethodExpression(); + final String methodName = methodExpression.getReferenceName(); + if (!"startsWith".equals(methodName) && !"endsWith".equals(methodName)) { + return; + } + final PsiExpressionList argumentList = call.getArgumentList(); + if (argumentList == null) { + return; + } + final PsiExpression[] args = argumentList.getExpressions(); + if (args.length != 1 && args.length != 2) { + return; + } + if (!isSingleCharacterStringLiteral(args[0])) { + return; + } + final PsiExpression qualifier = methodExpression.getQualifierExpression(); + if (qualifier == null) { + return; + } + final PsiType type = qualifier.getType(); + if (!TypeUtils.isJavaLangString(type)) { + return; + } + registerMethodCallError(call); + } + + private static boolean isSingleCharacterStringLiteral(PsiExpression arg) { + final PsiType type = arg.getType(); + if (!TypeUtils.isJavaLangString(type)) { + return false; + } + if (!(arg instanceof PsiLiteralExpression)) { + return false; + } + final PsiLiteralExpression literal = (PsiLiteralExpression) arg; + final String value = (String) literal.getValue(); + if (value == null) { + return false; + } + if (value.length() != 1) { + return false; + } + return true; + } + + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/performance/StaticCollectionInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/performance/StaticCollectionInspection.java new file mode 100644 index 000000000000..4a0874eb2cf9 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/performance/StaticCollectionInspection.java @@ -0,0 +1,53 @@ +package com.siyeh.ig.performance; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiField; +import com.intellij.psi.PsiModifier; +import com.intellij.psi.PsiType; +import com.siyeh.ig.BaseInspection; +import com.siyeh.ig.BaseInspectionVisitor; +import com.siyeh.ig.GroupNames; +import com.siyeh.ig.VariableInspection; +import com.siyeh.ig.psiutils.CollectionUtils; + +public class StaticCollectionInspection extends VariableInspection { + + public String getDisplayName() { + return "Static collection"; + } + + public String getGroupDisplayName() { + return GroupNames.PERFORMANCE_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "Static collection #ref #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new StaticCollectionVisitor(this, inspectionManager, onTheFly); + } + + private static class StaticCollectionVisitor extends BaseInspectionVisitor { + private StaticCollectionVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitField(PsiField field) { + if (!field.hasModifierProperty(PsiModifier.STATIC)) { + return; + } + final PsiType type = field.getType(); + if (type == null) { + return; + } + if (!CollectionUtils.isCollectionClassOrInterface(type)) { + return; + } + registerFieldError(field); + } + + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/performance/StringBufferMustHaveInitialCapacityInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/performance/StringBufferMustHaveInitialCapacityInspection.java new file mode 100644 index 000000000000..9c03282ad3f9 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/performance/StringBufferMustHaveInitialCapacityInspection.java @@ -0,0 +1,57 @@ +package com.siyeh.ig.performance; + +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 StringBufferMustHaveInitialCapacityInspection extends ExpressionInspection { + + public String getDisplayName() { + return "StringBuffer or StringBuilder without initial capacity"; + } + + public String getGroupDisplayName() { + return GroupNames.PERFORMANCE_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "#ref without initial capacity #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new StringBufferInitialCapacityVisitor(this, inspectionManager, onTheFly); + } + + private static class StringBufferInitialCapacityVisitor extends BaseInspectionVisitor { + private StringBufferInitialCapacityVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitNewExpression(PsiNewExpression expression) { + super.visitNewExpression(expression); + final PsiType type = expression.getType(); + + if (!TypeUtils.typeEquals("java.lang.StringBuffer", type) && + !TypeUtils.typeEquals("java.lang.StringBuilder", type)) { + return; + } + final PsiExpressionList argumentList = expression.getArgumentList(); + if (argumentList == null) { + return; + } + final PsiExpression[] args = argumentList.getExpressions(); + if (args == null) { + return; + } + if (args.length != 0) { + return; + } + registerError(expression); + } + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/performance/StringBufferReplaceableByStringBuilderInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/performance/StringBufferReplaceableByStringBuilderInspection.java new file mode 100644 index 000000000000..917b7853b636 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/performance/StringBufferReplaceableByStringBuilderInspection.java @@ -0,0 +1,101 @@ +package com.siyeh.ig.performance; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.psi.*; +import com.intellij.psi.util.PsiTreeUtil; +import com.intellij.openapi.roots.ProjectRootManager; +import com.intellij.openapi.project.Project; +import com.intellij.pom.java.LanguageLevel; +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; +import com.siyeh.ig.psiutils.VariableAccessUtils; + +public class StringBufferReplaceableByStringBuilderInspection extends ExpressionInspection { + + public String getDisplayName() { + return "StringBuffer may be StringBuilder (J2SDK 5.0 only)"; + } + + public String getGroupDisplayName() { + return GroupNames.PERFORMANCE_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "StringBuffer #ref may be declared as StringBuilder #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new StringBufferReplaceableByStringBuilderVisitor(this, inspectionManager, onTheFly); + } + + private static class StringBufferReplaceableByStringBuilderVisitor extends BaseInspectionVisitor { + private StringBufferReplaceableByStringBuilderVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitLocalVariable(PsiLocalVariable variable) { + super.visitLocalVariable(variable); + final PsiManager manager = variable.getManager(); + final LanguageLevel languageLevel = manager.getEffectiveLanguageLevel(); + if (languageLevel.equals(LanguageLevel.JDK_1_3) || + languageLevel.equals(LanguageLevel.JDK_1_4)) { + return; + } + final PsiCodeBlock codeBlock = + (PsiCodeBlock) PsiTreeUtil.getParentOfType(variable, PsiCodeBlock.class); + if (codeBlock == null) { + return; + } + final PsiType type = variable.getType(); + if (!TypeUtils.typeEquals("java.lang.StringBuffer", type)) { + return; + } + final PsiExpression initializer = variable.getInitializer(); + if (initializer == null) { + return; + } + if (!isNewStringBuffer(initializer)) { + return; + } + if (VariableAccessUtils.variableIsAssigned(variable, codeBlock)) { + return; + } + if (VariableAccessUtils.variableIsAssignedFrom(variable, codeBlock)) { + return; + } + if (VariableAccessUtils.variableIsReturned(variable, codeBlock)) { + return; + } + if (VariableAccessUtils.variableIsPassedAsMethodArgument(variable, codeBlock)) { + return; + } + if (VariableAccessUtils.variableIsUsedInInnerClass(variable, codeBlock)) { + return; + } + registerVariableError(variable); + } + + private boolean isNewStringBuffer(PsiExpression expression) { + if (expression == null) { + return false; + } else if (expression instanceof PsiNewExpression) { + return true; + } else if (expression instanceof PsiMethodCallExpression) { + final PsiReferenceExpression methodExpression = + ((PsiMethodCallExpression) expression).getMethodExpression(); + final String methodName = methodExpression.getReferenceName(); + if (!"append".equals(methodName)) { + return false; + } + final PsiExpression qualifier = + methodExpression.getQualifierExpression(); + return isNewStringBuffer(qualifier); + } + return false; + } + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/performance/StringBufferReplaceableByStringInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/performance/StringBufferReplaceableByStringInspection.java new file mode 100644 index 000000000000..b06065c51f22 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/performance/StringBufferReplaceableByStringInspection.java @@ -0,0 +1,101 @@ +package com.siyeh.ig.performance; + +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; +import com.siyeh.ig.psiutils.VariableAccessUtils; + +public class StringBufferReplaceableByStringInspection extends ExpressionInspection { + + public String getDisplayName() { + return "Constant StringBuffer may be String"; + } + + public String getGroupDisplayName() { + return GroupNames.PERFORMANCE_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "Constant StringBuffer #ref may be declared as String #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new StringBufferReplaceableByStringBuilderVisitor(this, inspectionManager, onTheFly); + } + + private static class StringBufferReplaceableByStringBuilderVisitor extends BaseInspectionVisitor { + private StringBufferReplaceableByStringBuilderVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitLocalVariable(PsiLocalVariable variable) { + super.visitLocalVariable(variable); + + + final PsiCodeBlock codeBlock = + (PsiCodeBlock) PsiTreeUtil.getParentOfType(variable, PsiCodeBlock.class); + if (codeBlock == null) { + return; + } + final PsiType type = variable.getType(); + if (!TypeUtils.typeEquals("java.lang.StringBuffer", type) && + !TypeUtils.typeEquals("java.lang.StringBuilder", type)) { + return; + } + final PsiExpression initializer = variable.getInitializer(); + if (initializer == null) { + return; + } + if (!isNewStringBufferOrStringBuilder(initializer)) { + return; + } + if (VariableAccessUtils.variableIsAssigned(variable, codeBlock)) { + return; + } + if (VariableAccessUtils.variableIsAssignedFrom(variable, codeBlock)) { + return; + } + if (VariableAccessUtils.variableIsReturned(variable, codeBlock)) { + return; + } + if (VariableAccessUtils.variableIsPassedAsMethodArgument(variable, codeBlock)) { + return; + } + if (variableIsAppendedTo(variable, codeBlock)) { + return; + } + registerVariableError(variable); + } + + public static boolean variableIsAppendedTo(PsiVariable variable, PsiElement context) { + final VariableIsAppendedToVisitor visitor = new VariableIsAppendedToVisitor(variable); + context.accept(visitor); + return visitor.isAppendedTo(); + } + + private boolean isNewStringBufferOrStringBuilder(PsiExpression expression) { + if (expression == null) { + return false; + } else if (expression instanceof PsiNewExpression) { + return true; + } else if (expression instanceof PsiMethodCallExpression) { + final PsiReferenceExpression methodExpression = + ((PsiMethodCallExpression) expression).getMethodExpression(); + final String methodName = methodExpression.getReferenceName(); + if (!"append".equals(methodName)) { + return false; + } + final PsiExpression qualifier = + methodExpression.getQualifierExpression(); + return isNewStringBufferOrStringBuilder(qualifier); + } + return false; + } + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/performance/StringBufferToStringInConcatenationInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/performance/StringBufferToStringInConcatenationInspection.java new file mode 100644 index 000000000000..e3d19d3478b9 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/performance/StringBufferToStringInConcatenationInspection.java @@ -0,0 +1,114 @@ +package com.siyeh.ig.performance; + +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 StringBufferToStringInConcatenationInspection extends ExpressionInspection { + private final StringBufferToStringFix fix = new StringBufferToStringFix(); + + public String getDisplayName() { + return "StringBuffer.toString() in concatenation"; + } + + public String getGroupDisplayName() { + return GroupNames.PERFORMANCE_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "Calls to StringBuffer.#ref() in concatenation #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new StringBufferToStringVisitor(this, inspectionManager, onTheFly); + } + + public InspectionGadgetsFix buildFix(PsiElement location) { + return fix; + } + + private static class StringBufferToStringFix extends InspectionGadgetsFix { + public String getName() { + return "Remove .toString()"; + } + + public void applyFix(Project project, ProblemDescriptor descriptor) { + final PsiElement methodNameToken = descriptor.getPsiElement(); + final PsiElement methodCallExpression = methodNameToken.getParent(); + final PsiMethodCallExpression methodCall = + (PsiMethodCallExpression) methodCallExpression.getParent(); + final PsiReferenceExpression expression = methodCall.getMethodExpression(); + final PsiExpression qualifier = expression.getQualifierExpression(); + final String newExpression = qualifier.getText(); + replaceExpression(project, methodCall, newExpression); + } + } + + private static class StringBufferToStringVisitor extends BaseInspectionVisitor { + private StringBufferToStringVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitMethodCallExpression(PsiMethodCallExpression expression) { + super.visitMethodCallExpression(expression); + final PsiElement parent = expression.getParent(); + if (!(parent instanceof PsiBinaryExpression)) { + return; + } + final PsiBinaryExpression parentBinary = (PsiBinaryExpression) parent; + final PsiJavaToken sign = parentBinary.getOperationSign(); + if (sign == null) { + return; + } + if (sign.getTokenType() != JavaTokenType.PLUS) { + return; + } + final PsiExpression rhs = parentBinary.getROperand(); + if (rhs == null) { + return; + } + if (!rhs.equals(expression)) { + return; + } + if (!isStringBufferToString(expression)) { + return; + } + final PsiReferenceExpression methodExpression = expression.getMethodExpression(); + if (methodExpression == null) { + return; + } + registerMethodCallError(expression); + } + + private static boolean isStringBufferToString(PsiMethodCallExpression expression) { + final PsiMethod method = expression.resolveMethod(); + if (method == null) { + return false; + } + final String methodName = method.getName(); + if (methodName == null) { + return false; + } + if (!"toString".equals(methodName)) { + return false; + } + final PsiParameterList parameterList = method.getParameterList(); + if (parameterList == null) { + return false; + } + final PsiParameter[] parameters = parameterList.getParameters(); + if (parameters.length != 0) { + return false; + } + final PsiClass aClass = method.getContainingClass(); + final String className = aClass.getQualifiedName(); + if (!"java.lang.StringBuffer".equals(className)) { + return false; + } + return true; + } + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/performance/StringConcatenationInLoopsInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/performance/StringConcatenationInLoopsInspection.java new file mode 100644 index 000000000000..fa20ab11b25e --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/performance/StringConcatenationInLoopsInspection.java @@ -0,0 +1,190 @@ +package com.siyeh.ig.performance; + +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.ControlFlowUtils; +import com.siyeh.ig.psiutils.TypeUtils; +import com.siyeh.ig.ui.SingleCheckboxOptionsPanel; + +import javax.swing.*; + +public class StringConcatenationInLoopsInspection extends ExpressionInspection { + public boolean m_ignoreUnlessAssigned = false; + + public String getDisplayName() { + return "String concatenation in loop"; + } + + public String getGroupDisplayName() { + return GroupNames.PERFORMANCE_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "String concatenation (#ref) in loop #loc"; + } + + public JComponent createOptionsPanel() { + return new SingleCheckboxOptionsPanel("Only warn if concatenated string is assigned", + this, "m_ignoreUnlessAssigned"); + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new StringConcatenationInLoopsVisitor(this, inspectionManager, + onTheFly); + } + + private class StringConcatenationInLoopsVisitor + extends BaseInspectionVisitor { + private StringConcatenationInLoopsVisitor(BaseInspection inspection, + InspectionManager inspectionManager, + boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitBinaryExpression(PsiBinaryExpression expression) { + super.visitBinaryExpression(expression); + final PsiJavaToken sign = expression.getOperationSign(); + if (sign == null) { + return; + } + if (sign.getTokenType() != JavaTokenType.PLUS) { + return; + } + final PsiType type = expression.getType(); + if (type == null) { + return; + } + if (!TypeUtils.isJavaLangString(type)) { + return; + } + if (!ControlFlowUtils.isInLoop(expression)) { + return; + } + if (ControlFlowUtils.isInExitStatement(expression)) { + return; + } + if (isEvaluatedAtCompileTime(expression)) { + return; + } + if (m_ignoreUnlessAssigned && !isOnRHSOfAssignment(expression)) { + return; + } + registerError(sign); + } + + + public void visitAssignmentExpression(PsiAssignmentExpression expression) { + super.visitAssignmentExpression(expression); + + final PsiJavaToken sign = expression.getOperationSign(); + if (sign == null) { + return; + } + if (sign.getTokenType() != JavaTokenType.PLUSEQ) { + return; + } + final PsiExpression lhs = expression.getLExpression(); + if (lhs == null) { + return; + } + final PsiType type = lhs.getType(); + if (type == null) { + return; + } + if (!TypeUtils.isJavaLangString(type)) { + return; + } + if (!ControlFlowUtils.isInLoop(expression)) { + return; + } + if (ControlFlowUtils.isInExitStatement(expression)) { + return; + } + registerError(sign); + } + } + + private static boolean isEvaluatedAtCompileTime(PsiExpression expression) { + if (expression instanceof PsiLiteralExpression) { + return true; + } + if (expression instanceof PsiBinaryExpression) { + final PsiBinaryExpression binaryExpression = (PsiBinaryExpression) expression; + final PsiExpression lhs = binaryExpression.getLOperand(); + final PsiExpression rhs = binaryExpression.getROperand(); + return isEvaluatedAtCompileTime(lhs) && + isEvaluatedAtCompileTime(rhs); + } + if (expression instanceof PsiPrefixExpression) { + final PsiPrefixExpression prefixExpression = (PsiPrefixExpression) expression; + final PsiExpression operand = prefixExpression.getOperand(); + return isEvaluatedAtCompileTime(operand); + } + if (expression instanceof PsiReferenceExpression) { + final PsiReferenceExpression referenceExpression = (PsiReferenceExpression) expression; + final PsiElement qualifier = referenceExpression.getQualifier(); + if (qualifier instanceof PsiThisExpression) { + return false; + } + final PsiElement element = referenceExpression.resolve(); + if (element instanceof PsiField) { + final PsiField field = (PsiField) element; + final PsiExpression initializer = field.getInitializer(); + return field.hasModifierProperty(PsiModifier.FINAL) && + isEvaluatedAtCompileTime(initializer); + } + if (element instanceof PsiVariable) { + final PsiVariable variable = (PsiVariable) element; + final PsiExpression initializer = variable.getInitializer(); + return variable.hasModifierProperty(PsiModifier.FINAL) && + isEvaluatedAtCompileTime(initializer); + } + } + if (expression instanceof PsiParenthesizedExpression) { + final PsiParenthesizedExpression parenthesizedExpression = + (PsiParenthesizedExpression) expression; + final PsiExpression unparenthesizedExpression = parenthesizedExpression.getExpression(); + return isEvaluatedAtCompileTime(unparenthesizedExpression); + + } + if (expression instanceof PsiConditionalExpression) { + final PsiConditionalExpression conditionalExpression = + (PsiConditionalExpression) expression; + final PsiExpression condition = conditionalExpression.getCondition(); + final PsiExpression thenExpression = conditionalExpression.getThenExpression(); + final PsiExpression elseExpression = conditionalExpression.getElseExpression(); + return isEvaluatedAtCompileTime(condition) && + isEvaluatedAtCompileTime(thenExpression) && + isEvaluatedAtCompileTime(elseExpression); + + } + if (expression instanceof PsiTypeCastExpression) { + final PsiTypeCastExpression typeCastExpression = (PsiTypeCastExpression) expression; + final PsiTypeElement castType = typeCastExpression.getCastType(); + final PsiType type = castType.getType(); + return TypeUtils.typeEquals("java.lang.String", type); + } + return false; + } + + private static boolean isOnRHSOfAssignment(PsiExpression expression) { + final PsiElement parent = expression.getParent(); + if (parent instanceof PsiParenthesizedExpression) { + final PsiExpression containedExpression = ((PsiParenthesizedExpression) parent).getExpression(); + return isOnRHSOfAssignment(containedExpression); + } + if (parent instanceof PsiAssignmentExpression) { + return true; + } + if (parent instanceof PsiBinaryExpression) { + return isOnRHSOfAssignment((PsiExpression) parent); + } + return false; + } + + +} \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/performance/StringConstructorInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/performance/StringConstructorInspection.java new file mode 100644 index 000000000000..98dae1cbf16c --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/performance/StringConstructorInspection.java @@ -0,0 +1,94 @@ +package com.siyeh.ig.performance; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.codeInspection.ProblemDescriptor; +import com.intellij.openapi.project.Project; +import com.intellij.psi.*; +import com.siyeh.ig.*; +import com.siyeh.ig.psiutils.TypeUtils; + +public class StringConstructorInspection extends ExpressionInspection { + + public String getDisplayName() { + return "Redundant String constructor call"; + } + + public String getGroupDisplayName() { + return GroupNames.PERFORMANCE_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "#ref is redundant #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new StringConstructorVisitor(this, inspectionManager, onTheFly); + } + + public InspectionGadgetsFix buildFix(PsiElement location) { + return new StringConstructorFix((PsiNewExpression) location); + } + + private static class StringConstructorFix extends InspectionGadgetsFix { + private final String m_name; + + private StringConstructorFix(PsiNewExpression expression) { + super(); + final PsiExpressionList argList = expression.getArgumentList(); + final PsiExpression[] args = argList.getExpressions(); + if (args.length == 1) { + m_name = "Replace with arg"; + } else { + m_name = "Replace with empty string"; + } + } + + public String getName() { + return m_name; + } + + public void applyFix(Project project, ProblemDescriptor descriptor) { + final PsiNewExpression expression = (PsiNewExpression) descriptor.getPsiElement(); + final PsiExpressionList argList = expression.getArgumentList(); + final PsiExpression[] args = argList.getExpressions(); + final String argText; + if (args.length == 1) { + argText = args[0].getText(); + } else { + argText = "\"\""; + } + replaceExpression(project, expression, argText); + } + } + + private static class StringConstructorVisitor extends BaseInspectionVisitor { + private StringConstructorVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitNewExpression(PsiNewExpression expression) { + super.visitNewExpression(expression); + final PsiType type = expression.getType(); + if (!TypeUtils.isJavaLangString(type)) { + return; + } + final PsiExpressionList argList = expression.getArgumentList(); + if (argList == null) { + return; + } + final PsiExpression[] args = argList.getExpressions(); + + if (args.length > 1) { + return; + } + if (args.length == 1) { + final PsiType parameterType = args[0].getType(); + if (!TypeUtils.isJavaLangString(parameterType)) { + return; + } + } + registerError(expression); + } + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/performance/StringEqualsEmptyStringInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/performance/StringEqualsEmptyStringInspection.java new file mode 100644 index 000000000000..185dbb0bfc06 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/performance/StringEqualsEmptyStringInspection.java @@ -0,0 +1,108 @@ +package com.siyeh.ig.performance; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.codeInspection.ProblemDescriptor; +import com.intellij.psi.*; +import com.intellij.openapi.project.Project; +import com.siyeh.ig.*; +import com.siyeh.ig.psiutils.TypeUtils; + +public class StringEqualsEmptyStringInspection extends ExpressionInspection { + private final StringEqualsEmptyStringFix fix = new StringEqualsEmptyStringFix(); + + public String getDisplayName() { + return "String.equals(\"\")"; + } + + public String getGroupDisplayName() { + return GroupNames.PERFORMANCE_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return ".equals(\"\") can be replace by .length()==0 #loc"; + } + + public InspectionGadgetsFix buildFix(PsiElement location) { + return fix; + } + + private static class StringEqualsEmptyStringFix extends InspectionGadgetsFix { + public String getName() { + return "replace with .length()==0"; + } + + public void applyFix(Project project, ProblemDescriptor descriptor) { + final PsiIdentifier name = (PsiIdentifier) descriptor.getPsiElement(); + final PsiReferenceExpression expression = (PsiReferenceExpression) name.getParent(); + final PsiExpression call = (PsiExpression) expression.getParent(); + final PsiExpression qualifier = expression.getQualifierExpression(); + final String qualifierText = qualifier.getText(); + replaceExpression(project, call, qualifierText + ".length()==0"); + } + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new StringEqualsEmptyStringVisitor(this, inspectionManager, onTheFly); + } + + private static class StringEqualsEmptyStringVisitor extends BaseInspectionVisitor { + private StringEqualsEmptyStringVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitMethodCallExpression(PsiMethodCallExpression call) { + super.visitMethodCallExpression(call); + final PsiReferenceExpression methodExpression = call.getMethodExpression(); + final String methodName = methodExpression.getReferenceName(); + if (!"equals".equals(methodName)) { + return; + } + final PsiExpressionList argumentList = call.getArgumentList(); + if (argumentList == null) { + return; + } + final PsiExpression[] args = argumentList.getExpressions(); + if (args.length != 1) { + return; + } + if (!isEmptyStringLiteral(args[0])) { + return; + } + final PsiExpression qualifier = methodExpression.getQualifierExpression(); + if (qualifier == null) { + return; + } + final PsiType type = qualifier.getType(); + if (!TypeUtils.isJavaLangString(type)) { + return; + } + final PsiElement context = call.getParent(); + if (context instanceof PsiExpressionStatement) { + return; //cheesy, but necessary, because otherwise the quickfix will produce + //uncompilable code (out of merely incorrect code). + } + registerMethodCallError(call); + } + + private static boolean isEmptyStringLiteral(PsiExpression arg) { + final PsiType type = arg.getType(); + if (!TypeUtils.isJavaLangString(type)) { + return false; + } + if (!(arg instanceof PsiLiteralExpression)) { + return false; + } + final PsiLiteralExpression literal = (PsiLiteralExpression) arg; + final String value = (String) literal.getValue(); + if (value == null) { + return false; + } + if (value.length() != 0) { + return false; + } + return true; + } + + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/performance/StringReplaceableByStringBufferInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/performance/StringReplaceableByStringBufferInspection.java new file mode 100644 index 000000000000..a21f3c36d0c6 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/performance/StringReplaceableByStringBufferInspection.java @@ -0,0 +1,60 @@ +package com.siyeh.ig.performance; + +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 StringReplaceableByStringBufferInspection extends ExpressionInspection { + + public String getDisplayName() { + return "Non-constant String should be StringBuffer"; + } + + public String getGroupDisplayName() { + return GroupNames.PERFORMANCE_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "Non-constant String #ref should probably be declared as StringBuffer #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new StringReplaceableByStringBufferVisitor(this, inspectionManager, onTheFly); + } + + private static class StringReplaceableByStringBufferVisitor extends BaseInspectionVisitor { + private StringReplaceableByStringBufferVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitLocalVariable(PsiLocalVariable variable) { + super.visitLocalVariable(variable); + final PsiCodeBlock codeBlock = + (PsiCodeBlock) PsiTreeUtil.getParentOfType(variable, PsiCodeBlock.class); + if (codeBlock == null) { + return; + } + final PsiType type = variable.getType(); + if (!TypeUtils.typeEquals("java.lang.String", type)) { + return; + } + if (!variableIsAppendedTo(variable, codeBlock)) { + return; + } + registerVariableError(variable); + } + + public static boolean variableIsAppendedTo(PsiVariable variable, PsiElement context) { + final StringVariableIsAppendedToVisitor visitor = new StringVariableIsAppendedToVisitor(variable); + context.accept(visitor); + return visitor.isAppendedTo(); + } + + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/performance/StringToStringInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/performance/StringToStringInspection.java new file mode 100644 index 000000000000..7565cd743e91 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/performance/StringToStringInspection.java @@ -0,0 +1,83 @@ +package com.siyeh.ig.performance; + +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 StringToStringInspection extends ExpressionInspection { + private final StringToStringFix fix = new StringToStringFix(); + + public String getDisplayName() { + return "Redundant String.toString()"; + } + + public String getGroupDisplayName() { + return GroupNames.PERFORMANCE_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "#ref is redundant #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new StringToStringVisitor(this, inspectionManager, onTheFly); + } + + public InspectionGadgetsFix buildFix(PsiElement location) { + return fix; + } + + private static class StringToStringFix extends InspectionGadgetsFix { + public String getName() { + return "Simplify"; + } + + public void applyFix(Project project, ProblemDescriptor descriptor) { + final PsiMethodCallExpression call = (PsiMethodCallExpression) descriptor.getPsiElement(); + final PsiReferenceExpression expression = call.getMethodExpression(); + final PsiExpression qualifier = expression.getQualifierExpression(); + final String qualifierText = qualifier.getText(); + replaceExpression(project, call, qualifierText); + } + } + + private static class StringToStringVisitor extends BaseInspectionVisitor { + private StringToStringVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitMethodCallExpression(PsiMethodCallExpression expression) { + super.visitMethodCallExpression(expression); + final PsiReferenceExpression methodExpression = expression.getMethodExpression(); + if (methodExpression == null) { + return; + } + final String methodName = methodExpression.getReferenceName(); + if (!"toString".equals(methodName)) { + return; + } + + final PsiMethod method = expression.resolveMethod(); + if (method == null) { + return; + } + final PsiParameterList paramList = method.getParameterList(); + if (paramList == null) { + return; + } + final PsiParameter[] parameters = paramList.getParameters(); + if (parameters.length != 0) { + return; + } + final PsiClass aClass = method.getContainingClass(); + final String className = aClass.getQualifiedName(); + if (!"java.lang.String".equals(className)) { + return; + } + registerError(expression); + } + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/performance/StringVariableIsAppendedToVisitor.java b/plugins/InspectionGadgets/src/com/siyeh/ig/performance/StringVariableIsAppendedToVisitor.java new file mode 100644 index 000000000000..ca1bc0e434cb --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/performance/StringVariableIsAppendedToVisitor.java @@ -0,0 +1,81 @@ +package com.siyeh.ig.performance; + +import com.intellij.psi.*; +import com.intellij.psi.tree.IElementType; + +public class StringVariableIsAppendedToVisitor extends PsiRecursiveElementVisitor { + private boolean appendedTo = false; + private final PsiVariable variable; + + public StringVariableIsAppendedToVisitor(PsiVariable variable) { + super(); + this.variable = variable; + } + + public void visitReferenceExpression(PsiReferenceExpression referenceExpression) { + final PsiExpression qualifier = referenceExpression.getQualifierExpression(); + if (qualifier != null) { + qualifier.accept(this); + } + final PsiReferenceParameterList typeParameters = referenceExpression.getParameterList(); + if (typeParameters != null) { + typeParameters.accept(this); + } + } + + public void visitAssignmentExpression(PsiAssignmentExpression assignment) { + super.visitAssignmentExpression(assignment); + final PsiExpression lhs = assignment.getLExpression(); + if (lhs == null) { + return; + } + final PsiExpression rhs = assignment.getRExpression(); + if (rhs == null) { + return; + } + if (!(lhs instanceof PsiReferenceExpression)) { + return; + } + final PsiReferenceExpression reference = (PsiReferenceExpression) lhs; + final PsiElement referent = reference.resolve(); + if (!variable.equals(referent)) { + return; + } + final PsiJavaToken operationSign = assignment.getOperationSign(); + if (operationSign == null) { + return; + } + final IElementType tokenType = operationSign.getTokenType(); + if (tokenType.equals(JavaTokenType.PLUSEQ)) { + appendedTo = true; + } else if (isConcatenation(rhs)) { + appendedTo = true; + } + } + + private boolean isConcatenation(PsiExpression expression) { + if (expression == null) { + return false; + } + if (expression instanceof PsiReferenceExpression) { + final PsiElement referent = ((PsiReference) expression).resolve(); + return variable.equals(referent); + } + if (expression instanceof PsiParenthesizedExpression) { + final PsiExpression body = + ((PsiParenthesizedExpression) expression).getExpression(); + return isConcatenation(body); + } + if (expression instanceof PsiBinaryExpression) { + final PsiBinaryExpression binaryExpression = (PsiBinaryExpression) expression; + final PsiExpression lhs = binaryExpression.getLOperand(); + final PsiExpression rhs = binaryExpression.getROperand(); + return isConcatenation(lhs) || isConcatenation(rhs); + } + return false; + } + + public boolean isAppendedTo() { + return appendedTo; + } +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/performance/TailRecursionInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/performance/TailRecursionInspection.java new file mode 100644 index 000000000000..50ed630fe46d --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/performance/TailRecursionInspection.java @@ -0,0 +1,65 @@ +package com.siyeh.ig.performance; + +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 TailRecursionInspection extends ExpressionInspection { + + public String getDisplayName() { + return "Tail recursion"; + } + + public String getGroupDisplayName() { + return GroupNames.PERFORMANCE_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "Tail recursive call #ref() #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new TailRecursionVisitor(this, inspectionManager, onTheFly); + } + + private static class TailRecursionVisitor extends BaseInspectionVisitor { + private TailRecursionVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitReturnStatement(PsiReturnStatement statement) { + super.visitReturnStatement(statement); + final PsiExpression returnValue = statement.getReturnValue(); + if (returnValue == null) { + return; + } + if (!(returnValue instanceof PsiMethodCallExpression)) { + return; + } + final PsiMethod containingMethod = + (PsiMethod) PsiTreeUtil.getParentOfType(statement, PsiMethod.class); + if (containingMethod == null) { + return; + } + final PsiMethodCallExpression returnCall = (PsiMethodCallExpression) returnValue; + final PsiMethod method = returnCall.resolveMethod(); + if (method == null) { + return; + } + if (!method.equals(containingMethod)) { + return; + } + + final PsiReferenceExpression methodExpression = returnCall.getMethodExpression(); + if (methodExpression == null) { + return; + } + registerMethodCallError(returnCall); + } + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/performance/TrivialStringConcatenationInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/performance/TrivialStringConcatenationInspection.java new file mode 100644 index 000000000000..0ba34735dd11 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/performance/TrivialStringConcatenationInspection.java @@ -0,0 +1,119 @@ +package com.siyeh.ig.performance; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.codeInspection.ProblemDescriptor; +import com.intellij.openapi.project.Project; +import com.intellij.psi.*; +import com.siyeh.ig.*; +import com.siyeh.ig.psiutils.TypeUtils; + +import java.util.HashMap; +import java.util.Map; + +public class TrivialStringConcatenationInspection extends ExpressionInspection { + private static final Map s_typeToWrapperMap = new HashMap(6); + + static { + s_typeToWrapperMap.put("short", "Short"); + s_typeToWrapperMap.put("int", "Integer"); + s_typeToWrapperMap.put("long", "Long"); + s_typeToWrapperMap.put("float", "Float"); + s_typeToWrapperMap.put("double", "Double"); + s_typeToWrapperMap.put("boolean", "Boolean"); + s_typeToWrapperMap.put("byte", "Byte"); + } + + public String getDisplayName() { + return "Concatenation with empty string"; + } + + public String getGroupDisplayName() { + return GroupNames.PERFORMANCE_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + final String replacementString = calculateReplacementExpression(location); + return "#ref can be simplified to " + replacementString + " #loc"; + } + + private static String calculateReplacementExpression(PsiElement location) { + final PsiBinaryExpression expression = (PsiBinaryExpression) location; + final PsiExpression lOperand = expression.getLOperand(); + final PsiExpression rOperand = expression.getROperand(); + final PsiExpression replacement; + if (isEmptyString(lOperand)) { + replacement = rOperand; + } else { + + replacement = lOperand; + } + final PsiType type = replacement.getType(); + final String text = type.getCanonicalText(); + if (s_typeToWrapperMap.containsKey(text)) { + return s_typeToWrapperMap.get(text) + ".toString(" + replacement.getText() + ')'; + } else { + return replacement.getText(); + } + + } + + public InspectionGadgetsFix buildFix(PsiElement location) { + return new UnnecessaryTemporaryObjectFix((PsiBinaryExpression) location); + } + + private static class UnnecessaryTemporaryObjectFix extends InspectionGadgetsFix { + private final String m_name; + + private UnnecessaryTemporaryObjectFix(PsiBinaryExpression expression) { + super(); + m_name = "Replace with " + calculateReplacementExpression(expression); + } + + public String getName() { + return m_name; + } + + public void applyFix(Project project, ProblemDescriptor descriptor) { + final PsiBinaryExpression expression = (PsiBinaryExpression) descriptor.getPsiElement(); + final String newExpression = calculateReplacementExpression(expression); + replaceExpression(project, expression, newExpression); + } + + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new TrivialStringConcatenationVisitor(this, inspectionManager, onTheFly); + } + + private static class TrivialStringConcatenationVisitor extends BaseInspectionVisitor { + private TrivialStringConcatenationVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitBinaryExpression(PsiBinaryExpression exp) { + super.visitBinaryExpression(exp); + if (!TypeUtils.expressionHasType("java.lang.String", exp)) { + return; + } + final PsiExpression lhs = exp.getLOperand(); + if (lhs == null) { + return; + } + final PsiExpression rhs = exp.getROperand(); + if (rhs == null) { + return; + } + if (!isEmptyString(lhs) && !isEmptyString(rhs)) { + return; + } + registerError(exp); + } + } + + private static boolean isEmptyString(PsiExpression exp) { + + final String text = exp.getText(); + return "\"\"".equals(text); + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/performance/UnnecessaryTemporaryOnConversionFromStringInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/performance/UnnecessaryTemporaryOnConversionFromStringInspection.java new file mode 100644 index 000000000000..f1e13dda389a --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/performance/UnnecessaryTemporaryOnConversionFromStringInspection.java @@ -0,0 +1,142 @@ +package com.siyeh.ig.performance; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.codeInspection.ProblemDescriptor; +import com.intellij.openapi.project.Project; +import com.intellij.psi.*; +import com.siyeh.ig.*; +import com.siyeh.ig.psiutils.TypeUtils; + +import java.util.HashMap; +import java.util.Map; + +public class UnnecessaryTemporaryOnConversionFromStringInspection extends ExpressionInspection { + private static final Map s_basicTypeMap = new HashMap(6); + private static final Map s_conversionMap = new HashMap(6); + + static { + s_basicTypeMap.put("java.lang.Short", "shortValue"); + s_basicTypeMap.put("java.lang.Integer", "intValue"); + s_basicTypeMap.put("java.lang.Long", "longValue"); + s_basicTypeMap.put("java.lang.Float", "floatValue"); + s_basicTypeMap.put("java.lang.Double", "doubleValue"); + s_basicTypeMap.put("java.lang.Boolean", "booleanValue"); + + s_conversionMap.put("java.lang.Short", "parseShort"); + s_conversionMap.put("java.lang.Integer", "parseInt"); + s_conversionMap.put("java.lang.Long", "parseLong"); + s_conversionMap.put("java.lang.Float", "parseFloat"); + s_conversionMap.put("java.lang.Double", "parseDouble"); + s_conversionMap.put("java.lang.Boolean", "valueOf"); + } + + public String getDisplayName() { + return "Unnecessary temporary object in conversion from String"; + } + + public String getGroupDisplayName() { + return GroupNames.PERFORMANCE_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + final String replacementString = calculateReplacementExpression(location); + return "#ref can be simplified to " + replacementString + " #loc"; + } + + private static String calculateReplacementExpression(PsiElement location) { + final PsiMethodCallExpression expression = (PsiMethodCallExpression) location; + final PsiReferenceExpression methodExpression = expression.getMethodExpression(); + final PsiNewExpression qualifier = (PsiNewExpression) methodExpression.getQualifierExpression(); + final PsiExpressionList argumentList = qualifier.getArgumentList(); + final PsiExpression arg = argumentList.getExpressions()[0]; + final PsiType type = qualifier.getType(); + final String qualifierType = type.getPresentableText(); + final String canonicalType = type.getCanonicalText(); + + final String conversionName = (String) s_conversionMap.get(canonicalType); + if (TypeUtils.typeEquals("java.lang.Boolean", type)) { + return qualifierType + '.' + conversionName + '(' + arg.getText() + ").booleanValue()"; + } else { + return qualifierType + '.' + conversionName + '(' + arg.getText() + ')'; + } + } + + public InspectionGadgetsFix buildFix(PsiElement location) { + return new UnnecessaryTemporaryObjectFix((PsiMethodCallExpression) location); + } + + private static class UnnecessaryTemporaryObjectFix extends InspectionGadgetsFix { + private final String m_name; + + private UnnecessaryTemporaryObjectFix(PsiMethodCallExpression location) { + super(); + m_name = "Replace with " + calculateReplacementExpression(location); + } + + public String getName() { + return m_name; + } + + public void applyFix(Project project, ProblemDescriptor descriptor) { + final PsiMethodCallExpression expression = + (PsiMethodCallExpression) descriptor.getPsiElement(); + final String newExpression = calculateReplacementExpression(expression); + replaceExpression(project, expression, newExpression); + } + + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new UnnecessaryTemporaryObjectVisitor(this, inspectionManager, onTheFly); + } + + private static class UnnecessaryTemporaryObjectVisitor extends BaseInspectionVisitor { + private UnnecessaryTemporaryObjectVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitMethodCallExpression(PsiMethodCallExpression expression) { + super.visitMethodCallExpression(expression); + final PsiReferenceExpression methodExpression = expression.getMethodExpression(); + if (methodExpression == null) { + return; + } + final String methodName = methodExpression.getReferenceName(); + final Map basicTypeMap = s_basicTypeMap; + if (!basicTypeMap.containsValue(methodName)) { + return; + } + final PsiExpression qualifier = methodExpression.getQualifierExpression(); + if (qualifier == null) { + return; + } + if (!(qualifier instanceof PsiNewExpression)) { + return; + } + final PsiNewExpression newExp = (PsiNewExpression) qualifier; + final PsiExpressionList argList = newExp.getArgumentList(); + final PsiExpression[] args = argList.getExpressions(); + if (args.length != 1) { + return; + } + final PsiType argType = args[0].getType(); + if (!TypeUtils.isJavaLangString(argType)) { + return; + } + final PsiType type = qualifier.getType(); + if (type == null) { + return; + } + final String typeText = type.getCanonicalText(); + if (!basicTypeMap.containsKey(typeText)) { + return; + } + final Object mappingMethod = basicTypeMap.get(typeText); + if (!mappingMethod.equals(methodName)) { + return; + } + registerError(expression); + } + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/performance/UnnecessaryTemporaryOnConversionToStringInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/performance/UnnecessaryTemporaryOnConversionToStringInspection.java new file mode 100644 index 000000000000..c59bee3a28b2 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/performance/UnnecessaryTemporaryOnConversionToStringInspection.java @@ -0,0 +1,110 @@ +package com.siyeh.ig.performance; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.codeInspection.ProblemDescriptor; +import com.intellij.openapi.project.Project; +import com.intellij.psi.*; +import com.siyeh.ig.*; + +import java.util.HashSet; +import java.util.Set; + +public class UnnecessaryTemporaryOnConversionToStringInspection extends ExpressionInspection { + private static final Set s_basicTypes = new HashSet(6); + + static { + s_basicTypes.add("java.lang.Short"); + s_basicTypes.add("java.lang.Integer"); + s_basicTypes.add("java.lang.Long"); + s_basicTypes.add("java.lang.Float"); + s_basicTypes.add("java.lang.Double"); + s_basicTypes.add("java.lang.Boolean"); + } + + public String getDisplayName() { + return "Unnecessary temporary object in conversion to String"; + } + + public String getGroupDisplayName() { + return GroupNames.PERFORMANCE_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + final String replacementString = calculateReplacementExpression(location); + return "#ref can be simplified to " + replacementString + " #loc"; + } + + private static String calculateReplacementExpression(PsiElement location) { + final PsiMethodCallExpression expression = (PsiMethodCallExpression) location; + final PsiReferenceExpression methodExpression = expression.getMethodExpression(); + final PsiNewExpression qualifier = (PsiNewExpression) methodExpression.getQualifierExpression(); + final PsiExpressionList argumentList = qualifier.getArgumentList(); + final PsiExpression arg = argumentList.getExpressions()[0]; + final PsiType type = qualifier.getType(); + final String qualifierType = type.getPresentableText(); + return qualifierType + ".toString(" + arg.getText() + ')'; + } + + public InspectionGadgetsFix buildFix(PsiElement location) { + return new UnnecessaryTemporaryObjectFix((PsiMethodCallExpression) location); + } + + private static class UnnecessaryTemporaryObjectFix extends InspectionGadgetsFix { + private final String m_name; + + private UnnecessaryTemporaryObjectFix(PsiMethodCallExpression expression) { + super(); + m_name = "Replace with " + calculateReplacementExpression(expression); + } + + public String getName() { + return m_name; + } + + public void applyFix(Project project, ProblemDescriptor descriptor) { + final PsiMethodCallExpression expression = (PsiMethodCallExpression) descriptor.getPsiElement(); + final String newExpression = calculateReplacementExpression(expression); + replaceExpression(project, expression, newExpression); + } + + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new UnnecessaryTemporaryObjectVisitor(this, inspectionManager, onTheFly); + } + + private static class UnnecessaryTemporaryObjectVisitor extends BaseInspectionVisitor { + private UnnecessaryTemporaryObjectVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitMethodCallExpression(PsiMethodCallExpression expression) { + super.visitMethodCallExpression(expression); + final PsiReferenceExpression methodExpression = expression.getMethodExpression(); + if (methodExpression == null) { + return; + } + final String methodName = methodExpression.getReferenceName(); + if (!"toString".equals(methodName)) { + return; + } + final PsiExpression qualifier = methodExpression.getQualifierExpression(); + if (qualifier == null) { + return; + } + if (!(qualifier instanceof PsiNewExpression)) { + return; + } + final PsiType type = qualifier.getType(); + if (type == null) { + return; + } + final String typeName = type.getCanonicalText(); + if (!s_basicTypes.contains(typeName)) { + return; + } + registerError(expression); + } + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/performance/VariableAccessVisitor.java b/plugins/InspectionGadgets/src/com/siyeh/ig/performance/VariableAccessVisitor.java new file mode 100644 index 000000000000..81e7ade3e479 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/performance/VariableAccessVisitor.java @@ -0,0 +1,55 @@ +package com.siyeh.ig.performance; + +import com.intellij.psi.*; +import com.siyeh.ig.psiutils.ControlFlowUtils; + +import java.util.*; + +class VariableAccessVisitor extends PsiRecursiveElementVisitor { + private final Map m_accessCounts = new HashMap(2); + private final Set m_overAccessedFields = new HashSet(2); + private static final Integer ONE = new Integer(1); + private static final Integer TWO = new Integer(2); + + VariableAccessVisitor() { + super(); + } + + 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); + } + if (qualifier != null && !(qualifier instanceof PsiThisExpression)) { + return; + } + final PsiElement element = ref.resolve(); + if (!(element instanceof PsiField)) { + return; + } + final Set overAccessedFields = m_overAccessedFields; + if (overAccessedFields.contains(element)) { + return; + } + if (ControlFlowUtils.isInLoop(element)) { + overAccessedFields.add(element); + } + final Map accessCounts = m_accessCounts; + final Integer count = (Integer) accessCounts.get(element); + if (count == null) { + accessCounts.put(element, ONE); + } else if (count.equals(ONE)) { + accessCounts.put(element, TWO); + } else { + overAccessedFields.add(element); + } + } + + public Set getOveraccessedFields() { + return Collections.unmodifiableSet(m_overAccessedFields); + } +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/performance/ZeroLengthArrayInitializationInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/performance/ZeroLengthArrayInitializationInspection.java new file mode 100644 index 000000000000..51a1af3339c7 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/performance/ZeroLengthArrayInitializationInspection.java @@ -0,0 +1,85 @@ +package com.siyeh.ig.performance; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.psi.*; +import com.intellij.psi.util.PsiTreeUtil; +import com.siyeh.ig.*; +import com.siyeh.ig.fixes.IntroduceConstantFix; + +public class ZeroLengthArrayInitializationInspection extends ExpressionInspection { + private final IntroduceConstantFix fix = new IntroduceConstantFix(); + + public String getDisplayName() { + return "Zero-length array allocation"; + } + + public String getGroupDisplayName() { + return GroupNames.PERFORMANCE_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "Allocation of zero length array #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new ZeroLengthArrayInitializationVisitor(this, inspectionManager, onTheFly); + } + + protected InspectionGadgetsFix buildFix(PsiElement location) { + return fix; + } + + protected boolean buildQuickFixesOnlyForOnTheFlyErrors() { + return true; + } + + private static class ZeroLengthArrayInitializationVisitor extends BaseInspectionVisitor { + private ZeroLengthArrayInitializationVisitor(BaseInspection inspection, + InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitNewExpression(PsiNewExpression expression) { + super.visitNewExpression(expression); + final PsiExpression[] dimensions = expression.getArrayDimensions(); + final PsiArrayInitializerExpression arrayInitializer = expression.getArrayInitializer(); + if (arrayInitializer != null) { + final PsiExpression[] initializers = arrayInitializer.getInitializers(); + if (initializers == null) { + return; + } + if (initializers.length != 0) { + return; + } + } else if (dimensions != null) { + + if (dimensions.length != 1) { + return; + } + final PsiExpression dimension = dimensions[0]; + final String dimensionText = dimension.getText(); + if (!"0".equals(dimensionText)) { + return; + } + } else { + return; + } + if (isDeclaredConstant(expression)) { + return; + } + registerError(expression); + } + + private static boolean isDeclaredConstant(PsiExpression expression) { + final PsiField field = + (PsiField) PsiTreeUtil.getParentOfType(expression, PsiField.class); + if (field == null) { + return false; + } + return field.hasModifierProperty(PsiModifier.STATIC) && + field.hasModifierProperty(PsiModifier.FINAL); + } + + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/portability/HardcodedFileSeparatorsInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/portability/HardcodedFileSeparatorsInspection.java new file mode 100644 index 000000000000..d0131411f8c4 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/portability/HardcodedFileSeparatorsInspection.java @@ -0,0 +1,169 @@ +package com.siyeh.ig.portability; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiLiteralExpression; +import com.intellij.psi.PsiType; +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; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class HardcodedFileSeparatorsInspection extends ExpressionInspection { + private static final char BACKSLASH = '\\'; + private static final char SLASH = '/'; + /** + * The regular expression pattern that matches strings which are likely to be date formats. Pattern + * instances are immutable, so caching the pattern like this is still thread-safe. + */ + private static final Pattern DATE_FORMAT_PATTERN = Pattern.compile("\\b[dDmM]+/[dDmM]+(/[yY]+)?"); + /** + * A regular expression pattern that matches strings which start with a URL protocol, as they're likely to actually + * be URLs. + */ + private static final Pattern URL_PATTERN = Pattern.compile("^[a-z][a-z0-9+\\-.]+://.*$"); + + public String getDisplayName() { + return "Hardcoded file separator"; + } + + public String getGroupDisplayName() { + return GroupNames.PORTABILITY_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "Hardcoded file separator #ref #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new HardcodedFileSeparatorsVisitor(this, inspectionManager, onTheFly); + } + + /** + * Check whether a string is likely to be a filename containing one or more hard-coded file separator characters. + * The method does some simple analysis of the string to determine whether it's likely to be some other type of data + * - a URL, a date format, or an XML fragment - before deciding that the string is a filename. + * + * @param str The string to examine. + * @return true if the string is likely to be a filename with hardcoded file separators, + * false otherwise. + */ + private static boolean isHardcodedFilenameString(String str) { + if (str == null) { + return false; + } + if (str.indexOf((int) '/') == -1 && str.indexOf((int) '\\') == -1) { + return false; + } + + final char startChar = str.charAt(0); + if (Character.isLetter(startChar) && str.charAt(1) == ':') { + return true; + } + + if (isXMLString(str)) { + return false; + } + + if (isDateFormatString(str)) { + return false; + } + + if (isURLString(str)) { + return false; + } + + return true; + } + + /** + * Check whether a string containing at least one '/' or '\' character is likely to be a fragment of XML. + * + * @param str The string to examine. + * @return true if the string is likely to be an XML fragment, or false if not. + */ + private static boolean isXMLString(String str) { + if (str.indexOf("") != -1) { + return true; + } + + return false; + } + + /** + * Check whether a string containing at least one '/' or '\' character is likely to be a date format string. + * + * @param str The string to check. + * @return true if the string is likely to be a date string, false if not. + */ + private static boolean isDateFormatString(String str) { + if (str.length() < 3) { + // A string this short is very unlikely to be a date format. + return false; + } + final int strLength = str.length(); + final char startChar = str.charAt(0); + final char endChar = str.charAt(strLength - 1); + if (startChar == '/' || endChar == '/') { + // Most likely it's a filename if the string starts or ends with a slash. + return false; + } else if (Character.isLetter(startChar) && str.charAt(1) == ':') { + // Most likely this is a Windows-style full file name. + return false; + } + + final Matcher dateFormatMatcher = DATE_FORMAT_PATTERN.matcher(str); + return dateFormatMatcher.find(); + } + + /** + * Checks whether a string containing at least one '/' or '\' character is likely to be a URL. + * + * @param str The string to check. + * @return true if the string is likely to be a URL, false if not. + */ + private static boolean isURLString(String str) { + final Matcher urlMatcher = URL_PATTERN.matcher(str); + return urlMatcher.find(); + } + + private static class HardcodedFileSeparatorsVisitor extends BaseInspectionVisitor { + + private HardcodedFileSeparatorsVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitLiteralExpression(PsiLiteralExpression expression) { + super.visitLiteralExpression(expression); + final PsiType type = expression.getType(); + if (TypeUtils.isJavaLangString(type)) { + final String value = (String) expression.getValue(); + + if (isHardcodedFilenameString(value)) { + registerError(expression); + } + + } else if (type.equals(PsiType.CHAR)) { + final Character value = (Character) expression.getValue(); + if (value == null) { + return; + } + final char charValue = value.charValue(); + if (charValue == BACKSLASH || charValue == SLASH) { + registerError(expression); + } + } + + } + + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/portability/HardcodedLineSeparatorsInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/portability/HardcodedLineSeparatorsInspection.java new file mode 100644 index 000000000000..34289be12d9b --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/portability/HardcodedLineSeparatorsInspection.java @@ -0,0 +1,66 @@ +package com.siyeh.ig.portability; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiLiteralExpression; +import com.intellij.psi.PsiType; +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 HardcodedLineSeparatorsInspection extends ExpressionInspection { + private static final int NEW_LINE_CHAR = (int) '\n'; + private static final int RETURN_CHAR = (int) '\r'; + + public String getDisplayName() { + return "Hardcoded line separator"; + } + + public String getGroupDisplayName() { + return GroupNames.PORTABILITY_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "Hardcoded line separator #ref #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new HardcodedLineSeparatorsVisitor(this, inspectionManager, onTheFly); + } + + private static class HardcodedLineSeparatorsVisitor extends BaseInspectionVisitor { + + private HardcodedLineSeparatorsVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitLiteralExpression(PsiLiteralExpression expression) { + super.visitLiteralExpression(expression); + final PsiType type = expression.getType(); + if (type == null) { + return; + } + if (TypeUtils.isJavaLangString(type)) { + final String value = (String) expression.getValue(); + if (value == null) { + return; + } + if (value.indexOf(NEW_LINE_CHAR) >= 0 || + value.indexOf(RETURN_CHAR) >= 0) { + registerError(expression); + } + } else if (type.equals(PsiType.CHAR)) { + final Character value = (Character) expression.getValue(); + if (value == null) { + return; + } + if (value.charValue() == NEW_LINE_CHAR + || value.charValue() == RETURN_CHAR) { + registerError(expression); + } + } + } + } +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/portability/NativeMethodsInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/portability/NativeMethodsInspection.java new file mode 100644 index 000000000000..910f5b7d93db --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/portability/NativeMethodsInspection.java @@ -0,0 +1,44 @@ +package com.siyeh.ig.portability; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiMethod; +import com.intellij.psi.PsiModifier; +import com.siyeh.ig.BaseInspection; +import com.siyeh.ig.BaseInspectionVisitor; +import com.siyeh.ig.GroupNames; +import com.siyeh.ig.MethodInspection; + +public class NativeMethodsInspection extends MethodInspection { + + public String getDisplayName() { + return "Native method"; + } + + public String getGroupDisplayName() { + return GroupNames.PORTABILITY_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "Methods declared '#ref' are non-portable #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new NativeMethodVisitor(this, inspectionManager, onTheFly); + } + + private static class NativeMethodVisitor extends BaseInspectionVisitor { + private NativeMethodVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitMethod(PsiMethod method) { + if (!method.hasModifierProperty(PsiModifier.NATIVE)) { + return; + } + registerModifierError(PsiModifier.NATIVE, method); + } + + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/portability/RuntimeExecInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/portability/RuntimeExecInspection.java new file mode 100644 index 000000000000..beb0f809cb12 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/portability/RuntimeExecInspection.java @@ -0,0 +1,56 @@ +package com.siyeh.ig.portability; + +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 RuntimeExecInspection extends ExpressionInspection { + + public String getDisplayName() { + return "Call to Runtime.exec()"; + } + + public String getGroupDisplayName() { + return GroupNames.PORTABILITY_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "Call to Runtime.#ref() is non-portable #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new RuntimeExecVisitor(this, inspectionManager, onTheFly); + } + + private static class RuntimeExecVisitor extends BaseInspectionVisitor { + private RuntimeExecVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitMethodCallExpression(PsiMethodCallExpression expression) { + super.visitMethodCallExpression(expression); + final PsiReferenceExpression methodExpression = expression.getMethodExpression(); + if (methodExpression == null) { + return; + } + final String methodName = methodExpression.getReferenceName(); + if (!"exec".equals(methodName)) { + return; + } + final PsiMethod method = expression.resolveMethod(); + if (method == null) { + return; + } + final PsiClass aClass = method.getContainingClass(); + final String className = aClass.getQualifiedName(); + if (!"java.lang.Runtime".equals(className)) { + return; + } + registerError(expression); + } + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/portability/SystemExitInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/portability/SystemExitInspection.java new file mode 100644 index 000000000000..c5cf156a89e4 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/portability/SystemExitInspection.java @@ -0,0 +1,90 @@ +package com.siyeh.ig.portability; + +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 SystemExitInspection extends ExpressionInspection { + + public String getDisplayName() { + return "Call to System.exit() or related methods"; + } + + public String getGroupDisplayName() { + return GroupNames.PORTABILITY_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + final PsiIdentifier methodNameIdentifier = (PsiIdentifier) location; + final PsiReference methodExpression = (PsiReference) methodNameIdentifier.getParent(); + final PsiMethod method = (PsiMethod) methodExpression.resolve(); + final PsiClass containingClass = method.getContainingClass(); + return "Call to " + containingClass.getName() + ".#ref() is non-portable #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new SystemExitVisitor(this, inspectionManager, onTheFly); + } + + private static class SystemExitVisitor extends BaseInspectionVisitor { + private SystemExitVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitMethodCallExpression(PsiMethodCallExpression expression) { + super.visitMethodCallExpression(expression); + + final PsiReferenceExpression methodExpression = expression.getMethodExpression(); + if (methodExpression == null) { + return; + } + if (!isSystemExit(expression)) { + return; + } + registerMethodCallError(expression); + } + + private static boolean isSystemExit(PsiMethodCallExpression expression) { + final PsiReferenceExpression methodExpression = expression.getMethodExpression(); + + final String methodName = methodExpression.getReferenceName(); + if (!"exit".equals(methodName) && !"halt".equals(methodName)) { + return false; + } + final PsiMethod method = expression.resolveMethod(); + if (method == null) { + return false; + } + + final PsiParameterList paramList = method.getParameterList(); + if (paramList == null) { + return false; + } + final PsiParameter[] parameters = paramList.getParameters(); + if (parameters.length != 1) { + return false; + } + final PsiType parameterType = parameters[0].getType(); + if (!parameterType.equals(PsiType.INT)) { + return false; + } + final PsiClass aClass = method.getContainingClass(); + if (aClass == null) { + return false; + } + final String className = aClass.getQualifiedName(); + if (className == null) { + return false; + } + if (!"java.lang.System".equals(className) && + !"java.lang.Runtime".equals(className)) { + return false; + } + return true; + } + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/portability/SystemGetenvInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/portability/SystemGetenvInspection.java new file mode 100644 index 000000000000..e18f944960e2 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/portability/SystemGetenvInspection.java @@ -0,0 +1,69 @@ +package com.siyeh.ig.portability; + +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 SystemGetenvInspection extends ExpressionInspection { + + public String getDisplayName() { + return "Call to System.getenv()"; + } + + public String getGroupDisplayName() { + return GroupNames.PORTABILITY_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "Call to System.#ref() is non-portable #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new SystemGetenvVisitor(this, inspectionManager, onTheFly); + } + + private static class SystemGetenvVisitor extends BaseInspectionVisitor { + private SystemGetenvVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitMethodCallExpression(PsiMethodCallExpression expression) { + super.visitMethodCallExpression(expression); + final PsiReferenceExpression methodExpression = expression.getMethodExpression(); + if (methodExpression == null) { + return; + } + final String methodName = methodExpression.getReferenceName(); + if (!"getenv".equals(methodName)) { + return; + } + final PsiMethod method = expression.resolveMethod(); + if (method == null) { + return; + } + final PsiParameterList paramList = method.getParameterList(); + if (paramList == null) { + return; + } + final PsiParameter[] parameters = paramList.getParameters(); + if (parameters.length != 1) { + return; + } + final PsiType parameterType = parameters[0].getType(); + if (!TypeUtils.isJavaLangString(parameterType)) { + return; + } + final PsiClass aClass = method.getContainingClass(); + final String className = aClass.getQualifiedName(); + if (!"java.lang.System".equals(className)) { + return; + } + registerMethodCallError(expression); + } + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/portability/UseOfSunClassesInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/portability/UseOfSunClassesInspection.java new file mode 100644 index 000000000000..fad95506d9a9 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/portability/UseOfSunClassesInspection.java @@ -0,0 +1,68 @@ +package com.siyeh.ig.portability; + +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.VariableInspection; + +public class UseOfSunClassesInspection extends VariableInspection { + + public String getDisplayName() { + return "Use of sun.* classes"; + } + + public String getGroupDisplayName() { + return GroupNames.PORTABILITY_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "Use of Sun-supplied class #ref is non-portable #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new ObsoleteCollectionVisitor(this, inspectionManager, onTheFly); + } + + private static class ObsoleteCollectionVisitor extends BaseInspectionVisitor { + private ObsoleteCollectionVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitVariable(PsiVariable variable) { + super.visitVariable(variable); + final PsiType type = variable.getType(); + if (type == null) { + return; + } + final PsiType deepComponentType = type.getDeepComponentType(); + if (deepComponentType == null) { + return; + } + final String typeName = deepComponentType.getCanonicalText(); + if(!typeName.startsWith("sun.")) + { + return; + } + final PsiTypeElement typeElement = variable.getTypeElement(); + registerError(typeElement); + } + + public void visitNewExpression(PsiNewExpression newExpression) { + super.visitNewExpression(newExpression); + final PsiType type = newExpression.getType(); + if (type == null) { + return; + } + final String typeName = type.getCanonicalText(); + if (!typeName.startsWith("sun.")) { + return; + } + final PsiJavaCodeReferenceElement classNameElement = newExpression.getClassReference(); + registerError(classNameElement); + } + + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/psiutils/ArrayContentsAccessedVisitor.java b/plugins/InspectionGadgets/src/com/siyeh/ig/psiutils/ArrayContentsAccessedVisitor.java new file mode 100644 index 000000000000..b81ebe74bef2 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/psiutils/ArrayContentsAccessedVisitor.java @@ -0,0 +1,70 @@ +package com.siyeh.ig.psiutils; + +import com.intellij.psi.*; + +public class ArrayContentsAccessedVisitor extends PsiRecursiveElementVisitor { + private boolean accessed = false; + private final PsiVariable variable; + + public ArrayContentsAccessedVisitor(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); + } + } + + public void visitForeachStatement(PsiForeachStatement statement) { + super.visitForeachStatement(statement); + final PsiExpression qualifier = statement.getIteratedValue(); + if (qualifier == null) { + return; + } + if (!(qualifier instanceof PsiReferenceExpression)) { + return; + } + final PsiElement referent = ((PsiReference) qualifier).resolve(); + if (referent == null) { + return; + } + if (!referent.equals(variable)) { + return; + } + accessed = true; + } + + public void visitArrayAccessExpression(PsiArrayAccessExpression arg) { + super.visitArrayAccessExpression(arg); + if (arg.getParent() instanceof PsiAssignmentExpression && + ((PsiAssignmentExpression) arg.getParent()).getLExpression().equals(arg)) { + return; + } + final PsiExpression arrayExpression = arg.getArrayExpression(); + if (arrayExpression == null) { + return; + } + if (!(arrayExpression instanceof PsiReferenceExpression)) { + return; + } + final PsiElement referent = ((PsiReference) arrayExpression).resolve(); + if (referent == null) { + return; + } + if (referent.equals(variable)) { + accessed = true; + } + + } + + public boolean isAccessed() { + return accessed; + } +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/psiutils/ArrayContentsAssignedVisitor.java b/plugins/InspectionGadgets/src/com/siyeh/ig/psiutils/ArrayContentsAssignedVisitor.java new file mode 100644 index 000000000000..b757febbaf2f --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/psiutils/ArrayContentsAssignedVisitor.java @@ -0,0 +1,57 @@ +package com.siyeh.ig.psiutils; + +import com.intellij.psi.*; + +public class ArrayContentsAssignedVisitor extends PsiRecursiveElementVisitor { + private boolean assigned = false; + private final PsiVariable variable; + + public ArrayContentsAssignedVisitor(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); + } + } + + public void visitAssignmentExpression(PsiAssignmentExpression assignment) { + super.visitAssignmentExpression(assignment); + final PsiJavaToken operationSign = assignment.getOperationSign(); + if (operationSign.getTokenType() != JavaTokenType.EQ) { + return; + } + final PsiExpression arg = assignment.getLExpression(); + if (arg == null) { + return; + } + if (!(arg instanceof PsiArrayAccessExpression)) { + return; + } + final PsiExpression arrayExpression = ((PsiArrayAccessExpression) arg).getArrayExpression(); + if (arrayExpression == null) { + return; + } + if (!(arrayExpression instanceof PsiReferenceExpression)) { + return; + } + final PsiElement referent = ((PsiReference) arrayExpression).resolve(); + if (referent == null) { + return; + } + if (referent.equals(variable)) { + assigned = true; + } + } + + public boolean isAssigned() { + return assigned; + } +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/psiutils/BoolUtils.java b/plugins/InspectionGadgets/src/com/siyeh/ig/psiutils/BoolUtils.java new file mode 100644 index 000000000000..8490e8cf7912 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/psiutils/BoolUtils.java @@ -0,0 +1,52 @@ +package com.siyeh.ig.psiutils; + +import com.intellij.psi.JavaTokenType; +import com.intellij.psi.PsiExpression; +import com.intellij.psi.PsiJavaToken; +import com.intellij.psi.PsiPrefixExpression; + +public class BoolUtils { + private BoolUtils() { + super(); + } + + private static boolean isNegation(PsiExpression exp) { + if (!(exp instanceof PsiPrefixExpression)) { + return false; + } + final PsiPrefixExpression prefixExp = (PsiPrefixExpression) exp; + final PsiJavaToken sign = prefixExp.getOperationSign(); + return sign.getTokenType() == JavaTokenType.EXCL; + } + + private static PsiExpression getNegated(PsiExpression exp) { + final PsiPrefixExpression prefixExp = (PsiPrefixExpression) exp; + final PsiExpression operand = prefixExp.getOperand(); + return ParenthesesUtils.stripParentheses(operand); + } + + public static String getNegatedExpressionText(PsiExpression condition) { + if (isNegation(condition)) { + final PsiExpression negatedCondition = getNegated(condition); + return negatedCondition.getText(); + } else if (ParenthesesUtils.getPrecendence(condition) > + ParenthesesUtils.PREFIX_PRECEDENCE) { + return "!(" + condition.getText() + ')'; + } else { + return '!' + condition.getText(); + } + + } + + public static boolean isTrue(PsiExpression test) { + if (test == null) { + return false; + } + final String text = test.getText(); + if ("true".equals(text)) { + return true; + + } + return false; + } +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/psiutils/ClassUtils.java b/plugins/InspectionGadgets/src/com/siyeh/ig/psiutils/ClassUtils.java new file mode 100644 index 000000000000..ddf0193f0d6d --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/psiutils/ClassUtils.java @@ -0,0 +1,179 @@ +package com.siyeh.ig.psiutils; + +import com.intellij.psi.*; +import com.intellij.psi.util.PsiTreeUtil; + +import java.util.HashSet; +import java.util.Set; + +public class ClassUtils { + private ClassUtils() { + super(); + } + + private static final int NUM_IMMUTABLE_TYPES = 17; + private static final Set s_immutableTypes = new HashSet(NUM_IMMUTABLE_TYPES); + private static final Set s_primitiveNumericTypes = new HashSet(6); + private static final Set s_numericTypes = new HashSet(6); + + static { + s_primitiveNumericTypes.add("byte"); + s_primitiveNumericTypes.add("char"); + s_primitiveNumericTypes.add("short"); + s_primitiveNumericTypes.add("int"); + s_primitiveNumericTypes.add("long"); + s_primitiveNumericTypes.add("float"); + s_primitiveNumericTypes.add("double"); + + s_immutableTypes.add("boolean"); + s_immutableTypes.add("char"); + s_immutableTypes.add("short"); + s_immutableTypes.add("int"); + s_immutableTypes.add("long"); + s_immutableTypes.add("float"); + s_immutableTypes.add("double"); + s_immutableTypes.add("byte"); + s_immutableTypes.add("java.lang.Boolean"); + s_immutableTypes.add("java.lang.Char"); + s_immutableTypes.add("java.lang.Short"); + s_immutableTypes.add("java.lang.Integer"); + s_immutableTypes.add("java.lang.Long"); + s_immutableTypes.add("java.lang.Float"); + s_immutableTypes.add("java.lang.Double"); + s_immutableTypes.add("java.lang.Byte"); + s_immutableTypes.add("java.lang.String"); + s_immutableTypes.add("java.awt.Font"); + s_immutableTypes.add("java.awt.Color"); + + s_numericTypes.add("java.lang.Byte"); + s_numericTypes.add("java.lang.Short"); + s_numericTypes.add("java.lang.Integer"); + s_numericTypes.add("java.lang.Long"); + s_numericTypes.add("java.lang.Float"); + s_numericTypes.add("java.lang.Double"); + } + + public static boolean isSubclass(PsiClass aClass, String ancestorName) { + return isSubclass(aClass, ancestorName, new HashSet()); + } + + private static boolean isSubclass(PsiClass aClass, String ancestorName, Set alreadyChecked) { + PsiClass currentClass = aClass; + while (currentClass != null) { + final String className = currentClass.getQualifiedName(); + if (className != null) { + if (alreadyChecked.contains(className)) { + return false; + } else if (className.equals(ancestorName)) { + return true; + } + } + alreadyChecked.add(className); + currentClass = currentClass.getSuperClass(); + } + return false; + } + + public static boolean isPrimitive(PsiType type) { + return + type.equals(PsiType.BOOLEAN) || + type.equals(PsiType.LONG) || + type.equals(PsiType.INT) || + type.equals(PsiType.SHORT) || + type.equals(PsiType.CHAR) || + type.equals(PsiType.BYTE) || + type.equals(PsiType.FLOAT) || + type.equals(PsiType.DOUBLE); + } + + public static boolean isIntegral(PsiType type) { + return + type.equals(PsiType.LONG) || + type.equals(PsiType.INT) || + type.equals(PsiType.SHORT) || + type.equals(PsiType.CHAR) || + type.equals(PsiType.BYTE); + } + + public static boolean isImmutable(PsiType type) { + final String typeName = type.getCanonicalText(); + return s_immutableTypes.contains(typeName); + } + + private static boolean inSamePackage(PsiClass class1, PsiClass class2) { + final String className1 = class1.getQualifiedName(); + if (className1 == null) { + return false; + } + final int packageLength1 = className1.lastIndexOf((int) '.'); + final String classPackageName1; + if (packageLength1 == -1) { + classPackageName1 = ""; + } else { + classPackageName1 = className1.substring(0, packageLength1); + } + final String className2 = class2.getQualifiedName(); + if (className2 == null) { + return false; + } + final int packageLength2 = className2.lastIndexOf((int) '.'); + final String classPackageName2; + if (packageLength2 == -1) { + classPackageName2 = ""; + } else { + classPackageName2 = className2.substring(0, packageLength2); + } + return classPackageName1.equals(classPackageName2); + } + + public static boolean isFieldVisible(PsiField field, PsiClass fromClass) { + final PsiClass fieldClass = field.getContainingClass(); + + if (fieldClass.equals(fromClass)) { + return true; + } + if (field.hasModifierProperty(PsiModifier.PRIVATE)) { + return false; + } + if (field.hasModifierProperty(PsiModifier.PUBLIC) || + field.hasModifierProperty(PsiModifier.PROTECTED)) { + return true; + } + + return inSamePackage(fieldClass, fromClass); + } + + public static boolean isBuiltInNumericType(PsiType type) { + final String typeName = type.getCanonicalText(); + return s_numericTypes.contains(typeName); + } + + public static boolean isPrimitiveNumericType(PsiType type) { + final String typeName = type.getCanonicalText(); + return s_primitiveNumericTypes.contains(typeName); + } + + public static boolean isInnerClass(PsiClass aClass) { + final PsiClass parentClass = getContainingClass(aClass); + return parentClass != null; + } + + public static PsiClass getContainingClass(PsiElement aClass) { + final PsiClass parentClass = + (PsiClass) PsiTreeUtil.getParentOfType(aClass, PsiClass.class); + return parentClass; + } + + public static PsiClass getOutermostContainingClass(PsiClass aClass) { + PsiClass outerClass = aClass; + while (true) { + final PsiClass containingClass = (PsiClass) PsiTreeUtil.getParentOfType(outerClass, PsiClass.class); + if (containingClass != null) { + outerClass = containingClass; + } else { + break; + } + } + return outerClass; + } +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/psiutils/CloneUtils.java b/plugins/InspectionGadgets/src/com/siyeh/ig/psiutils/CloneUtils.java new file mode 100644 index 000000000000..b97df3898106 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/psiutils/CloneUtils.java @@ -0,0 +1,65 @@ +package com.siyeh.ig.psiutils; + +import com.intellij.psi.*; + +import java.util.HashSet; +import java.util.Set; + +public class CloneUtils { + private CloneUtils() { + super(); + + } + + public static boolean isCloneable(PsiClass aClass) { + return isCloneable(aClass, new HashSet()); + } + + private static boolean isCloneable(PsiClass aClass, Set alreadyChecked) { + final String qualifiedName = aClass.getQualifiedName(); + if (alreadyChecked.contains(qualifiedName)) { + return false; + } + alreadyChecked.add(qualifiedName); + final PsiClass[] supers = aClass.getSupers(); + for (int i = 0; i < supers.length; i++) { + final PsiClass aSuper = supers[i]; + if ("java.lang.Cloneable".equals(aSuper.getQualifiedName())) { + return true; + } + if (isCloneable(aSuper, alreadyChecked)) { + return true; + } + } + return false; + } + + public static boolean isDirectlyCloneable(PsiClass aClass) { + final PsiClass[] interfaces = aClass.getInterfaces(); + for (int i = 0; i < interfaces.length; i++) { + final String qualifiedName = interfaces[i].getQualifiedName(); + if ("java.lang.Cloneable".equals(qualifiedName)) { + return true; + } + } + return false; + } + + public static boolean isClone(PsiMethod method) { + final String methodName = method.getName(); + if (!"clone".equals(methodName)) { + return false; + } + final PsiParameterList parameterList = method.getParameterList(); + final PsiParameter[] parameters = parameterList.getParameters(); + if (parameters.length != 0) { + return false; + } + final PsiType returnType = method.getReturnType(); + if (!TypeUtils.isJavaLangObject(returnType)) { + return false; + } + return true; + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/psiutils/CollectionUtils.java b/plugins/InspectionGadgets/src/com/siyeh/ig/psiutils/CollectionUtils.java new file mode 100644 index 000000000000..3e11257f3cda --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/psiutils/CollectionUtils.java @@ -0,0 +1,227 @@ +package com.siyeh.ig.psiutils; + +import com.intellij.psi.*; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +public class CollectionUtils { + private static final Set s_collectionClassesRequiringCapacity = new HashSet(10); + private static final Set s_allCollectionClasses = new HashSet(10); + private static final Set s_allCollectionClassesAndInterfaces = new HashSet(10); + private static final Map s_interfaceForCollection = new HashMap(10); + + static { + s_collectionClassesRequiringCapacity.add("java.util.BitSet"); + s_collectionClassesRequiringCapacity.add("java.util.Vector"); + s_collectionClassesRequiringCapacity.add("java.util.ArrayList"); + s_collectionClassesRequiringCapacity.add("java.util.HashMap"); + s_collectionClassesRequiringCapacity.add("java.util.LinkedHashMap"); + s_collectionClassesRequiringCapacity.add("java.util.WeakHashMap"); + s_collectionClassesRequiringCapacity.add("java.util.Hashtable"); + s_collectionClassesRequiringCapacity.add("java.util.HashSet"); + s_collectionClassesRequiringCapacity.add("java.util.LinkedHashSet"); + s_collectionClassesRequiringCapacity.add("com.sun.java.util.collections.BitSet"); + s_collectionClassesRequiringCapacity.add("com.sun.java.util.collections.Vector"); + s_collectionClassesRequiringCapacity.add("com.sun.java.util.collections.ArrayList"); + s_collectionClassesRequiringCapacity.add("com.sun.java.util.collections.HashMap"); + s_collectionClassesRequiringCapacity.add("com.sun.java.util.collections.Hashtable"); + s_collectionClassesRequiringCapacity.add("com.sun.java.util.collections.HashSet"); + + s_allCollectionClasses.add("java.util.Vector"); + s_allCollectionClasses.add("java.util.ArrayList"); + s_allCollectionClasses.add("java.util.LinkedList"); + s_allCollectionClasses.add("java.util.HashMap"); + s_allCollectionClasses.add("java.util.IdentityHashMap"); + s_allCollectionClasses.add("java.util.LinkedHashMap"); + s_allCollectionClasses.add("java.util.WeakHashMap"); + s_allCollectionClasses.add("java.util.Hashtable"); + s_allCollectionClasses.add("java.util.HashSet"); + s_allCollectionClasses.add("java.util.LinkedHashSet"); + s_allCollectionClasses.add("java.util.TreeSet"); + s_allCollectionClasses.add("java.util.TreeMap"); + s_allCollectionClasses.add("java.util.EnumSet"); + s_allCollectionClasses.add("java.util.EnumMap"); + s_allCollectionClasses.add("com.sun.java.util.collections.Vector"); + s_allCollectionClasses.add("com.sun.java.util.collections.ArrayList"); + s_allCollectionClasses.add("com.sun.java.util.collections.LinkedList"); + s_allCollectionClasses.add("com.sun.java.util.collections.HashMap"); + s_allCollectionClasses.add("com.sun.java.util.collections.Hashtable"); + s_allCollectionClasses.add("com.sun.java.util.collections.HashSet"); + s_allCollectionClasses.add("com.sun.java.util.collections.TreeSet"); + s_allCollectionClasses.add("com.sun.java.util.collections.TreeMap"); + + s_allCollectionClassesAndInterfaces.add("java.util.Collection"); + s_allCollectionClassesAndInterfaces.add("java.util.Vector"); + s_allCollectionClassesAndInterfaces.add("java.util.ArrayList"); + s_allCollectionClassesAndInterfaces.add("java.util.LinkedList"); + s_allCollectionClassesAndInterfaces.add("java.util.HashMap"); + s_allCollectionClassesAndInterfaces.add("java.util.LinkedHashMap"); + s_allCollectionClassesAndInterfaces.add("java.util.IdentityHashMap"); + s_allCollectionClassesAndInterfaces.add("java.util.WeakHashMap"); + s_allCollectionClassesAndInterfaces.add("java.util.Hashtable"); + s_allCollectionClassesAndInterfaces.add("java.util.HashSet"); + s_allCollectionClassesAndInterfaces.add("java.util.LinkedHashSet"); + s_allCollectionClassesAndInterfaces.add("java.util.TreeSet"); + s_allCollectionClassesAndInterfaces.add("java.util.TreeMap"); + s_allCollectionClassesAndInterfaces.add("java.util.Set"); + s_allCollectionClassesAndInterfaces.add("java.util.Map"); + s_allCollectionClassesAndInterfaces.add("java.util.List"); + s_allCollectionClassesAndInterfaces.add("java.util.SortedMap"); + s_allCollectionClassesAndInterfaces.add("java.util.SortedSet"); + s_allCollectionClassesAndInterfaces.add("com.sun.java.util.collections.Collection"); + s_allCollectionClassesAndInterfaces.add("com.sun.java.util.collections.Vector"); + s_allCollectionClassesAndInterfaces.add("com.sun.java.util.collections.ArrayList"); + s_allCollectionClassesAndInterfaces.add("com.sun.java.util.collections.LinkedList"); + s_allCollectionClassesAndInterfaces.add("com.sun.java.util.collections.HashMap"); + s_allCollectionClassesAndInterfaces.add("com.sun.java.util.collections.Hashtable"); + s_allCollectionClassesAndInterfaces.add("com.sun.java.util.collections.HashSet"); + s_allCollectionClassesAndInterfaces.add("com.sun.java.util.collections.TreeSet"); + s_allCollectionClassesAndInterfaces.add("com.sun.java.util.collections.TreeMap"); + s_allCollectionClassesAndInterfaces.add("com.sun.java.util.collections.Set"); + s_allCollectionClassesAndInterfaces.add("com.sun.java.util.collections.Map"); + s_allCollectionClassesAndInterfaces.add("com.sun.java.util.collections.List"); + s_allCollectionClassesAndInterfaces.add("com.sun.java.util.collections.SortedMap"); + s_allCollectionClassesAndInterfaces.add("com.sun.java.util.collections.SortedSet"); + + s_interfaceForCollection.put("HashSet", "Set"); + s_interfaceForCollection.put("LinkedHashSet", "Set"); + s_interfaceForCollection.put("TreeSet", "SortedSet"); + s_interfaceForCollection.put("Vector", "List"); + s_interfaceForCollection.put("ArrayList", "List"); + s_interfaceForCollection.put("LinkedList", "List"); + s_interfaceForCollection.put("TreeMap", "Map"); + s_interfaceForCollection.put("HashMap", "Map"); + s_interfaceForCollection.put("IdentityHashMap", "Map"); + s_interfaceForCollection.put("LinkedHashMap", "Map"); + s_interfaceForCollection.put("WeakHashMap", "Map"); + s_interfaceForCollection.put("Hashtable", "Map"); + s_interfaceForCollection.put("EnumSet", "Set"); + s_interfaceForCollection.put("EnumMap", "Map"); + s_interfaceForCollection.put("java.util.HashSet", "java.util.Set"); + s_interfaceForCollection.put("java.util.LinkedHashSet", "java.util.Set"); + s_interfaceForCollection.put("java.util.TreeSet", "java.util.Set"); + s_interfaceForCollection.put("java.util.Vector", "java.util.List"); + s_interfaceForCollection.put("java.util.ArrayList", "java.util.List"); + s_interfaceForCollection.put("java.util.TreeMap", "java.util.Map"); + s_interfaceForCollection.put("java.util.HashMap", "java.util.Map"); + s_interfaceForCollection.put("java.util.IdentityHashMap", "java.util.Map"); + s_interfaceForCollection.put("java.util.LinkedHashMap", "java.util.Map"); + s_interfaceForCollection.put("java.util.WeakHashMap", "java.util.Map"); + s_interfaceForCollection.put("java.util.Hashtable", "java.util.Map"); + s_interfaceForCollection.put("java.util.EnumSet", "java.util.Set"); + s_interfaceForCollection.put("java.util.EnumMap", "java.util.Map"); + s_interfaceForCollection.put("com.sun.java.util.collections.HashSet", "com.sun.java.util.collections.Set"); + s_interfaceForCollection.put("com.sun.java.util.collections.TreeSet", "com.sun.java.util.collections.Set"); + s_interfaceForCollection.put("com.sun.java.util.collections.Vector", "com.sun.java.util.collections.List"); + s_interfaceForCollection.put("com.sun.java.util.collections.ArrayList", "com.sun.java.util.collections.List"); + s_interfaceForCollection.put("com.sun.java.util.collections.LinkedList", "com.sun.java.util.collections.List"); + s_interfaceForCollection.put("com.sun.java.util.collections.TreeMap", "com.sun.java.util.collections.Map"); + s_interfaceForCollection.put("com.sun.java.util.collections.HashMap", "com.sun.java.util.collections.Map"); + s_interfaceForCollection.put("com.sun.java.util.collections.Hashtable", "com.sun.java.util.collections.Map"); + } + + private CollectionUtils() { + super(); + } + + public static boolean isCollectionWithInitialCapacity(PsiType type) { + String className = type.getCanonicalText(); + final int genericParamPosition = className.indexOf((int) '<'); + if (genericParamPosition >= 0) { + className = className.substring(0, genericParamPosition); + } + return s_collectionClassesRequiringCapacity.contains(className); + } + + public static boolean isCollectionClass(PsiType type) { + String className = type.getCanonicalText(); + if (s_allCollectionClasses.contains(className)) { + return true; + } + final int genericParamPosition = className.indexOf((int) '<'); + if (genericParamPosition >= 0) { + className = className.substring(0, genericParamPosition); + } + return s_allCollectionClasses.contains(className); + } + + public static boolean isCollectionClassOrInterface(PsiType type) { + String className = type.getCanonicalText(); + if (s_allCollectionClassesAndInterfaces.contains(className)) { + return true; + } + final int genericParamPosition = className.indexOf((int) '<'); + if (genericParamPosition >= 0) { + className = className.substring(0, genericParamPosition); + } + return s_allCollectionClassesAndInterfaces.contains(className); + } + + public static boolean isConstantArrayOfZeroSize(PsiField field) { + if (!field.hasModifierProperty(PsiModifier.STATIC) || + !field.hasModifierProperty(PsiModifier.FINAL)) { + return false; + } + final PsiExpression initializer = field.getInitializer(); + if (!(initializer instanceof PsiNewExpression)) { + return false; + } + final PsiNewExpression expression = (PsiNewExpression) initializer; + final PsiExpression[] dimensions = expression.getArrayDimensions(); + if (dimensions != null) { + if (dimensions.length != 1) { + return false; + } + final PsiExpression dimension = dimensions[0]; + final String dimensionText = dimension.getText(); + if ("0".equals(dimensionText)) { + return true; + } + } + return false; + } + + public static boolean isArrayOrCollectionField(PsiExpression value) { + if (!(value instanceof PsiReferenceExpression)) { + return false; + } + final PsiReferenceExpression fieldReference = (PsiReferenceExpression) value; + + final PsiElement element = fieldReference.resolve(); + if (!(element instanceof PsiField)) { + return false; + } + final PsiType type = fieldReference.getType(); + if (type == null) { + return false; + } + if (type.getArrayDimensions() > 0) { + return !isConstantArrayOfZeroSize((PsiField) element); + } + String className = type.getCanonicalText(); + final int parameterStartPos = className.indexOf((int) '<'); + if (parameterStartPos >= 0) { + className = className.substring(0, parameterStartPos); + } + return s_allCollectionClassesAndInterfaces.contains(className); + + } + + public static String getInterfaceForClass(String name) { + String baseName; + final String arg; + final int paramStart = name.indexOf((int) '<'); + if (paramStart >= 0) { + baseName = name.substring(0, paramStart); + baseName = baseName.trim(); + arg = name.substring(paramStart); + } else { + baseName = name; + arg = ""; + } + return s_interfaceForCollection.get(baseName) + arg; + } +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/psiutils/ComparisonUtils.java b/plugins/InspectionGadgets/src/com/siyeh/ig/psiutils/ComparisonUtils.java new file mode 100644 index 000000000000..5911c827dc81 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/psiutils/ComparisonUtils.java @@ -0,0 +1,55 @@ +package com.siyeh.ig.psiutils; + +import com.intellij.psi.JavaTokenType; +import com.intellij.psi.PsiBinaryExpression; +import com.intellij.psi.PsiJavaToken; +import com.intellij.psi.tree.IElementType; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +public class ComparisonUtils { + private ComparisonUtils() { + super(); + } + + private static final Set s_comparisonStrings = new HashSet(6); + private static final Map s_swappedComparisons = new HashMap(6); + + static { + s_comparisonStrings.add("=="); + s_comparisonStrings.add("!="); + s_comparisonStrings.add(">"); + s_comparisonStrings.add("<"); + s_comparisonStrings.add(">="); + s_comparisonStrings.add("<="); + + s_swappedComparisons.put("==", "=="); + s_swappedComparisons.put("!=", "!="); + s_swappedComparisons.put(">", "<"); + s_swappedComparisons.put("<", ">"); + s_swappedComparisons.put(">=", "<="); + s_swappedComparisons.put("<=", ">="); + + } + + public static boolean isComparison(String str) { + return s_comparisonStrings.contains(str); + } + + public static String getFlippedComparison(String str) { + return (String) s_swappedComparisons.get(str); + } + + public static boolean isEqualityComparison(PsiBinaryExpression operator) { + final PsiJavaToken sign = operator.getOperationSign(); + if (sign == null) { + return false; + } + final IElementType tokenType = sign.getTokenType(); + return tokenType.equals(JavaTokenType.EQEQ) || tokenType.equals(JavaTokenType.NE); + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/psiutils/ControlFlowUtils.java b/plugins/InspectionGadgets/src/com/siyeh/ig/psiutils/ControlFlowUtils.java new file mode 100644 index 000000000000..5a63a67c6ebd --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/psiutils/ControlFlowUtils.java @@ -0,0 +1,419 @@ +package com.siyeh.ig.psiutils; + +import com.intellij.psi.*; +import com.intellij.psi.util.PsiTreeUtil; + +public class ControlFlowUtils { + private ControlFlowUtils() { + super(); + + } + + public static boolean statementMayCompleteNormally(PsiStatement statement) { + if (statement == null) { + return true; + } + if (statement instanceof PsiBreakStatement || + statement instanceof PsiContinueStatement || + statement instanceof PsiReturnStatement || + statement instanceof PsiThrowStatement) { + return false; + } else if (statement instanceof PsiExpressionListStatement || + statement instanceof PsiExpressionStatement || + statement instanceof PsiEmptyStatement || + statement instanceof PsiAssertStatement || + statement instanceof PsiDeclarationStatement) { + return true; + } else if (statement instanceof PsiForStatement) { + return forStatementMayReturnNormally((PsiForStatement) statement); + } else if (statement instanceof PsiForeachStatement) { + return foreachStatementMayReturnNormally((PsiForeachStatement) statement); + } else if (statement instanceof PsiWhileStatement) { + return whileStatementMayReturnNormally((PsiWhileStatement) statement); + } else if (statement instanceof PsiDoWhileStatement) { + return doWhileStatementMayReturnNormally((PsiDoWhileStatement) statement); + } else if (statement instanceof PsiSynchronizedStatement) { + final PsiCodeBlock body = ((PsiSynchronizedStatement) statement).getBody(); + return codeBlockMayCompleteNormally(body); + } else if (statement instanceof PsiBlockStatement) { + final PsiCodeBlock codeBlock = ((PsiBlockStatement) statement).getCodeBlock(); + return codeBlockMayCompleteNormally(codeBlock); + } else if (statement instanceof PsiLabeledStatement) { + return labeledStatementMayCompleteNormally((PsiLabeledStatement) statement); + } else if (statement instanceof PsiIfStatement) { + return ifStatementMayReturnNormally((PsiIfStatement) statement); + } else if (statement instanceof PsiTryStatement) { + return tryStatementMayReturnNormally((PsiTryStatement) statement); + } else if (statement instanceof PsiSwitchStatement) { + return switchStatementMayReturnNormally((PsiSwitchStatement) statement); + } else // unknown statement type + { + return true; + } + } + + private static boolean doWhileStatementMayReturnNormally(PsiDoWhileStatement loopStatement) { + final PsiExpression test = loopStatement.getCondition(); + final PsiStatement body = loopStatement.getBody(); + return statementMayCompleteNormally(body) && !BoolUtils.isTrue(test) + || statementIsBreakTarget(loopStatement); + } + + private static boolean whileStatementMayReturnNormally(PsiWhileStatement loopStatement) { + final PsiExpression test = loopStatement.getCondition(); + return !BoolUtils.isTrue(test) + || statementIsBreakTarget(loopStatement); + } + + private static boolean forStatementMayReturnNormally(PsiForStatement loopStatement) { + final PsiExpression test = loopStatement.getCondition(); + if (statementIsBreakTarget(loopStatement)) { + return true; + } + if (test == null) { + return false; + } + if (BoolUtils.isTrue(test)) { + return false; + } + return true; + } + + private static boolean foreachStatementMayReturnNormally(PsiForeachStatement loopStatement) { + return true; + } + + private static boolean switchStatementMayReturnNormally(PsiSwitchStatement switchStatement) { + if (statementIsBreakTarget(switchStatement)) { + return true; + } + final PsiCodeBlock body = switchStatement.getBody(); + if (body == null) { + return true; + } + final PsiStatement[] statements = body.getStatements(); + if (statements == null) { + return true; + } + if (statements.length == 0) { + return true; + } + + return statementMayCompleteNormally(statements[statements.length - 1]); + } + + private static boolean tryStatementMayReturnNormally(PsiTryStatement tryStatement) { + final PsiCodeBlock finallyBlock = tryStatement.getFinallyBlock(); + if (finallyBlock != null) { + if (!codeBlockMayCompleteNormally(finallyBlock)) { + return false; + } + } + final PsiCodeBlock tryBlock = tryStatement.getTryBlock(); + if (codeBlockMayCompleteNormally(tryBlock)) { + return true; + } + final PsiCodeBlock[] catchBlocks = tryStatement.getCatchBlocks(); + for (int i = 0; i < catchBlocks.length; i++) { + final PsiCodeBlock catchBlock = catchBlocks[i]; + if (codeBlockMayCompleteNormally(catchBlock)) { + return true; + } + } + return false; + } + + private static boolean ifStatementMayReturnNormally(PsiIfStatement ifStatement) { + final PsiStatement thenBranch = ifStatement.getThenBranch(); + if (statementMayCompleteNormally(thenBranch)) { + return true; + } + final PsiStatement elseBranch = ifStatement.getElseBranch(); + if (elseBranch == null || + statementMayCompleteNormally(elseBranch)) { + return true; + } + return false; + } + + private static boolean labeledStatementMayCompleteNormally(PsiLabeledStatement labeledStatement) { + final PsiStatement statement = labeledStatement.getStatement(); + return statementMayCompleteNormally(statement) || statementIsBreakTarget(statement); + } + + private static boolean codeBlockMayCompleteNormally(PsiCodeBlock block) { + if (block == null) { + return true; + } + final PsiStatement[] statements = block.getStatements(); + for (int i = 0; i < statements.length; i++) { + final PsiStatement statement = statements[i]; + if (!statementMayCompleteNormally(statement)) { + return false; + } + } + return true; + } + + private static boolean statementIsBreakTarget(PsiStatement statement) { + final BreakFinder breakFinder = new BreakFinder(statement); + statement.accept(breakFinder); + return breakFinder.breakFound(); + } + + public static boolean statementContainsReturn(PsiStatement statement) { + final ReturnFinder returnFinder = new ReturnFinder(); + statement.accept(returnFinder); + return returnFinder.returnFound(); + } + + public static boolean statementIsContinueTarget(PsiStatement statement) { + final ContinueFinder continueFinder = new ContinueFinder(statement); + statement.accept(continueFinder); + return continueFinder.continueFound(); + } + + public static boolean isInLoop(PsiElement element) { + return isInForStatementBody(element) || + isInForeachStatementBody(element) || + isInWhileStatementBody(element) || + isInDoWhileStatementBody(element); + } + + public static boolean isInFinallyBlock(PsiElement element) { + PsiElement currentElement = element; + while (true) { + final PsiTryStatement tryStatement = + (PsiTryStatement) PsiTreeUtil.getParentOfType(currentElement, PsiTryStatement.class); + if (tryStatement == null) { + return false; + } + final PsiCodeBlock finallyBlock = tryStatement.getFinallyBlock(); + if (finallyBlock != null) { + if (PsiTreeUtil.isAncestor(finallyBlock, currentElement, true)) { + return true; + } + } + currentElement = tryStatement; + } + } + + public static boolean isInCatchBlock(PsiElement element) { + PsiElement currentElement = element; + while (true) { + final PsiTryStatement tryStatement = + (PsiTryStatement) PsiTreeUtil.getParentOfType(currentElement, PsiTryStatement.class); + if (tryStatement == null) { + return false; + } + final PsiCodeBlock[] catchBlocks = tryStatement.getCatchBlocks(); + for (int i = 0; i < catchBlocks.length; i++) { + final PsiCodeBlock catchBlock = catchBlocks[i]; + if (PsiTreeUtil.isAncestor(catchBlock, currentElement, true)) { + return true; + } + } + currentElement = tryStatement; + } + } + + private static boolean isInWhileStatementBody(PsiElement element) { + final PsiWhileStatement whileStatement = + (PsiWhileStatement) PsiTreeUtil.getParentOfType(element, PsiWhileStatement.class); + if (whileStatement == null) { + return false; + } + final PsiStatement body = whileStatement.getBody(); + return PsiTreeUtil.isAncestor(body, element, true); + } + + private static boolean isInDoWhileStatementBody(PsiElement element) { + final PsiDoWhileStatement doWhileStatement = + (PsiDoWhileStatement) PsiTreeUtil.getParentOfType(element, PsiDoWhileStatement.class); + if (doWhileStatement == null) { + return false; + } + final PsiStatement body = doWhileStatement.getBody(); + return PsiTreeUtil.isAncestor(body, element, true); + } + + private static boolean isInForStatementBody(PsiElement element) { + final PsiForStatement forStatement = + (PsiForStatement) PsiTreeUtil.getParentOfType(element, PsiForStatement.class); + if (forStatement == null) { + return false; + } + final PsiStatement body = forStatement.getBody(); + return PsiTreeUtil.isAncestor(body, element, true); + } + + private static boolean isInForeachStatementBody(PsiElement element) { + final PsiForeachStatement foreachStatement = + (PsiForeachStatement) PsiTreeUtil.getParentOfType(element, PsiForeachStatement.class); + if (foreachStatement == null) { + return false; + } + final PsiStatement body = foreachStatement.getBody(); + return PsiTreeUtil.isAncestor(body, element, true); + } + + public static PsiStatement stripBraces(PsiStatement branch) { + if (branch instanceof PsiBlockStatement) { + final PsiBlockStatement block = (PsiBlockStatement) branch; + final PsiCodeBlock codeBlock = block.getCodeBlock(); + final PsiStatement[] statements = codeBlock.getStatements(); + if (statements.length == 1) { + return statements[0]; + } else { + return block; + } + } else { + return branch; + } + } + + private static class ReturnFinder extends PsiRecursiveElementVisitor { + private boolean m_found = false; + + private ReturnFinder() { + super(); + } + + public boolean returnFound() { + return m_found; + } + + public void visitClass(PsiClass psiClass) { + // do nothing, to keep drilling into inner classes + } + + public void visitReferenceExpression(PsiReferenceExpression ref) { + } + + public void visitReturnStatement(PsiReturnStatement returnStatement) { + super.visitReturnStatement(returnStatement); + m_found = true; + } + } + + private static class BreakFinder extends PsiRecursiveElementVisitor { + private boolean m_found = false; + private final PsiStatement m_target; + + private BreakFinder(PsiStatement target) { + super(); + m_target = target; + } + + public boolean breakFound() { + return m_found; + } + + public void visitReferenceExpression(PsiReferenceExpression ref) { + } + + public void visitBreakStatement(PsiBreakStatement breakStatement) { + super.visitBreakStatement(breakStatement); + final PsiStatement exitedStatement = breakStatement.findExitedStatement(); + if (m_target.equals(exitedStatement)) { + m_found = true; + } + } + } + + private static class ContinueFinder extends PsiRecursiveElementVisitor { + private boolean m_found = false; + private int m_nestingDepth = 0; + private String m_label = null; + + private ContinueFinder(PsiStatement target) { + super(); + if (target.getParent() instanceof PsiLabeledStatement) { + final PsiLabeledStatement labeledStatement = (PsiLabeledStatement) target.getParent(); + final PsiIdentifier identifier = labeledStatement.getLabelIdentifier(); + m_label = identifier.getText(); + } + } + + public boolean continueFound() { + return m_found; + } + + public void visitReferenceExpression(PsiReferenceExpression ref) { + } + + public void visitContinueStatement(PsiContinueStatement statement) { + super.visitContinueStatement(statement); + final PsiIdentifier labelIdentifier = statement.getLabelIdentifier(); + if (m_nestingDepth == 1 && labelIdentifier == null) { + m_found = true; + } else if (labelMatches(labelIdentifier)) { + m_found = true; + } + } + + private boolean labelMatches(PsiIdentifier labelIdentifier) { + if (labelIdentifier == null) { + return false; + } + final String labelText = labelIdentifier.getText(); + return labelText.equals(m_label); + } + + public void visitDoWhileStatement(PsiDoWhileStatement statement) { + m_nestingDepth++; + super.visitDoWhileStatement(statement); + m_nestingDepth--; + } + + public void visitForStatement(PsiForStatement statement) { + m_nestingDepth++; + super.visitForStatement(statement); + m_nestingDepth--; + } + + public void visitForeachStatement(PsiForeachStatement statement) { + m_nestingDepth++; + super.visitForeachStatement(statement); + m_nestingDepth--; + } + + public void visitWhileStatement(PsiWhileStatement statement) { + m_nestingDepth++; + super.visitWhileStatement(statement); + m_nestingDepth--; + } + + } + + public static boolean isInExitStatement(PsiExpression expression) { + return isInReturnStatementArgument(expression) || + isInThrowStatementArgument(expression); + } + + private static boolean isInReturnStatementArgument(PsiExpression expression) { + final PsiReturnStatement returnStatement = + (PsiReturnStatement) PsiTreeUtil.getParentOfType(expression, PsiReturnStatement.class); + return returnStatement != null; + } + + private static boolean isInThrowStatementArgument(PsiExpression expression) { + final PsiThrowStatement throwStatement = + (PsiThrowStatement) PsiTreeUtil.getParentOfType(expression, PsiThrowStatement.class); + return throwStatement != null; + } + + public static boolean methodAlwaysThrowsException(PsiMethod method) { + final PsiCodeBlock body = method.getBody(); + final ReturnFinder returnFinder = new ReturnFinder(); + body.accept(returnFinder); + if (returnFinder.returnFound()) { + return false; + } + if (codeBlockMayCompleteNormally(body)) { + return false; + } + return true; + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/psiutils/ExceptionUtils.java b/plugins/InspectionGadgets/src/com/siyeh/ig/psiutils/ExceptionUtils.java new file mode 100644 index 000000000000..581df980cacc --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/psiutils/ExceptionUtils.java @@ -0,0 +1,154 @@ +package com.siyeh.ig.psiutils; + +import com.intellij.psi.*; + +import java.util.Collections; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Set; + +public class ExceptionUtils { + private ExceptionUtils() { + super(); + } + + private static final Set s_genericExceptionTypes = new HashSet(4); + + static { + s_genericExceptionTypes.add("java.lang.Throwable"); + s_genericExceptionTypes.add("java.lang.Exception"); + s_genericExceptionTypes.add("java.lang.RuntimeException"); + s_genericExceptionTypes.add("java.lang.Error"); + } + + private static Set getExceptionTypesHandled(PsiTryStatement statement) { + final Set out = new HashSet(5); + final PsiParameter[] params = statement.getCatchBlockParameters(); + for (int i = 0; i < params.length; i++) { + final PsiType type = params[i].getType(); + out.add(type); + } + return out; + } + + public static Set calculateExceptionsThrown(PsiElement statement, PsiElementFactory factory) { + final ExceptionsThrownVisitor visitor = new ExceptionsThrownVisitor(factory); + statement.accept(visitor); + return visitor.getExceptionsThrown(); + } + + public static boolean isGenericExceptionClass(PsiType exceptionType) { + if (exceptionType == null) { + return false; + } + final String className = exceptionType.getCanonicalText(); + return s_genericExceptionTypes.contains(className); + + } + + private static class ExceptionsThrownVisitor extends PsiRecursiveElementVisitor { + private final PsiElementFactory m_factory; + private final Set m_exceptionsThrown = new HashSet(4); + + private ExceptionsThrownVisitor(PsiElementFactory factory) { + super(); + m_factory = factory; + } + + public void visitReferenceExpression(PsiReferenceExpression expression) { + + } + + public void visitMethodCallExpression(PsiMethodCallExpression expression) { + super.visitMethodCallExpression(expression); + final PsiMethod method = expression.resolveMethod(); + if (method == null) { + return; + } + final PsiReferenceList throwsList = method.getThrowsList(); + if (throwsList == null) { + return; + } + final PsiJavaCodeReferenceElement[] list = throwsList.getReferenceElements(); + for (int i = 0; i < list.length; i++) { + final PsiJavaCodeReferenceElement referenceElement = list[i]; + final PsiClass exceptionClass = (PsiClass) referenceElement.resolve(); + if (exceptionClass != null) { + final PsiClassType exceptionType = m_factory.createType(exceptionClass); + m_exceptionsThrown.add(exceptionType); + } + } + } + + public void visitNewExpression(PsiNewExpression expression) { + super.visitNewExpression(expression); + final PsiMethod method = expression.resolveMethod(); + if (method != null) { + final PsiReferenceList throwsList = method.getThrowsList(); + final PsiJavaCodeReferenceElement[] list = throwsList.getReferenceElements(); + for (int i = 0; i < list.length; i++) { + final PsiJavaCodeReferenceElement referenceElement = list[i]; + final PsiClass exceptionClass = (PsiClass) referenceElement.resolve(); + if (exceptionClass != null) { + final PsiClassType exceptionType = m_factory.createType(exceptionClass); + m_exceptionsThrown.add(exceptionType); + } + } + } + } + + 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; + } + m_exceptionsThrown.add(type); + } + + public void visitTryStatement(PsiTryStatement statement) { + final PsiCodeBlock tryBlock = statement.getTryBlock(); + final PsiElementFactory factory = m_factory; + final Set exceptionsThrown = m_exceptionsThrown; + if (tryBlock != null) { + final Set tryExceptions = calculateExceptionsThrown(tryBlock, factory); + final Set exceptionsHandled = ExceptionUtils.getExceptionTypesHandled(statement); + for (Iterator thrown = tryExceptions.iterator(); thrown.hasNext();) { + final PsiType thrownType = (PsiType) thrown.next(); + if (!isExceptionHandled(exceptionsHandled, thrownType)) { + exceptionsThrown.add(thrownType); + } + } + } + final PsiCodeBlock finallyBlock = statement.getFinallyBlock(); + if (finallyBlock != null) { + final Set finallyExceptions = calculateExceptionsThrown(finallyBlock, factory); + exceptionsThrown.addAll(finallyExceptions); + } + + final PsiCodeBlock[] catchBlocks = statement.getCatchBlocks(); + for (int i = 0; i < catchBlocks.length; i++) { + final Set catchExceptions = calculateExceptionsThrown(catchBlocks[i], factory); + exceptionsThrown.addAll(catchExceptions); + } + } + + private static boolean isExceptionHandled(Set exceptionHandled, PsiType thrownType) { + for (Iterator handled = exceptionHandled.iterator(); handled.hasNext();) { + final PsiType handledType = (PsiType) handled.next(); + if (handledType.isAssignableFrom(thrownType)) { + return true; + } + } + return false; + } + + private Set getExceptionsThrown() { + return Collections.unmodifiableSet(m_exceptionsThrown); + } + } +} \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/psiutils/ExpectedTypeUtils.java b/plugins/InspectionGadgets/src/com/siyeh/ig/psiutils/ExpectedTypeUtils.java new file mode 100644 index 000000000000..9ed39ae5b0e3 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/psiutils/ExpectedTypeUtils.java @@ -0,0 +1,164 @@ +package com.siyeh.ig.psiutils; + +import com.intellij.openapi.project.Project; +import com.intellij.psi.*; +import com.intellij.psi.search.GlobalSearchScope; + +public class ExpectedTypeUtils { + + private ExpectedTypeUtils() { + super(); + } + + public static PsiType findExpectedType(PsiExpression exp) { + PsiElement context = exp.getParent(); + PsiExpression wrappedExp = exp; + final PsiManager manager = exp.getManager(); + while (context instanceof PsiParenthesizedExpression) { + wrappedExp = (PsiExpression) context; + context = context.getParent(); + } + if (context instanceof PsiVariable) { + final PsiVariable psiVariable = (PsiVariable) context; + return psiVariable.getType(); + } else if (context instanceof PsiReferenceExpression) { + final PsiReferenceExpression ref = (PsiReferenceExpression) context; + final PsiElement parent = ref.getParent(); + if (parent instanceof PsiMethodCallExpression) { + final PsiMethod psiMethod = ((PsiMethodCallExpression) parent).resolveMethod(); + if (psiMethod == null) { + return null; + } + final PsiClass aClass = psiMethod.getContainingClass(); + final PsiElementFactory factory = manager.getElementFactory(); + return factory.createType(aClass); + } else if (parent instanceof PsiReferenceExpression) { + final PsiElement elt = ((PsiReferenceExpression) parent).resolve(); + if (elt instanceof PsiField) { + final PsiClass aClass = ((PsiField) elt).getContainingClass(); + final PsiElementFactory factory = manager.getElementFactory(); + return factory.createType(aClass); + } else { + return null; + } + } + + } else if (context instanceof PsiAssignmentExpression) { + final PsiAssignmentExpression assignment = (PsiAssignmentExpression) context; + final PsiExpression rExpression = assignment.getRExpression(); + if (rExpression != null) { + if (rExpression.equals(wrappedExp)) { + final PsiExpression lExpression = assignment.getLExpression(); + return lExpression.getType(); + } + } + } else if (context instanceof PsiBinaryExpression) { + final PsiBinaryExpression binaryExp = (PsiBinaryExpression) context; + final PsiJavaToken sign = binaryExp.getOperationSign(); + final PsiType type = binaryExp.getType(); + if (TypeUtils.isJavaLangString(type)) { + return null; + } + if (isArithmeticOperation(sign)) { + return type; + } else { + return null; + } + } else if (context instanceof PsiPrefixExpression) { + final PsiPrefixExpression prefixExp = (PsiPrefixExpression) context; + return prefixExp.getType(); + } else if (context instanceof PsiPostfixExpression) { + final PsiPostfixExpression postfixExp = (PsiPostfixExpression) context; + return postfixExp.getType(); + } else if (context instanceof PsiConditionalExpression) { + final PsiConditionalExpression conditional = (PsiConditionalExpression) context; + final PsiExpression condition = conditional.getCondition(); + if (condition.equals(wrappedExp)) { + return PsiType.BOOLEAN; + } + return conditional.getType(); + } else if (context instanceof PsiExpressionList) { + final PsiExpressionList expList = (PsiExpressionList) context; + final PsiMethod method = ExpectedTypeUtils.findCalledMethod(expList); + if (method == null) { + return null; + } + final int parameterPosition = ExpectedTypeUtils.getParameterPosition(expList, wrappedExp); + return ExpectedTypeUtils.getTypeOfParemeter(method, parameterPosition); + } else if (context instanceof PsiReturnStatement) { + final PsiReturnStatement psiReturnStatement = (PsiReturnStatement) context; + final PsiMethod method = ExpectedTypeUtils.findEnclosingPsiMethod(psiReturnStatement); + if (method == null) { + return null; + } + return method.getReturnType(); + } else if (context instanceof PsiWhileStatement) { + return PsiType.BOOLEAN; + } else if (context instanceof PsiDoWhileStatement) { + return PsiType.BOOLEAN; + } else if (context instanceof PsiForStatement) { + return PsiType.BOOLEAN; + } else if (context instanceof PsiIfStatement) { + return PsiType.BOOLEAN; + } else if (context instanceof PsiSynchronizedStatement) { + final Project project = manager.getProject(); + final GlobalSearchScope scope = GlobalSearchScope.allScope(project); + return PsiClassType.getJavaLangObject(manager, scope); + } + return null; + } + + private static boolean isArithmeticOperation(PsiJavaToken sign) { + return sign.equals(JavaTokenType.PLUS) + || sign.equals(JavaTokenType.MINUS) + || sign.equals(JavaTokenType.ASTERISK) + || sign.equals(JavaTokenType.DIV) || + sign.equals(JavaTokenType.PERC); + } + + private static int getParameterPosition(PsiExpressionList expressionList, PsiExpression exp) { + final PsiExpression[] expressions = expressionList.getExpressions(); + for (int i = 0; i < expressions.length; i++) { + if (expressions[i].equals(exp)) { + return i; + } + } + return -1; + } + + private static PsiType getTypeOfParemeter(PsiMethod psiMethod, int parameterPosition) { + final PsiParameterList paramList = psiMethod.getParameterList(); + final PsiParameter[] parameters = paramList.getParameters(); + if (parameterPosition >= parameters.length || parameterPosition < 0) { + return null; + } + + final PsiParameter param = parameters[parameterPosition]; + return param.getType(); + } + + private static PsiMethod findEnclosingPsiMethod(PsiElement psiElement) { + PsiElement currentPsiElement = psiElement; + while (currentPsiElement != null) { + currentPsiElement = currentPsiElement.getParent(); + if (currentPsiElement instanceof PsiMethod) { + return (PsiMethod) currentPsiElement; + } + } + return null; + } + + private static PsiMethod findCalledMethod(PsiExpressionList expList) { + final PsiElement parent = expList.getParent(); + if (parent instanceof PsiMethodCallExpression) { + final PsiMethodCallExpression methodCall = (PsiMethodCallExpression) parent; + final PsiMethod method = methodCall.resolveMethod(); + return method; + } else if (parent instanceof PsiNewExpression) { + final PsiNewExpression psiNewExpression = (PsiNewExpression) parent; + return psiNewExpression.resolveMethod(); + } + return null; + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/psiutils/ExpressionEquivalenceChecker.java b/plugins/InspectionGadgets/src/com/siyeh/ig/psiutils/ExpressionEquivalenceChecker.java new file mode 100644 index 000000000000..a69e9ec75a05 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/psiutils/ExpressionEquivalenceChecker.java @@ -0,0 +1,314 @@ +package com.siyeh.ig.psiutils; + +import com.intellij.psi.*; + +public class ExpressionEquivalenceChecker { + private ExpressionEquivalenceChecker() { + super(); + + } + + private static final int THIS_EXPRESSION = 0; + private static final int LITERAL_EXPRESSION = 1; + private static final int CLASS_OBJECT_EXPRESSION = 2; + private static final int REFERENCE_EXPRESSION = 3; + private static final int SUPER_EXPRESSION = 4; + private static final int METHOD_CALL_EXPRESSION = 5; + private static final int NEW_EXPRESSION = 6; + private static final int ARRAY_INITIALIZER_EXPRESSION = 7; + private static final int TYPECAST_EXPRESSION = 8; + private static final int ARRAY_ACCESS_EXPRESSION = 9; + private static final int PREFIX_EXPRESSION = 10; + private static final int POSTFIX_EXPRESSION = 11; + private static final int BINARY_EXPRESSION = 12; + private static final int CONDITIONAL_EXPRESSION = 13; + private static final int ASSIGNMENT_EXPRESSION = 14; + + public static boolean expressionsAreEquivalent(PsiExpression exp1, PsiExpression exp2) { + if (exp1 == null && exp2 == null) { + return true; + } + if (exp1 == null || exp2 == null) { + return false; + } + final PsiExpression expToCompare1 = stripParentheses(exp1); + final PsiExpression expToCompare2 = stripParentheses(exp2); + final int type1 = getExpressionType(expToCompare1); + final int type2 = getExpressionType(expToCompare2); + if (type1 != type2) { + return false; + } + switch (type1) { + case THIS_EXPRESSION: + case SUPER_EXPRESSION: + return true; + case LITERAL_EXPRESSION: + case CLASS_OBJECT_EXPRESSION: + final String text1 = expToCompare1.getText(); + final String text2 = expToCompare2.getText(); + return text1.equals(text2); + case REFERENCE_EXPRESSION: + return referenceExpressionsAreEquivalent((PsiReferenceExpression) expToCompare1, + (PsiReferenceExpression) expToCompare2); + case METHOD_CALL_EXPRESSION: + return methodCallExpressionsAreEquivalent((PsiMethodCallExpression) expToCompare1, + (PsiMethodCallExpression) expToCompare2); + case NEW_EXPRESSION: + return newExpressionsAreEquivalent((PsiNewExpression) expToCompare1, + (PsiNewExpression) expToCompare2); + case ARRAY_INITIALIZER_EXPRESSION: + return arrayInitializerExpressionsAreEquivalent((PsiArrayInitializerExpression) expToCompare1, + (PsiArrayInitializerExpression) expToCompare2); + case TYPECAST_EXPRESSION: + return typecastExpressionsAreEquivalent((PsiTypeCastExpression) expToCompare2, + (PsiTypeCastExpression) expToCompare1); + case ARRAY_ACCESS_EXPRESSION: + return arrayAccessExpressionsAreEquivalent((PsiArrayAccessExpression) expToCompare2, + (PsiArrayAccessExpression) expToCompare1); + case PREFIX_EXPRESSION: + return prefixExpressionsAreEquivalent((PsiPrefixExpression) expToCompare1, + (PsiPrefixExpression) expToCompare2); + case POSTFIX_EXPRESSION: + return postfixExpressionsAreEquivalent((PsiPostfixExpression) expToCompare1, + (PsiPostfixExpression) expToCompare2); + case BINARY_EXPRESSION: + return binaryExpressionsAreEquivalent((PsiBinaryExpression) expToCompare1, + (PsiBinaryExpression) expToCompare2); + case ASSIGNMENT_EXPRESSION: + return assignmentExpressionsAreEquivalent((PsiAssignmentExpression) expToCompare1, + (PsiAssignmentExpression) expToCompare2); + case CONDITIONAL_EXPRESSION: + return conditionalExpressionsAreEquivalent((PsiConditionalExpression) expToCompare1, + (PsiConditionalExpression) expToCompare2); + default: + return false; + } + } + + private static PsiExpression stripParentheses(PsiExpression exp) { + PsiExpression strippedExpression = exp; + while (strippedExpression instanceof PsiParenthesizedExpression) { + final PsiParenthesizedExpression parenExp = (PsiParenthesizedExpression) strippedExpression; + strippedExpression = parenExp.getExpression(); + } + return strippedExpression; + } + + private static boolean referenceExpressionsAreEquivalent(PsiReferenceExpression expToCompare1, PsiReferenceExpression expToCompare2) { + final String referenceName1 = expToCompare1.getReferenceName(); + final String referenceName2 = expToCompare2.getReferenceName(); + if (!referenceName1.equals(referenceName2)) { + return false; + } + final PsiExpression qualifier1 = expToCompare1.getQualifierExpression(); + final PsiExpression qualifier2 = expToCompare2.getQualifierExpression(); + + return expressionsAreEquivalent(qualifier1, qualifier2); + } + + private static boolean methodCallExpressionsAreEquivalent(PsiMethodCallExpression methodExp1, + PsiMethodCallExpression methodExp2) { + final PsiReferenceExpression methodExpression1 = methodExp1.getMethodExpression(); + final PsiReferenceExpression methodExpression2 = methodExp2.getMethodExpression(); + if (!expressionsAreEquivalent(methodExpression1, methodExpression2)) { + return false; + } + final PsiExpressionList argumentList1 = methodExp1.getArgumentList(); + final PsiExpression[] args1 = argumentList1.getExpressions(); + final PsiExpressionList argumentList2 = methodExp2.getArgumentList(); + final PsiExpression[] args2 = argumentList2.getExpressions(); + return expressionListsAreEquivalent(args1, + args2); + } + + private static boolean newExpressionsAreEquivalent(PsiNewExpression newExp1, PsiNewExpression newExp2) { + final PsiExpression[] dimensions1 = newExp1.getArrayDimensions(); + final PsiExpression[] dimensions2 = newExp2.getArrayDimensions(); + if (!expressionListsAreEquivalent(dimensions1, dimensions2)) { + return false; + } + final PsiArrayInitializerExpression initializer1 = newExp1.getArrayInitializer(); + final PsiArrayInitializerExpression initializer2 = newExp2.getArrayInitializer(); + if (!expressionsAreEquivalent(initializer1, initializer2)) { + return false; + } + final PsiExpression qualifier1 = newExp1.getQualifier(); + final PsiExpression qualifier2 = newExp2.getQualifier(); + if (!expressionsAreEquivalent(qualifier1, qualifier2)) { + return false; + } + final PsiExpressionList argumentList1 = newExp1.getArgumentList(); + final PsiExpression[] args1 = argumentList1.getExpressions(); + final PsiExpressionList argumentList2 = newExp2.getArgumentList(); + final PsiExpression[] args2 = argumentList2.getExpressions(); + return expressionListsAreEquivalent(args1, + args2); + } + + private static boolean arrayInitializerExpressionsAreEquivalent(PsiArrayInitializerExpression arrInitExp1, + PsiArrayInitializerExpression arrInitExp2) { + final PsiExpression[] initializers1 = arrInitExp1.getInitializers(); + final PsiExpression[] initializers2 = arrInitExp2.getInitializers(); + return expressionListsAreEquivalent(initializers1, initializers2); + } + + private static boolean typecastExpressionsAreEquivalent(PsiTypeCastExpression typecastExp2, + PsiTypeCastExpression typecastExp1) { + final PsiTypeElement castType2 = typecastExp2.getCastType(); + final String castTypeText2 = castType2.getText(); + final PsiTypeElement castType1 = typecastExp1.getCastType(); + final String castTypeText1 = castType1.getText(); + if (!castTypeText2.equals(castTypeText1)) { + return false; + } + final PsiExpression operand1 = typecastExp1.getOperand(); + final PsiExpression operand2 = typecastExp2.getOperand(); + return expressionsAreEquivalent(operand1, operand2); + } + + private static boolean arrayAccessExpressionsAreEquivalent(PsiArrayAccessExpression arrAccessExp2, + PsiArrayAccessExpression arrAccessExp1) { + final PsiExpression array1 = arrAccessExp2.getArrayExpression(); + final PsiExpression array2 = arrAccessExp1.getArrayExpression(); + final PsiExpression index1 = arrAccessExp1.getIndexExpression(); + final PsiExpression index2 = arrAccessExp2.getIndexExpression(); + return expressionsAreEquivalent(array1, array2) + && expressionsAreEquivalent(index1, index2); + } + + private static boolean prefixExpressionsAreEquivalent(PsiPrefixExpression prefixExp1, + PsiPrefixExpression prefixExp2) { + final PsiJavaToken sign1 = prefixExp1.getOperationSign(); + final PsiJavaToken sign2 = prefixExp2.getOperationSign(); + if (sign1.getTokenType() != sign2.getTokenType()) { + return false; + } + final PsiExpression operand1 = prefixExp1.getOperand(); + final PsiExpression operand2 = prefixExp2.getOperand(); + return expressionsAreEquivalent(operand1, operand2); + } + + private static boolean postfixExpressionsAreEquivalent(PsiPostfixExpression postfixExp1, + PsiPostfixExpression postfixExp2) { + final PsiJavaToken sign1 = postfixExp1.getOperationSign(); + final PsiJavaToken sign2 = postfixExp2.getOperationSign(); + if (sign1.getTokenType() != sign2.getTokenType()) { + return false; + } + final PsiExpression operand1 = postfixExp1.getOperand(); + final PsiExpression operand2 = postfixExp2.getOperand(); + return expressionsAreEquivalent(operand1, operand2); + } + + private static boolean binaryExpressionsAreEquivalent(PsiBinaryExpression binaryExp1, + PsiBinaryExpression binaryExp2) { + final PsiJavaToken sign1 = binaryExp1.getOperationSign(); + final PsiJavaToken sign2 = binaryExp2.getOperationSign(); + if (sign1.getTokenType() != + sign2.getTokenType()) { + return false; + } + final PsiExpression lhs1 = binaryExp1.getLOperand(); + final PsiExpression lhs2 = binaryExp2.getLOperand(); + final PsiExpression rhs1 = binaryExp1.getROperand(); + final PsiExpression rhs2 = binaryExp2.getROperand(); + return expressionsAreEquivalent(lhs1, lhs2) + && expressionsAreEquivalent(rhs1, rhs2); + } + + private static boolean assignmentExpressionsAreEquivalent(PsiAssignmentExpression assignExp1, + PsiAssignmentExpression assignExp2) { + final PsiJavaToken sign1 = assignExp1.getOperationSign(); + final PsiJavaToken sign2 = assignExp2.getOperationSign(); + if (sign1.getTokenType() != + sign2.getTokenType()) { + return false; + } + final PsiExpression lhs1 = assignExp1.getLExpression(); + final PsiExpression lhs2 = assignExp2.getLExpression(); + final PsiExpression rhs1 = assignExp1.getRExpression(); + final PsiExpression rhs2 = assignExp2.getRExpression(); + return expressionsAreEquivalent(lhs1, lhs2) + && expressionsAreEquivalent(rhs1, rhs2); + } + + private static boolean conditionalExpressionsAreEquivalent(PsiConditionalExpression condExp1, + PsiConditionalExpression condExp2) { + final PsiExpression cond1 = condExp1.getCondition(); + final PsiExpression cond2 = condExp2.getCondition(); + final PsiExpression then1 = condExp1.getThenExpression(); + final PsiExpression else1 = condExp1.getElseExpression(); + final PsiExpression then2 = condExp2.getThenExpression(); + final PsiExpression else2 = condExp2.getElseExpression(); + return expressionsAreEquivalent(cond1, cond2) + && expressionsAreEquivalent(then1, then2) + && expressionsAreEquivalent(else1, else2); + } + + private static boolean expressionListsAreEquivalent(PsiExpression[] expressions1, PsiExpression[] expressions2) { + if (expressions1 == null && expressions2 == null) { + return true; + } + if (expressions1 == null || expressions2 == null) { + return false; + } + if (expressions1.length != expressions2.length) { + return false; + } + for (int i = 0; i < expressions1.length; i++) { + if (!expressionsAreEquivalent(expressions1[i], expressions1[i])) { + return false; + } + } + return true; + } + + private static int getExpressionType(PsiExpression exp) { + if (exp instanceof PsiThisExpression) { + return THIS_EXPRESSION; + } + if (exp instanceof PsiLiteralExpression) { + return LITERAL_EXPRESSION; + } + if (exp instanceof PsiClassObjectAccessExpression) { + return CLASS_OBJECT_EXPRESSION; + } + if (exp instanceof PsiReferenceExpression) { + return REFERENCE_EXPRESSION; + } + if (exp instanceof PsiSuperExpression) { + return SUPER_EXPRESSION; + } + if (exp instanceof PsiMethodCallExpression) { + return METHOD_CALL_EXPRESSION; + } + if (exp instanceof PsiNewExpression) { + return NEW_EXPRESSION; + } + if (exp instanceof PsiArrayInitializerExpression) { + return ARRAY_INITIALIZER_EXPRESSION; + } + if (exp instanceof PsiTypeCastExpression) { + return TYPECAST_EXPRESSION; + } + if (exp instanceof PsiArrayAccessExpression) { + return ARRAY_ACCESS_EXPRESSION; + } + if (exp instanceof PsiPrefixExpression) { + return PREFIX_EXPRESSION; + } + if (exp instanceof PsiPostfixExpression) { + return POSTFIX_EXPRESSION; + } + if (exp instanceof PsiBinaryExpression) { + return BINARY_EXPRESSION; + } + if (exp instanceof PsiConditionalExpression) { + return CONDITIONAL_EXPRESSION; + } + if (exp instanceof PsiAssignmentExpression) { + return ASSIGNMENT_EXPRESSION; + } + return -1; + } +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/psiutils/ImportUtils.java b/plugins/InspectionGadgets/src/com/siyeh/ig/psiutils/ImportUtils.java new file mode 100644 index 000000000000..add8e764f276 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/psiutils/ImportUtils.java @@ -0,0 +1,168 @@ +package com.siyeh.ig.psiutils; + +import com.intellij.psi.*; + +public class ImportUtils { + private ImportUtils() { + super(); + } + + public static boolean nameCanBeImported(String fqName, PsiJavaFile file) { + if (hasExactImportMatch(fqName, file)) { + return true; + } + if (hasExactImportConflict(fqName, file)) { + return false; + } + if (hasOnDemandImportConflict(fqName, file)) { + return false; + } + if (containsConflictingClassReference(fqName, file)) { + return false; + } + return true; + } + + private static boolean hasExactImportMatch(String fqName, PsiJavaFile file) { + final PsiImportList imports = file.getImportList(); + final PsiImportStatement[] importStatements = imports.getImportStatements(); + for (int i = 0; i < importStatements.length; i++) { + final PsiImportStatement importStatement = importStatements[i]; + if (!importStatement.isOnDemand()) { + final String importName = importStatement.getQualifiedName(); + if (importName.equals(fqName)) { + return true; + } + } + } + return false; + } + + private static boolean hasExactImportConflict(String fqName, PsiJavaFile file) { + final PsiImportList imports = file.getImportList(); + final PsiImportStatement[] importStatements = imports.getImportStatements(); + final int lastDotIndex = fqName.lastIndexOf((int) '.'); + final String shortName = fqName.substring(lastDotIndex + 1); + final String dottedShortName = '.' + shortName; + for (int i = 0; i < importStatements.length; i++) { + final PsiImportStatement importStatement = importStatements[i]; + if (!importStatement.isOnDemand()) { + final String importName = importStatement.getQualifiedName(); + + if (!importName.equals(fqName)) { + if (importName.endsWith(dottedShortName)) { + return true; + } + } + } + } + return false; + } + + public static boolean hasOnDemandImportConflict(String fqName, PsiJavaFile file) { + final PsiImportList imports = file.getImportList(); + final PsiImportStatement[] importStatements = imports.getImportStatements(); + final int lastDotIndex = fqName.lastIndexOf((int) '.'); + final String shortName = fqName.substring(lastDotIndex + 1); + final String packageName = fqName.substring(0, lastDotIndex); + for (int i = 0; i < importStatements.length; i++) { + final PsiImportStatement importStatement = importStatements[i]; + if (importStatement.isOnDemand()) { + final PsiJavaCodeReferenceElement ref = importStatement.getImportReference(); + if (ref == null) { + continue; + } + final String packageText = ref.getText(); + if (packageText.equals(packageName)) { + continue; + } + final PsiElement element = ref.resolve(); + if (element != null && element instanceof PsiPackage) { + final PsiPackage aPackage = (PsiPackage) element; + final PsiClass[] classes = aPackage.getClasses(); + for (int j = 0; j < classes.length; j++) { + final PsiClass aClass = classes[j]; + final String className = aClass.getName(); + if (shortName.equals(className)) { + return true; + } + } + } + } + } + return false; + } + + private static boolean containsConflictingClassReference(String fqName, PsiJavaFile file) { + final int lastDotIndex = fqName.lastIndexOf((int) '.'); + final String shortName = fqName.substring(lastDotIndex + 1); + final PsiClass[] classes = file.getClasses(); + for (int i = 0; i < classes.length; i++) { + if (shortName.equals(classes[i].getName())) { + if (!fqName.equals(classes[i].getQualifiedName())) { + return true; + } + } + } + final ClassReferenceVisitor visitor = new ClassReferenceVisitor(shortName, fqName); + file.accept(visitor); + return visitor.isReferenceFound(); + } + + public static boolean importStatementMatches(PsiImportStatement importStatement, String name) { + final String qualifiedName = importStatement.getQualifiedName(); + + if (importStatement.isOnDemand()) { + final int lastDotIndex = name.lastIndexOf((int) '.'); + final String packageName = name.substring(0, lastDotIndex); + return packageName.equals(qualifiedName); + } else { + return name.equals(qualifiedName); + } + } + + private static class ClassReferenceVisitor extends PsiRecursiveElementVisitor { + private final String m_name; + private final String fullyQualifiedName; + private boolean m_referenceFound = false; + + private ClassReferenceVisitor(String className, String fullyQualifiedName) { + super(); + m_name = className; + this.fullyQualifiedName = fullyQualifiedName; + } + + 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 visitReferenceElement(PsiJavaCodeReferenceElement ref) { + final String text = ref.getText(); + if (text.indexOf((int) '.') >= 0) { + return; + } + final PsiElement element = ref.resolve(); + + if (element instanceof PsiClass && !(element instanceof PsiTypeParameter)) { + final PsiClass aClass = (PsiClass) element; + final String testClassName = aClass.getName(); + final String testClassQualifiedName = aClass.getQualifiedName(); + if (testClassQualifiedName != null && testClassName != null && !testClassQualifiedName.equals(fullyQualifiedName) && + testClassName.equals(m_name)) { + m_referenceFound = true; + } + } + } + + private boolean isReferenceFound() { + return m_referenceFound; + } + } +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/psiutils/InitializationReadUtils.java b/plugins/InspectionGadgets/src/com/siyeh/ig/psiutils/InitializationReadUtils.java new file mode 100644 index 000000000000..58c88e8628d9 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/psiutils/InitializationReadUtils.java @@ -0,0 +1,424 @@ +package com.siyeh.ig.psiutils; + +import com.intellij.psi.*; +import com.intellij.psi.util.PsiTreeUtil; +import com.intellij.psi.util.MethodSignature; +import com.intellij.psi.util.MethodSignatureUtil; + +import java.util.HashSet; +import java.util.Set; +import java.util.List; +import java.util.ArrayList; + +public class InitializationReadUtils { + + private final Set uninitializedReads; // Set to prevent duplicates + + public InitializationReadUtils() { + super(); + uninitializedReads = new HashSet(); + } + + public List getUninitializedReads() { + return new ArrayList(uninitializedReads); + } + + public boolean blockMustAssignVariable(PsiVariable field, + PsiCodeBlock block) { + return cachingBlockMustAssignVariable(field, block, new HashSet()); + } + + private boolean cachingBlockMustAssignVariable(PsiVariable field, PsiCodeBlock block, Set checkedMethods) { + if (block == null) { + return false; + } + + final PsiStatement[] statements = block.getStatements(); + for (int i = 0; i < statements.length; i++) { + final PsiStatement statement = statements[i]; + if (statementMustAssignVariable(field, statement, checkedMethods)) { + return true; + } + } + return false; + } + + private boolean statementMustAssignVariable(PsiVariable field, + PsiStatement statement, + Set checkedMethods) { + if (statement == null) { + return false; + } + if (statement instanceof PsiBreakStatement || + statement instanceof PsiContinueStatement || + statement instanceof PsiAssertStatement || + statement instanceof PsiEmptyStatement) { + return false; + } else if (statement instanceof PsiReturnStatement) { + final PsiReturnStatement returnStatement = (PsiReturnStatement) statement; + final PsiExpression returnValue = returnStatement.getReturnValue(); + return expressionMustAssignVariable(field, returnValue, checkedMethods); + } else if (statement instanceof PsiThrowStatement) { + final PsiThrowStatement throwStatement = (PsiThrowStatement) statement; + final PsiExpression exception = throwStatement.getException(); + return expressionMustAssignVariable(field, exception, checkedMethods); + } else if (statement instanceof PsiExpressionListStatement) { + final PsiExpressionListStatement list = (PsiExpressionListStatement) statement; + final PsiExpressionList expressionList = list.getExpressionList(); + final PsiExpression[] expressions = expressionList.getExpressions(); + for (int i = 0; i < expressions.length; i++) { + final PsiExpression expression = expressions[i]; + if (expressionMustAssignVariable(field, expression, checkedMethods)) { + return true; + } + } + return false; + } else if (statement instanceof PsiExpressionStatement) { + final PsiExpressionStatement expressionStatement = (PsiExpressionStatement) statement; + final PsiExpression expression = expressionStatement.getExpression(); + return expressionMustAssignVariable(field, expression, checkedMethods); + } else if (statement instanceof PsiDeclarationStatement) { + return declarationStatementMustAssignVariable(field, + (PsiDeclarationStatement) statement, + checkedMethods); + } else if (statement instanceof PsiForStatement) { + return forStatementMustAssignVariable(field, + (PsiForStatement) statement, + checkedMethods); + } else if (statement instanceof PsiForeachStatement) { + return foreachStatementMustAssignVariable(field, + (PsiForeachStatement) statement); + } else if (statement instanceof PsiWhileStatement) { + return whileStatementMustAssignVariable(field, + (PsiWhileStatement) statement, + checkedMethods); + } else if (statement instanceof PsiDoWhileStatement) { + return doWhileMustAssignVariable(field, + (PsiDoWhileStatement) statement, + checkedMethods); + } else if (statement instanceof PsiSynchronizedStatement) { + final PsiCodeBlock body = ((PsiSynchronizedStatement) statement).getBody(); + return cachingBlockMustAssignVariable(field, body, checkedMethods); + } else if (statement instanceof PsiBlockStatement) { + final PsiCodeBlock codeBlock = ((PsiBlockStatement) statement).getCodeBlock(); + return cachingBlockMustAssignVariable(field, codeBlock, checkedMethods); + } else if (statement instanceof PsiLabeledStatement) { + final PsiLabeledStatement labeledStatement = (PsiLabeledStatement) statement; + final PsiStatement statementLabeled = labeledStatement.getStatement(); + return statementMustAssignVariable(field, statementLabeled, checkedMethods); + } else if (statement instanceof PsiIfStatement) { + return ifStatementMustAssignVariable(field, + (PsiIfStatement) statement, + checkedMethods); + } else if (statement instanceof PsiTryStatement) { + return tryStatementMustAssignVariable(field, + (PsiTryStatement) statement, + checkedMethods); + } else if (statement instanceof PsiSwitchStatement) { + return false; + } else // unknown statement type + { + return false; + } + } + + private boolean declarationStatementMustAssignVariable(PsiVariable field, + PsiDeclarationStatement declarationStatement, + Set checkedMethods) { + final PsiElement[] elements = declarationStatement.getDeclaredElements(); + for (int i = 0; i < elements.length; i++) { + if (elements[i] instanceof PsiVariable) { + final PsiVariable variable = (PsiVariable) elements[i]; + final PsiExpression initializer = variable.getInitializer(); + if (expressionMustAssignVariable(field, initializer, checkedMethods)) { + return true; + } + } + } + return false; + } + + private boolean tryStatementMustAssignVariable(PsiVariable field, + PsiTryStatement tryStatement, + Set checkedMethods) { + final PsiCodeBlock[] catchBlocks = tryStatement.getCatchBlocks(); + if (catchBlocks == null || catchBlocks.length == 0) { + final PsiCodeBlock tryBlock = tryStatement.getTryBlock(); + if (cachingBlockMustAssignVariable(field, tryBlock, checkedMethods)) { + return true; + } + } + final PsiCodeBlock finallyBlock = tryStatement.getFinallyBlock(); + return cachingBlockMustAssignVariable(field, finallyBlock, checkedMethods); + } + + private boolean ifStatementMustAssignVariable(PsiVariable field, + PsiIfStatement ifStatement, + Set checkedMethods) { + final PsiExpression condition = ifStatement.getCondition(); + if (expressionMustAssignVariable(field, condition, checkedMethods)) { + return true; + } + final PsiStatement thenBranch = ifStatement.getThenBranch(); + final PsiStatement elseBranch = ifStatement.getElseBranch(); + return statementMustAssignVariable(field, thenBranch, checkedMethods) && + statementMustAssignVariable(field, elseBranch, checkedMethods); + } + + private boolean doWhileMustAssignVariable(PsiVariable field, + PsiDoWhileStatement doWhileStatement, + Set checkedMethods) { + final PsiExpression condition = doWhileStatement.getCondition(); + final PsiStatement body = doWhileStatement.getBody(); + return expressionMustAssignVariable(field, condition, checkedMethods) || + statementMustAssignVariable(field, body, checkedMethods); + } + + private boolean whileStatementMustAssignVariable(PsiVariable field, + PsiWhileStatement whileStatement, + Set checkedMethods) { + final PsiExpression condition = whileStatement.getCondition(); + if (expressionMustAssignVariable(field, condition, checkedMethods)) { + return true; + } + final PsiExpression test = condition; + if (BoolUtils.isTrue(test)) { + final PsiStatement body = whileStatement.getBody(); + if (statementMustAssignVariable(field, body, checkedMethods)) { + return true; + } + } + return false; + } + + private boolean forStatementMustAssignVariable(PsiVariable field, + PsiForStatement forStatement, + Set checkedMethods) { + final PsiStatement initialization = forStatement.getInitialization(); + if (statementMustAssignVariable(field, initialization, checkedMethods)) { + return true; + } + final PsiExpression test = forStatement.getCondition(); + if (expressionMustAssignVariable(field, test, checkedMethods)) { + return true; + } + if (BoolUtils.isTrue(test)) { + final PsiStatement body = forStatement.getBody(); + if (statementMustAssignVariable(field, body, checkedMethods)) { + return true; + } + final PsiStatement update = forStatement.getUpdate(); + if (statementMustAssignVariable(field, update, checkedMethods)) { + return true; + } + } + return false; + } + + private boolean foreachStatementMustAssignVariable(PsiVariable field, + PsiForeachStatement forStatement) { + return false; + } + + private boolean expressionMustAssignVariable(PsiVariable field, + PsiExpression expression, + Set checkedMethods) { + if (expression == null) { + return false; + } + if (expression instanceof PsiThisExpression || + expression instanceof PsiLiteralExpression || + expression instanceof PsiSuperExpression || + expression instanceof PsiClassObjectAccessExpression) { + return false; + } else if (expression instanceof PsiReferenceExpression) { + + final PsiReferenceExpression refExp = (PsiReferenceExpression) expression; + if (field.equals(refExp.resolve())) { + + if (refExp.getParent() instanceof PsiAssignmentExpression) { + final PsiAssignmentExpression pae = (PsiAssignmentExpression) refExp.getParent(); + if (pae.getRExpression() != null) { + if (pae.getRExpression().equals(refExp)) { + if (!refExp.isQualified() || refExp.getQualifierExpression() instanceof PsiThisExpression) { + uninitializedReads.add(expression); + } + } + } + } else { + if (!refExp.isQualified() || refExp.getQualifierExpression() instanceof PsiThisExpression) { + uninitializedReads.add(expression); + } + } + } + if (refExp.isQualified()) { + return expressionMustAssignVariable(field, refExp.getQualifierExpression(), checkedMethods); + } else { + return false; + } + } else if (expression instanceof PsiMethodCallExpression) { + final PsiMethod method = (PsiMethod) PsiTreeUtil.getParentOfType(expression, PsiMethod.class); + if (method != null) { + final PsiReferenceExpression methodExpression = ((PsiMethodCallExpression) expression).getMethodExpression(); + if (methodExpression != null) { + final PsiMethod calledMethod = (PsiMethod) methodExpression.resolve(); + if (method.equals(calledMethod)) { + // Skip recursive call to self that causes StackOverflowError. + return false; + } + } + } + return methodCallMustAssignVariable(expression, field, checkedMethods); + } else if (expression instanceof PsiNewExpression) { + return newExpressionMustAssignVariable(expression, field, checkedMethods); + } else if (expression instanceof PsiArrayInitializerExpression) { + final PsiArrayInitializerExpression array = + (PsiArrayInitializerExpression) expression; + final PsiExpression[] initializers = array.getInitializers(); + for (int i = 0; i < initializers.length; i++) { + final PsiExpression initializer = initializers[i]; + if (expressionMustAssignVariable(field, initializer, checkedMethods)) { + return true; + } + } + return false; + } else if (expression instanceof PsiTypeCastExpression) { + final PsiTypeCastExpression typeCast = (PsiTypeCastExpression) expression; + final PsiExpression operand = typeCast.getOperand(); + return expressionMustAssignVariable(field, operand, checkedMethods); + } else if (expression instanceof PsiArrayAccessExpression) { + final PsiArrayAccessExpression accessExpression = (PsiArrayAccessExpression) expression; + final PsiExpression arrayExpression = accessExpression.getArrayExpression(); + final PsiExpression indexExpression = accessExpression.getIndexExpression(); + return expressionMustAssignVariable(field, arrayExpression, checkedMethods) || + expressionMustAssignVariable(field, indexExpression, checkedMethods); + } else if (expression instanceof PsiPrefixExpression) { + final PsiPrefixExpression prefixExpression = (PsiPrefixExpression) expression; + final PsiExpression operand = prefixExpression.getOperand(); + return expressionMustAssignVariable(field, operand, checkedMethods); + } else if (expression instanceof PsiPostfixExpression) { + final PsiPostfixExpression postfixExpression = (PsiPostfixExpression) expression; + final PsiExpression operand = postfixExpression.getOperand(); + return expressionMustAssignVariable(field, operand, checkedMethods); + } else if (expression instanceof PsiBinaryExpression) { + final PsiBinaryExpression binaryExpression = (PsiBinaryExpression) expression; + final PsiExpression lhs = binaryExpression.getLOperand(); + final PsiExpression rhs = binaryExpression.getROperand(); + return expressionMustAssignVariable(field, lhs, checkedMethods) || + expressionMustAssignVariable(field, rhs, checkedMethods); + } else if (expression instanceof PsiConditionalExpression) { + final PsiConditionalExpression conditional = (PsiConditionalExpression) expression; + final PsiExpression condition = conditional.getCondition(); + if (expressionMustAssignVariable(field, condition, checkedMethods)) { + return true; + } + final PsiExpression thenExpression = conditional.getThenExpression(); + final PsiExpression elseExpression = conditional.getElseExpression(); + return expressionMustAssignVariable(field, thenExpression, checkedMethods) && + expressionMustAssignVariable(field, elseExpression, checkedMethods); + } else if (expression instanceof PsiAssignmentExpression) { + final PsiAssignmentExpression assignment = (PsiAssignmentExpression) expression; + final PsiExpression lhs = assignment.getLExpression(); + if (expressionMustAssignVariable(field, lhs, checkedMethods)) { + return true; + } + final PsiExpression rhs = assignment.getRExpression(); + if (expressionMustAssignVariable(field, rhs, checkedMethods)) { + return true; + } + if (lhs instanceof PsiReferenceExpression) { + final PsiElement element = ((PsiReferenceExpression) lhs).resolve(); + if (element != null && + field != null && + element.equals(field)) { + return true; + } + } + return false; + } else { + return false; + } + } + + private boolean newExpressionMustAssignVariable(PsiExpression expression, + PsiVariable field, + Set checkedMethods) { + final PsiNewExpression callExpression = + (PsiNewExpression) expression; + final PsiExpressionList argumentList = callExpression.getArgumentList(); + if (argumentList != null) { + final PsiExpression[] args = argumentList.getExpressions(); + for (int i = 0; i < args.length; i++) { + final PsiExpression arg = args[i]; + if (expressionMustAssignVariable(field, arg, checkedMethods)) { + return true; + } + } + } + final PsiArrayInitializerExpression arrayInitializer = callExpression.getArrayInitializer(); + if (expressionMustAssignVariable(field, arrayInitializer, checkedMethods)) { + return true; + } + final PsiExpression[] arrayDimensions = callExpression.getArrayDimensions(); + if (arrayDimensions != null) { + for (int i = 0; i < arrayDimensions.length; i++) { + final PsiExpression dim = arrayDimensions[i]; + if (expressionMustAssignVariable(field, dim, checkedMethods)) { + return true; + } + } + } + return false; + } + + private boolean methodCallMustAssignVariable(PsiExpression expression, + PsiVariable field, Set checkedMethods) { + final PsiMethodCallExpression callExpression = (PsiMethodCallExpression) expression; + + final PsiExpressionList argList = callExpression.getArgumentList(); + final PsiExpression[] args = argList.getExpressions(); + for (int i = 0; i < args.length; i++) { + final PsiExpression arg = args[i]; + if (expressionMustAssignVariable(field, arg, checkedMethods)) { + return true; + } + } + final PsiReferenceExpression methodExpression = callExpression.getMethodExpression(); + if (expressionMustAssignVariable(field, methodExpression, checkedMethods)) { + return true; + } + final PsiMethod method = callExpression.resolveMethod(); + if (method == null) { + return false; + } + final MethodSignature methodSignature = + MethodSignatureUtil.createMethodSignature(method.getName(), + method.getParameterList(), + method.getTypeParameterList(), + EmptySubstitutor.getInstance()); + if (!checkedMethods.add(methodSignature)) { + return false; + } + + final PsiClass containingClass = + ClassUtils.getContainingClass(expression); + final PsiClass calledClass = method.getContainingClass(); + + // Can remark out this block to continue chase outside of of current class + + if (!calledClass.equals(containingClass)) { + return false; + } + + if (method.hasModifierProperty(PsiModifier.STATIC) + || method.isConstructor() + || method.hasModifierProperty(PsiModifier.PRIVATE) + || method.hasModifierProperty(PsiModifier.FINAL) + || calledClass.hasModifierProperty(PsiModifier.FINAL)) { + final PsiCodeBlock body = method.getBody(); + return cachingBlockMustAssignVariable(field, body, checkedMethods); + } + return false; + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/psiutils/InitializationUtils.java b/plugins/InspectionGadgets/src/com/siyeh/ig/psiutils/InitializationUtils.java new file mode 100644 index 000000000000..97da3070e5a3 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/psiutils/InitializationUtils.java @@ -0,0 +1,338 @@ +package com.siyeh.ig.psiutils; + +import com.intellij.psi.*; +import com.intellij.psi.util.MethodSignature; +import com.intellij.psi.util.MethodSignatureUtil; + +import java.util.HashSet; +import java.util.Set; + +public class InitializationUtils { + private InitializationUtils() { + super(); + } + + public static boolean blockMustAssignVariable(PsiVariable field, PsiCodeBlock block) { + return cachingblockMustAssignVariable(field, block, new HashSet()); + } + + private static boolean cachingblockMustAssignVariable(PsiVariable field, PsiCodeBlock block, Set checkedMethods) { + if (block == null) { + return false; + } + final PsiStatement[] statements = block.getStatements(); + for (int i = 0; i < statements.length; i++) { + final PsiStatement statement = statements[i]; + if (statementMustAssignVariable(field, statement, checkedMethods)) { + return true; + } + } + return false; + } + + private static boolean statementMustAssignVariable(PsiVariable field, PsiStatement statement, Set checkedMethods) { + if (statement == null) { + return false; + } + if (statement instanceof PsiBreakStatement || + statement instanceof PsiContinueStatement || + statement instanceof PsiAssertStatement || + statement instanceof PsiEmptyStatement) { + return false; + } else if (statement instanceof PsiReturnStatement) { + final PsiReturnStatement returnStatement = (PsiReturnStatement) statement; + final PsiExpression returnValue = returnStatement.getReturnValue(); + return expressionMustAssignVariable(field, returnValue, checkedMethods); + } else if (statement instanceof PsiThrowStatement) { + final PsiThrowStatement throwStatement = (PsiThrowStatement) statement; + final PsiExpression exception = throwStatement.getException(); + return expressionMustAssignVariable(field, exception, checkedMethods); + } else if (statement instanceof PsiExpressionListStatement) { + final PsiExpressionListStatement list = (PsiExpressionListStatement) statement; + final PsiExpressionList expressionList = list.getExpressionList(); + final PsiExpression[] expressions = expressionList.getExpressions(); + for (int i = 0; i < expressions.length; i++) { + final PsiExpression expression = expressions[i]; + if (expressionMustAssignVariable(field, expression, checkedMethods)) { + return true; + } + } + return false; + } else if (statement instanceof PsiExpressionStatement) { + final PsiExpressionStatement expressionStatement = (PsiExpressionStatement) statement; + final PsiExpression expression = expressionStatement.getExpression(); + return expressionMustAssignVariable(field, expression, checkedMethods); + } else if (statement instanceof PsiDeclarationStatement) { + return declarationStatementMustAssignVariable(field, (PsiDeclarationStatement) statement, checkedMethods); + } else if (statement instanceof PsiForStatement) { + return forStatementMustAssignVariable(field, (PsiForStatement) statement, checkedMethods); + } else if (statement instanceof PsiForeachStatement) { + return foreachStatementMustAssignVariable(field, (PsiForeachStatement) statement); + } else if (statement instanceof PsiWhileStatement) { + return whileStatementMustAssignVariable(field, (PsiWhileStatement) statement, checkedMethods); + } else if (statement instanceof PsiDoWhileStatement) { + return doWhileMustAssignVariable(field, (PsiDoWhileStatement) statement, checkedMethods); + } else if (statement instanceof PsiSynchronizedStatement) { + final PsiCodeBlock body = ((PsiSynchronizedStatement) statement).getBody(); + return cachingblockMustAssignVariable(field, body, checkedMethods); + } else if (statement instanceof PsiBlockStatement) { + final PsiCodeBlock codeBlock = ((PsiBlockStatement) statement).getCodeBlock(); + return cachingblockMustAssignVariable(field, codeBlock, checkedMethods); + } else if (statement instanceof PsiLabeledStatement) { + final PsiLabeledStatement labeledStatement = (PsiLabeledStatement) statement; + final PsiStatement statementLabeled = labeledStatement.getStatement(); + return statementMustAssignVariable(field, statementLabeled, checkedMethods); + } else if (statement instanceof PsiIfStatement) { + return ifStatementMustAssignVariable(field, (PsiIfStatement) statement, checkedMethods); + } else if (statement instanceof PsiTryStatement) { + return tryStatementMustAssignVariable(field, (PsiTryStatement) statement, checkedMethods); + } else if (statement instanceof PsiSwitchStatement) { + return false; + } else // unknown statement type + { + return false; + } + } + + private static boolean declarationStatementMustAssignVariable(PsiVariable field, + PsiDeclarationStatement declarationStatement, + Set checkedMethods) { + final PsiElement[] elements = declarationStatement.getDeclaredElements(); + for (int i = 0; i < elements.length; i++) { + final PsiVariable variable = (PsiVariable) elements[i]; + final PsiExpression initializer = variable.getInitializer(); + if (expressionMustAssignVariable(field, initializer, checkedMethods)) { + return true; + } + } + return false; + } + + private static boolean tryStatementMustAssignVariable(PsiVariable field, PsiTryStatement tryStatement, Set checkedMethods) { + final PsiCodeBlock[] catchBlocks = tryStatement.getCatchBlocks(); + if (catchBlocks == null || catchBlocks.length == 0) { + final PsiCodeBlock tryBlock = tryStatement.getTryBlock(); + if (cachingblockMustAssignVariable(field, tryBlock, checkedMethods)) { + return true; + } + } + final PsiCodeBlock finallyBlock = tryStatement.getFinallyBlock(); + return cachingblockMustAssignVariable(field, finallyBlock, checkedMethods); + } + + private static boolean ifStatementMustAssignVariable(PsiVariable field, PsiIfStatement ifStatement, Set checkedMethods) { + final PsiExpression condition = ifStatement.getCondition(); + if (expressionMustAssignVariable(field, condition, checkedMethods)) { + return true; + } + final PsiStatement thenBranch = ifStatement.getThenBranch(); + final PsiStatement elseBranch = ifStatement.getElseBranch(); + return statementMustAssignVariable(field, thenBranch, checkedMethods) && + statementMustAssignVariable(field, elseBranch, checkedMethods); + } + + private static boolean doWhileMustAssignVariable(PsiVariable field, PsiDoWhileStatement doWhileStatement, Set checkedMethods) { + final PsiExpression condition = doWhileStatement.getCondition(); + final PsiStatement body = doWhileStatement.getBody(); + return expressionMustAssignVariable(field, condition, checkedMethods) || + statementMustAssignVariable(field, body, checkedMethods); + } + + private static boolean whileStatementMustAssignVariable(PsiVariable field, PsiWhileStatement whileStatement, Set checkedMethods) { + final PsiExpression condition = whileStatement.getCondition(); + if (expressionMustAssignVariable(field, condition, checkedMethods)) { + return true; + } + final PsiExpression test = condition; + if (BoolUtils.isTrue(test)) { + final PsiStatement body = whileStatement.getBody(); + if (statementMustAssignVariable(field, body, checkedMethods)) { + return true; + } + } + return false; + } + + private static boolean forStatementMustAssignVariable(PsiVariable field, PsiForStatement forStatement, Set checkedMethods) { + final PsiStatement initialization = forStatement.getInitialization(); + if (statementMustAssignVariable(field, initialization, checkedMethods)) { + return true; + } + final PsiExpression test = forStatement.getCondition(); + if (expressionMustAssignVariable(field, test, checkedMethods)) { + return true; + } + if (BoolUtils.isTrue(test)) { + final PsiStatement body = forStatement.getBody(); + if (statementMustAssignVariable(field, body, checkedMethods)) { + return true; + } + final PsiStatement update = forStatement.getUpdate(); + if (statementMustAssignVariable(field, update, checkedMethods)) { + return true; + } + } + return false; + } + + private static boolean foreachStatementMustAssignVariable(PsiVariable field, PsiForeachStatement forStatement) { + return false; + } + + private static boolean expressionMustAssignVariable(PsiVariable field, PsiExpression expression, Set checkedMethods) { + if (expression == null) { + return false; + } + if (expression instanceof PsiThisExpression || + expression instanceof PsiLiteralExpression || + expression instanceof PsiSuperExpression || + expression instanceof PsiClassObjectAccessExpression) { + return false; + } else if (expression instanceof PsiReferenceExpression) { + return false; + } else if (expression instanceof PsiMethodCallExpression) { + return methodCallMustAssignVariable(expression, field, checkedMethods); + } else if (expression instanceof PsiNewExpression) { + return newExpressionMustAssignVariable(expression, field, checkedMethods); + } else if (expression instanceof PsiArrayInitializerExpression) { + final PsiArrayInitializerExpression array = + (PsiArrayInitializerExpression) expression; + final PsiExpression[] initializers = array.getInitializers(); + for (int i = 0; i < initializers.length; i++) { + final PsiExpression initializer = initializers[i]; + if (expressionMustAssignVariable(field, initializer, checkedMethods)) { + return true; + } + } + return false; + } else if (expression instanceof PsiTypeCastExpression) { + final PsiTypeCastExpression typeCast = (PsiTypeCastExpression) expression; + final PsiExpression operand = typeCast.getOperand(); + return expressionMustAssignVariable(field, operand, checkedMethods); + } else if (expression instanceof PsiArrayAccessExpression) { + final PsiArrayAccessExpression accessExpression = (PsiArrayAccessExpression) expression; + final PsiExpression arrayExpression = accessExpression.getArrayExpression(); + final PsiExpression indexExpression = accessExpression.getIndexExpression(); + return expressionMustAssignVariable(field, arrayExpression, checkedMethods) || + expressionMustAssignVariable(field, indexExpression, checkedMethods); + } else if (expression instanceof PsiPrefixExpression) { + final PsiPrefixExpression prefixExpression = (PsiPrefixExpression) expression; + final PsiExpression operand = prefixExpression.getOperand(); + return expressionMustAssignVariable(field, operand, checkedMethods); + } else if (expression instanceof PsiPostfixExpression) { + final PsiPostfixExpression postfixExpression = (PsiPostfixExpression) expression; + final PsiExpression operand = postfixExpression.getOperand(); + return expressionMustAssignVariable(field, operand, checkedMethods); + } else if (expression instanceof PsiBinaryExpression) { + final PsiBinaryExpression binaryExpression = (PsiBinaryExpression) expression; + final PsiExpression lhs = binaryExpression.getLOperand(); + final PsiExpression rhs = binaryExpression.getROperand(); + return expressionMustAssignVariable(field, lhs, checkedMethods) || + expressionMustAssignVariable(field, rhs, checkedMethods); + } else if (expression instanceof PsiConditionalExpression) { + final PsiConditionalExpression conditional = (PsiConditionalExpression) expression; + final PsiExpression condition = conditional.getCondition(); + if (expressionMustAssignVariable(field, condition, checkedMethods)) { + return true; + } + final PsiExpression thenExpression = conditional.getThenExpression(); + final PsiExpression elseExpression = conditional.getElseExpression(); + return expressionMustAssignVariable(field, thenExpression, checkedMethods) && + expressionMustAssignVariable(field, elseExpression, checkedMethods); + } else if (expression instanceof PsiAssignmentExpression) { + final PsiAssignmentExpression assignment = (PsiAssignmentExpression) expression; + final PsiExpression lhs = assignment.getLExpression(); + if (expressionMustAssignVariable(field, lhs, checkedMethods)) { + return true; + } + final PsiExpression rhs = assignment.getRExpression(); + if (expressionMustAssignVariable(field, rhs, checkedMethods)) { + return true; + } + if (lhs instanceof PsiReferenceExpression) { + final PsiElement element = ((PsiReferenceExpression) lhs).resolve(); + if (element != null && + field != null && + element.equals(field)) { + return true; + } + } + return false; + } else { + return false; + } + } + + private static boolean newExpressionMustAssignVariable(PsiExpression expression, PsiVariable field, Set checkedMethods) { + final PsiNewExpression callExpression = + (PsiNewExpression) expression; + final PsiExpressionList argumentList = callExpression.getArgumentList(); + if (argumentList != null) { + final PsiExpression[] args = argumentList.getExpressions(); + for (int i = 0; i < args.length; i++) { + final PsiExpression arg = args[i]; + if (expressionMustAssignVariable(field, arg, checkedMethods)) { + return true; + } + } + } + final PsiArrayInitializerExpression arrayInitializer = callExpression.getArrayInitializer(); + if (expressionMustAssignVariable(field, arrayInitializer, checkedMethods)) { + return true; + } + final PsiExpression[] arrayDimensions = callExpression.getArrayDimensions(); + if (arrayDimensions != null) { + for (int i = 0; i < arrayDimensions.length; i++) { + final PsiExpression dim = arrayDimensions[i]; + if (expressionMustAssignVariable(field, dim, checkedMethods)) { + return true; + } + } + } + return false; + } + + private static boolean methodCallMustAssignVariable(PsiExpression expression, PsiVariable field, Set checkedMethods) { + final PsiMethodCallExpression callExpression = + (PsiMethodCallExpression) expression; + final PsiExpressionList argList = callExpression.getArgumentList(); + final PsiExpression[] args = argList.getExpressions(); + for (int i = 0; i < args.length; i++) { + final PsiExpression arg = args[i]; + if (expressionMustAssignVariable(field, arg, checkedMethods)) { + return true; + } + } + final PsiReferenceExpression methodExpression = callExpression.getMethodExpression(); + if (expressionMustAssignVariable(field, methodExpression, checkedMethods)) { + return true; + } + final PsiMethod method = callExpression.resolveMethod(); + if (method == null) { + return false; + } + final MethodSignature methodSignature = + MethodSignatureUtil.createMethodSignature(method.getName(), + method.getParameterList(), + method.getTypeParameterList(), + EmptySubstitutor.getInstance()); + if (!checkedMethods.add(methodSignature)) { + return false; + } + final PsiClass containingClass = + ClassUtils.getContainingClass(expression); + final PsiClass calledClass = method.getContainingClass(); + if (!calledClass.equals(containingClass)) { + return false; + } + if (method.hasModifierProperty(PsiModifier.STATIC) + || method.isConstructor() + || method.hasModifierProperty(PsiModifier.PRIVATE) + || method.hasModifierProperty(PsiModifier.FINAL) + || calledClass.hasModifierProperty(PsiModifier.FINAL)) { + final PsiCodeBlock body = method.getBody(); + return cachingblockMustAssignVariable(field, body, checkedMethods); + } + return false; + } +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/psiutils/LibraryUtil.java b/plugins/InspectionGadgets/src/com/siyeh/ig/psiutils/LibraryUtil.java new file mode 100644 index 000000000000..89db0968b41a --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/psiutils/LibraryUtil.java @@ -0,0 +1,17 @@ +package com.siyeh.ig.psiutils; + +import com.intellij.psi.PsiClass; +import com.intellij.psi.PsiFile; + +public class LibraryUtil { + private LibraryUtil() { + super(); + } + + public static boolean classIsInLibrary(PsiClass aClass) { + final PsiFile file = aClass.getContainingFile(); + final String fileName = file.getName(); + return !fileName.endsWith(".java"); + } +} + diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/psiutils/MethodCallUtils.java b/plugins/InspectionGadgets/src/com/siyeh/ig/psiutils/MethodCallUtils.java new file mode 100644 index 000000000000..b5b36f6e8d2b --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/psiutils/MethodCallUtils.java @@ -0,0 +1,33 @@ +package com.siyeh.ig.psiutils; + +import com.intellij.psi.PsiExpression; +import com.intellij.psi.PsiMethodCallExpression; +import com.intellij.psi.PsiReferenceExpression; +import com.intellij.psi.PsiType; + +public class MethodCallUtils { + private MethodCallUtils() { + super(); + + } + + public static String getMethodName(PsiMethodCallExpression expression) { + final PsiReferenceExpression method = expression.getMethodExpression(); + if (method == null) { + return null; + } + return method.getReferenceName(); + } + + public static PsiType getTargetType(PsiMethodCallExpression expression) { + final PsiReferenceExpression method = expression.getMethodExpression(); + if (method == null) { + return null; + } + final PsiExpression qualifierExpression = method.getQualifierExpression(); + if (qualifierExpression == null) { + return null; + } + return qualifierExpression.getType(); + } +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/psiutils/ParenthesesUtils.java b/plugins/InspectionGadgets/src/com/siyeh/ig/psiutils/ParenthesesUtils.java new file mode 100644 index 000000000000..fcd94db947ad --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/psiutils/ParenthesesUtils.java @@ -0,0 +1,369 @@ +package com.siyeh.ig.psiutils; + +import com.intellij.psi.*; +import com.intellij.psi.tree.IElementType; + +import java.util.HashMap; +import java.util.Map; + +public class ParenthesesUtils { + private ParenthesesUtils() { + super(); + + } + + private static final int PARENTHESIZED_PRECEDENCE = 0; + private static final int LITERAL_PRECEDENCE = 0; + public static final int METHOD_CALL_PRECEDENCE = 1; + + private static final int POSTFIX_PRECEDENCE = 2; + public static final int PREFIX_PRECEDENCE = 3; + public static final int TYPE_CAST_PRECEDENCE = 4; + private static final int MULTIPLICATIVE_PRECEDENCE = 5; + private static final int ADDITIVE_PRECEDENCE = 6; + private static final int SHIFT_PRECEDENCE = 7; + private static final int RELATIONAL_PRECEDENCE = 8; + private static final int EQUALITY_PRECEDENCE = 9; + + private static final int BINARY_AND_PRECEDENCE = 10; + private static final int BINARY_XOR_PRECEDENCE = 11; + private static final int BINARY_OR_PRECEDENCE = 12; + private static final int AND_PRECEDENCE = 13; + private static final int OR_PRECEDENCE = 14; + private static final int CONDITIONAL_PRECEDENCE = 15; + private static final int ASSIGNMENT_PRECEDENCE = 16; + + private static final int NUM_PRECEDENCES = 17; + + private static final Map s_binaryOperatorPrecedence = new HashMap(NUM_PRECEDENCES); + + static { + s_binaryOperatorPrecedence.put("+", new Integer(ADDITIVE_PRECEDENCE)); + s_binaryOperatorPrecedence.put("-", new Integer(ADDITIVE_PRECEDENCE)); + s_binaryOperatorPrecedence.put("*", new Integer(MULTIPLICATIVE_PRECEDENCE)); + s_binaryOperatorPrecedence.put("/", new Integer(MULTIPLICATIVE_PRECEDENCE)); + s_binaryOperatorPrecedence.put("%", new Integer(MULTIPLICATIVE_PRECEDENCE)); + s_binaryOperatorPrecedence.put("&&", new Integer(AND_PRECEDENCE)); + s_binaryOperatorPrecedence.put("||", new Integer(OR_PRECEDENCE)); + s_binaryOperatorPrecedence.put("&", new Integer(BINARY_AND_PRECEDENCE)); + s_binaryOperatorPrecedence.put("|", new Integer(BINARY_OR_PRECEDENCE)); + s_binaryOperatorPrecedence.put("^", new Integer(BINARY_XOR_PRECEDENCE)); + s_binaryOperatorPrecedence.put("<<", new Integer(SHIFT_PRECEDENCE)); + s_binaryOperatorPrecedence.put(">>", new Integer(SHIFT_PRECEDENCE)); + s_binaryOperatorPrecedence.put(">>>", new Integer(SHIFT_PRECEDENCE)); + s_binaryOperatorPrecedence.put(">", new Integer(RELATIONAL_PRECEDENCE)); + s_binaryOperatorPrecedence.put(">=", new Integer(RELATIONAL_PRECEDENCE)); + s_binaryOperatorPrecedence.put("<", new Integer(RELATIONAL_PRECEDENCE)); + s_binaryOperatorPrecedence.put("<=", new Integer(RELATIONAL_PRECEDENCE)); + s_binaryOperatorPrecedence.put("==", new Integer(EQUALITY_PRECEDENCE)); + s_binaryOperatorPrecedence.put("!=", new Integer(EQUALITY_PRECEDENCE)); + } + + public static PsiExpression stripParentheses(PsiExpression exp) { + PsiExpression parenthesized = exp; + while (parenthesized instanceof PsiParenthesizedExpression) { + parenthesized = ((PsiParenthesizedExpression) parenthesized).getExpression(); + } + return parenthesized; + } + + public static int getPrecendence(PsiExpression exp) { + if (exp instanceof PsiThisExpression || + exp instanceof PsiLiteralExpression || + exp instanceof PsiSuperExpression || + exp instanceof PsiReferenceExpression || + exp instanceof PsiClassObjectAccessExpression || + exp instanceof PsiArrayAccessExpression || + exp instanceof PsiArrayInitializerExpression) { + return LITERAL_PRECEDENCE; + } + if (exp instanceof PsiMethodCallExpression) { + return METHOD_CALL_PRECEDENCE; + } + if (exp instanceof PsiTypeCastExpression || + exp instanceof PsiNewExpression) { + return TYPE_CAST_PRECEDENCE; + } + if (exp instanceof PsiPrefixExpression) { + return PREFIX_PRECEDENCE; + } + if (exp instanceof PsiPostfixExpression) { + return POSTFIX_PRECEDENCE; + } + if (exp instanceof PsiBinaryExpression) { + final PsiJavaToken sign = ((PsiBinaryExpression) exp).getOperationSign(); + return precedenceForBinaryOperator(sign); + } + if (exp instanceof PsiInstanceOfExpression) { + return RELATIONAL_PRECEDENCE; + } + if (exp instanceof PsiConditionalExpression) { + return CONDITIONAL_PRECEDENCE; + } + if (exp instanceof PsiAssignmentExpression) { + return ASSIGNMENT_PRECEDENCE; + } + if (exp instanceof PsiParenthesizedExpression) { + return PARENTHESIZED_PRECEDENCE; + } + return -1; + } + + private static int precedenceForBinaryOperator(PsiJavaToken sign) { + final String operator = sign.getText(); + final Integer precedence = (Integer) s_binaryOperatorPrecedence.get(operator); + return precedence.intValue(); + } + + public static String removeParentheses(PsiExpression exp) { + if (exp instanceof PsiMethodCallExpression) { + return removeParensFromMethodCallExpression((PsiMethodCallExpression) exp); + } + if (exp instanceof PsiNewExpression) { + return removeParensFromNewExpression((PsiNewExpression) exp); + } + if (exp instanceof PsiAssignmentExpression) { + return removeParensFromAssignmentExpression((PsiAssignmentExpression) exp); + } + if (exp instanceof PsiArrayInitializerExpression) { + return removeParensFromArrayInitializerExpression((PsiArrayInitializerExpression) exp); + } + if (exp instanceof PsiTypeCastExpression) { + return removeParensFromTypeCastExpression((PsiTypeCastExpression) exp); + } + if (exp instanceof PsiArrayAccessExpression) { + return removeParensFromArrayAccessExpression((PsiArrayAccessExpression) exp); + } + if (exp instanceof PsiPrefixExpression) { + return removeParensFromPrefixExpression((PsiPrefixExpression) exp); + } + if (exp instanceof PsiPostfixExpression) { + return removeParensFromPostfixExpression((PsiPostfixExpression) exp); + } + if (exp instanceof PsiBinaryExpression) { + return removeParensFromBinaryExpression((PsiBinaryExpression) exp); + } + if (exp instanceof PsiInstanceOfExpression) { + return removeParensFromInstanceOfExpression((PsiInstanceOfExpression) exp); + } + if (exp instanceof PsiConditionalExpression) { + return removeParensFromConditionalExpression((PsiConditionalExpression) exp); + } + if (exp instanceof PsiParenthesizedExpression) { + return removeParensFromParenthesizedExpression((PsiParenthesizedExpression) exp); + } + + return exp.getText(); + } + + private static String removeParensFromParenthesizedExpression(PsiParenthesizedExpression parenthesizedExp) { + PsiExpression body = parenthesizedExp.getExpression(); + while (body instanceof PsiParenthesizedExpression) { + body = ((PsiParenthesizedExpression) body).getExpression(); + } + if (!(parenthesizedExp.getParent() instanceof PsiExpression)) { + return removeParentheses(body); + } + final PsiExpression parentExp = (PsiExpression) parenthesizedExp.getParent(); + final int parentPrecedence = getPrecendence(parentExp); + final int childPrecedence = getPrecendence(body); + if (parentPrecedence < childPrecedence) { + return '(' + removeParentheses(body) + ')'; + } else if (parentPrecedence == childPrecedence) { + if (parentExp instanceof PsiBinaryExpression && + body instanceof PsiBinaryExpression) { + final IElementType parentOperator = + ((PsiBinaryExpression) parentExp).getOperationSign().getTokenType(); + final IElementType bodyOperator = + ((PsiBinaryExpression) body).getOperationSign().getTokenType(); + + final PsiExpression lhs = ((PsiBinaryExpression) parentExp).getLOperand(); + + if (lhs.equals(parenthesizedExp) && parentOperator.equals(bodyOperator)) { + return removeParentheses(body); + } else { + return '(' + removeParentheses(body) + ')'; + } + } else { + return removeParentheses(body); + } + } else { + return removeParentheses(body); + } + } + + private static String removeParensFromConditionalExpression(PsiConditionalExpression conditionalExp) { + final PsiExpression condition = conditionalExp.getCondition(); + final PsiExpression thenBranch = conditionalExp.getThenExpression(); + final PsiExpression elseBranch = conditionalExp.getElseExpression(); + return removeParentheses(condition) + '?' + + removeParentheses(thenBranch) + ':' + + removeParentheses(elseBranch); + } + + private static String removeParensFromInstanceOfExpression(PsiInstanceOfExpression instanceofExp) { + final PsiExpression body = instanceofExp.getOperand(); + final PsiTypeElement type = instanceofExp.getCheckType(); + return removeParentheses(body) + " instanceof " + type.getText(); + } + + private static String removeParensFromBinaryExpression(PsiBinaryExpression binaryExp) { + final PsiExpression lhs = binaryExp.getLOperand(); + final PsiExpression rhs = binaryExp.getROperand(); + final PsiJavaToken sign = binaryExp.getOperationSign(); + return removeParentheses(lhs) + sign.getText() + removeParentheses(rhs); + } + + private static String removeParensFromPostfixExpression(PsiPostfixExpression postfixExp) { + final PsiExpression body = postfixExp.getOperand(); + final PsiJavaToken sign = postfixExp.getOperationSign(); + final String operand = sign.getText(); + return removeParentheses(body) + operand; + } + + private static String removeParensFromPrefixExpression(PsiPrefixExpression prefixExp) { + final PsiExpression body = prefixExp.getOperand(); + final PsiJavaToken sign = prefixExp.getOperationSign(); + final String operand = sign.getText(); + return operand + removeParentheses(body); + } + + private static String removeParensFromArrayAccessExpression(PsiArrayAccessExpression arrayAccessExp) { + final PsiExpression arrayExp = arrayAccessExp.getArrayExpression(); + final PsiExpression indexExp = arrayAccessExp.getIndexExpression(); + return removeParentheses(arrayExp) + '[' + removeParentheses(indexExp) + ']'; + } + + private static String removeParensFromTypeCastExpression(PsiTypeCastExpression typeCast) { + final PsiExpression body = typeCast.getOperand(); + final PsiTypeElement type = typeCast.getCastType(); + return '(' + type.getText() + ')' + removeParentheses(body); + } + + private static String removeParensFromArrayInitializerExpression(PsiArrayInitializerExpression init) { + final PsiExpression[] contents = init.getInitializers(); + final String text = init.getText(); + final int textLength = text.length(); + final StringBuffer out = new StringBuffer(textLength); + out.append('{'); + for (int i = 0; i < contents.length; i++) { + final PsiExpression arg = contents[i]; + if (i != 0) { + out.append(','); + } + final String strippedArg = removeParentheses(arg); + out.append(strippedArg); + } + out.append('}'); + return out.toString(); + } + + private static String removeParensFromAssignmentExpression(PsiAssignmentExpression assignment) { + final PsiExpression lhs = assignment.getLExpression(); + final PsiExpression rhs = assignment.getRExpression(); + final PsiJavaToken sign = assignment.getOperationSign(); + return removeParentheses(lhs) + sign.getText() + + removeParentheses(rhs); + } + + private static String removeParensFromNewExpression(PsiNewExpression newExp) { + final PsiExpression[] dimensions = newExp.getArrayDimensions(); + String[] strippedDimensions = null; + if (dimensions != null) { + strippedDimensions = new String[dimensions.length]; + for (int i = 0; i < dimensions.length; i++) { + strippedDimensions[i] = removeParentheses(dimensions[i]); + } + } + + final PsiExpression qualifier = newExp.getQualifier(); + final PsiExpression arrayInitializer = newExp.getArrayInitializer(); + String strippedInitializer = null; + if (arrayInitializer != null) { + strippedInitializer = removeParentheses(arrayInitializer); + } + + final PsiExpressionList argumentList = newExp.getArgumentList(); + String[] strippedArgs = null; + if (argumentList != null) { + final PsiExpression[] args = argumentList.getExpressions(); + if (args != null) { + strippedArgs = new String[args.length]; + for (int i = 0; i < args.length; i++) { + strippedArgs[i] = removeParentheses(args[i]); + } + } + } + final String expressionText = newExp.getText(); + if (qualifier != null) { + return expressionText; + } + final PsiElement[] children = newExp.getChildren(); + for (int i = 0; i < children.length; i++) { + final PsiElement child = children[i]; + if (child instanceof PsiAnonymousClass) { + return expressionText; + } + } + final int length = expressionText.length(); + final StringBuffer out = new StringBuffer(length); + out.append("new "); + final PsiType type = newExp.getType(); + final PsiType deepType = type.getDeepComponentType(); + final String text = deepType.getPresentableText(); + out.append(text); + if (strippedArgs != null) { + out.append('('); + for (int i = 0; i < strippedArgs.length; i++) { + if (i != 0) { + out.append(','); + } + out.append(strippedArgs[i]); + } + out.append(')'); + } + + if (strippedDimensions != null) { + if (strippedDimensions.length > 0) { + for (int i = 0; i < strippedDimensions.length; i++) { + out.append('['); + out.append(strippedDimensions[i]); + out.append(']'); + } + } else { + final int dimensionCount = type.getArrayDimensions(); + for (int i = 0; i < dimensionCount; i++) { + out.append("[]"); + } + } + } + if (strippedInitializer != null) { + out.append(strippedInitializer); + } + return out.toString(); + } + + private static String removeParensFromMethodCallExpression(PsiMethodCallExpression methCall) { + final PsiReferenceExpression target = methCall.getMethodExpression(); + final PsiExpressionList argumentList = methCall.getArgumentList(); + final PsiExpression[] args = argumentList.getExpressions(); + + final String methodCallText = methCall.getText(); + final int length = methodCallText.length(); + final StringBuffer out = new StringBuffer(length); + final String strippedTarget = removeParentheses(target); + out.append(strippedTarget); + out.append('('); + for (int i = 0; i < args.length; i++) { + final PsiExpression arg = args[i]; + if (i != 0) { + out.append(','); + } + final String strippedArg = removeParentheses(arg); + out.append(strippedArg); + } + out.append(')'); + return out.toString(); + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/psiutils/RecursionUtils.java b/plugins/InspectionGadgets/src/com/siyeh/ig/psiutils/RecursionUtils.java new file mode 100644 index 000000000000..a5a46f5cf9a3 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/psiutils/RecursionUtils.java @@ -0,0 +1,573 @@ +package com.siyeh.ig.psiutils; + +import com.intellij.psi.*; +import com.intellij.psi.tree.IElementType; + +public class RecursionUtils { + private RecursionUtils() { + super(); + } + + public static boolean statementMayReturnBeforeRecursing(PsiStatement statement, PsiMethod method) { + if (statement == null) { + return true; + } + if (statement instanceof PsiBreakStatement || + statement instanceof PsiContinueStatement || + statement instanceof PsiThrowStatement || + statement instanceof PsiExpressionListStatement || + statement instanceof PsiExpressionStatement || + statement instanceof PsiEmptyStatement || + statement instanceof PsiAssertStatement || + statement instanceof PsiDeclarationStatement) { + return false; + } else if (statement instanceof PsiReturnStatement) { + final PsiReturnStatement returnStatement = (PsiReturnStatement) statement; + final PsiExpression returnValue = returnStatement.getReturnValue(); + if (returnValue != null) { + if (expressionMustRecurse(returnValue, method)) { + return false; + } + } + return true; + } else if (statement instanceof PsiForStatement) { + return forStatementMayReturnBeforeRecursing((PsiForStatement) statement, method); + } else if (statement instanceof PsiForeachStatement) { + return foreachStatementMayReturnBeforeRecursing((PsiForeachStatement) statement, method); + } else if (statement instanceof PsiWhileStatement) { + return whileStatementMayReturnBeforeRecursing((PsiWhileStatement) statement, method); + } else if (statement instanceof PsiDoWhileStatement) { + return doWhileStatementMayReturnBeforeRecursing((PsiDoWhileStatement) statement, method); + } else if (statement instanceof PsiSynchronizedStatement) { + final PsiCodeBlock body = ((PsiSynchronizedStatement) statement).getBody(); + return codeBlockMayReturnBeforeRecursing(body, method, false); + } else if (statement instanceof PsiBlockStatement) { + final PsiCodeBlock codeBlock = ((PsiBlockStatement) statement).getCodeBlock(); + return codeBlockMayReturnBeforeRecursing(codeBlock, method, false); + } else if (statement instanceof PsiLabeledStatement) { + return labeledStatementMayReturnBeforeRecursing((PsiLabeledStatement) statement, method); + } else if (statement instanceof PsiIfStatement) { + return ifStatementMayReturnBeforeRecursing((PsiIfStatement) statement, method); + } else if (statement instanceof PsiTryStatement) { + return tryStatementMayReturnBeforeRecursing((PsiTryStatement) statement, method); + } else if (statement instanceof PsiSwitchStatement) { + return switchStatementMayReturnBeforeRecursing((PsiSwitchStatement) statement, method); + } else // unknown statement type + { + return true; + } + } + + private static boolean doWhileStatementMayReturnBeforeRecursing(PsiDoWhileStatement loopStatement, PsiMethod method) { + final PsiStatement body = loopStatement.getBody(); + return statementMayReturnBeforeRecursing(body, method); + } + + private static boolean whileStatementMayReturnBeforeRecursing(PsiWhileStatement loopStatement, PsiMethod method) { + final PsiExpression test = loopStatement.getCondition(); + if (expressionMustRecurse(test, method)) { + return false; + } + final PsiStatement body = loopStatement.getBody(); + return statementMayReturnBeforeRecursing(body, method); + + } + + private static boolean forStatementMayReturnBeforeRecursing(PsiForStatement loopStatement, PsiMethod method) { + final PsiStatement initialization = loopStatement.getInitialization(); + + if (statementMayReturnBeforeRecursing(initialization, method)) { + return true; + } + final PsiExpression test = loopStatement.getCondition(); + if (expressionMustRecurse(test, method)) { + return false; + } + final PsiStatement body = loopStatement.getBody(); + return statementMayReturnBeforeRecursing(body, method); + } + + + private static boolean foreachStatementMayReturnBeforeRecursing(PsiForeachStatement loopStatement, PsiMethod method) { + final PsiExpression test = loopStatement.getIteratedValue(); + if (expressionMustRecurse(test, method)) { + return false; + } + final PsiStatement body = loopStatement.getBody(); + return statementMayReturnBeforeRecursing(body, method); + } + + private static boolean switchStatementMayReturnBeforeRecursing(PsiSwitchStatement switchStatement, PsiMethod method) { + + final PsiCodeBlock body = switchStatement.getBody(); + if (body == null) { + return true; + } + final PsiStatement[] statements = body.getStatements(); + if (statements == null) { + return true; + } + for (int i = 0; i < statements.length; i++) { + final PsiStatement statement = statements[i]; + if (statementMayReturnBeforeRecursing(statement, method)) { + return true; + } + } + return statementMayReturnBeforeRecursing(statements[statements.length - 1], method); + } + + private static boolean tryStatementMayReturnBeforeRecursing(PsiTryStatement tryStatement, PsiMethod method) { + final PsiCodeBlock finallyBlock = tryStatement.getFinallyBlock(); + if (finallyBlock != null) { + if (!codeBlockMayReturnBeforeRecursing(finallyBlock, method, false)) { + return false; + } + } + final PsiCodeBlock tryBlock = tryStatement.getTryBlock(); + if (codeBlockMayReturnBeforeRecursing(tryBlock, method, false)) { + return true; + } + final PsiCodeBlock[] catchBlocks = tryStatement.getCatchBlocks(); + for (int i = 0; i < catchBlocks.length; i++) { + final PsiCodeBlock catchBlock = catchBlocks[i]; + if (codeBlockMayReturnBeforeRecursing(catchBlock, method, false)) { + return true; + } + } + return false; + } + + private static boolean ifStatementMayReturnBeforeRecursing(PsiIfStatement ifStatement, PsiMethod method) { + final PsiExpression test = ifStatement.getCondition(); + if (expressionMustRecurse(test, method)) { + return false; + } + final PsiStatement thenBranch = ifStatement.getThenBranch(); + if (statementMayReturnBeforeRecursing(thenBranch, method)) { + return true; + } + final PsiStatement elseBranch = ifStatement.getElseBranch(); + if (elseBranch != null && + statementMayReturnBeforeRecursing(elseBranch, method)) { + return true; + } + return false; + } + + private static boolean labeledStatementMayReturnBeforeRecursing(PsiLabeledStatement labeledStatement, PsiMethod method) { + final PsiStatement statement = labeledStatement.getStatement(); + return statementMayReturnBeforeRecursing(statement, method); + } + + private static boolean codeBlockMayReturnBeforeRecursing(PsiCodeBlock block, PsiMethod method, boolean endsInImplicitReturn) { + if (block == null) { + return true; + } + final PsiStatement[] statements = block.getStatements(); + for (int i = 0; i < statements.length; i++) { + final PsiStatement statement = statements[i]; + if (statementMayReturnBeforeRecursing(statement, method)) { + return true; + } + if (statementMustRecurse(statement, method)) { + return false; + } + } + return endsInImplicitReturn; + } + + public static boolean methodMayRecurse(PsiMethod method) { + final RecursionVisitor recursionVisitor = new RecursionVisitor(method); + method.accept(recursionVisitor); + return recursionVisitor.isRecursive(); + } + + private static boolean expressionMustRecurse(PsiExpression exp, PsiMethod method) { + if (exp == null) { + return false; + } + if (exp instanceof PsiMethodCallExpression) { + return methodCallExpressionMustRecurse((PsiMethodCallExpression) exp, method); + } + if (exp instanceof PsiNewExpression) { + return newExpressionMustRecurse((PsiNewExpression) exp, method); + } + if (exp instanceof PsiAssignmentExpression) { + return assignmentExpressionMustRecurse((PsiAssignmentExpression) exp, method); + } + if (exp instanceof PsiArrayInitializerExpression) { + return arrayInitializerExpressionMustRecurse((PsiArrayInitializerExpression) exp, method); + } + if (exp instanceof PsiTypeCastExpression) { + return typeCastExpressionMustRecurse((PsiTypeCastExpression) exp, method); + } + if (exp instanceof PsiArrayAccessExpression) { + return arrayAccessExpressionMustRecurse((PsiArrayAccessExpression) exp, method); + } + if (exp instanceof PsiPrefixExpression) { + return prefixExpressionMustRecurse((PsiPrefixExpression) exp, method); + } + if (exp instanceof PsiPostfixExpression) { + return postfixExpressionMustRecurse((PsiPostfixExpression) exp, method); + } + if (exp instanceof PsiBinaryExpression) { + return binaryExpressionMustRecurse((PsiBinaryExpression) exp, method); + } + if (exp instanceof PsiInstanceOfExpression) { + return instanceOfExpressionMustRecurse((PsiInstanceOfExpression) exp, method); + } + if (exp instanceof PsiConditionalExpression) { + return conditionalExpressionMustRecurse((PsiConditionalExpression) exp, method); + } + if (exp instanceof PsiParenthesizedExpression) { + return parenthesizedExpressionMustRecurse((PsiParenthesizedExpression) exp, method); + } + if (exp instanceof PsiReferenceExpression) { + return referenceExpressionMustRecurse((PsiReferenceExpression) exp, method); + } + if (exp instanceof PsiLiteralExpression || + exp instanceof PsiClassObjectAccessExpression || + exp instanceof PsiThisExpression || + exp instanceof PsiSuperExpression) { + return false; + } + return false; + } + + private static boolean conditionalExpressionMustRecurse(PsiConditionalExpression expression, PsiMethod method) { + final PsiExpression condExpression = expression.getCondition(); + if (expressionMustRecurse(condExpression, method)) { + return true; + } + final PsiExpression thenExpression = expression.getThenExpression(); + final PsiExpression elseExpression = expression.getElseExpression(); + return expressionMustRecurse(thenExpression, method) && expressionMustRecurse(elseExpression, method); + } + + private static boolean binaryExpressionMustRecurse(PsiBinaryExpression expression, PsiMethod method) { + final PsiExpression lhs = expression.getLOperand(); + if (expressionMustRecurse(lhs, method)) { + return true; + } + final PsiJavaToken sign = expression.getOperationSign(); + if (sign != null) { + final IElementType tokenType = sign.getTokenType(); + if (tokenType.equals(JavaTokenType.ANDAND) || + tokenType.equals(JavaTokenType.OROR)) { + return false; + } + } + final PsiExpression rhs = expression.getROperand(); + return expressionMustRecurse(rhs, method); + } + + private static boolean arrayAccessExpressionMustRecurse(PsiArrayAccessExpression expression, PsiMethod method) { + final PsiExpression arrayExp = expression.getArrayExpression(); + final PsiExpression indexExp = expression.getIndexExpression(); + return expressionMustRecurse(arrayExp, method) || + expressionMustRecurse(indexExp, method); + } + + private static boolean arrayInitializerExpressionMustRecurse(PsiArrayInitializerExpression expression, PsiMethod method) { + final PsiExpression[] initializers = expression.getInitializers(); + if (initializers == null) { + return false; + } + for (int i = 0; i < initializers.length; i++) { + final PsiExpression initializer = initializers[i]; + if (expressionMustRecurse(initializer, method)) { + return true; + } + } + return false; + } + + private static boolean prefixExpressionMustRecurse(PsiPrefixExpression expression, PsiMethod method) { + final PsiExpression operand = expression.getOperand(); + return expressionMustRecurse(operand, method); + } + + private static boolean postfixExpressionMustRecurse(PsiPostfixExpression expression, PsiMethod method) { + final PsiExpression operand = expression.getOperand(); + return expressionMustRecurse(operand, method); + } + + private static boolean instanceOfExpressionMustRecurse(PsiInstanceOfExpression expression, PsiMethod method) { + final PsiExpression operand = expression.getOperand(); + return expressionMustRecurse(operand, method); + } + + private static boolean parenthesizedExpressionMustRecurse(PsiParenthesizedExpression expression, PsiMethod method) { + final PsiExpression innerExpression = expression.getExpression(); + return expressionMustRecurse(innerExpression, method); + } + + private static boolean referenceExpressionMustRecurse(PsiReferenceExpression expression, PsiMethod method) { + + final PsiExpression qualifierExpression = expression.getQualifierExpression(); + if (qualifierExpression != null) { + return expressionMustRecurse(qualifierExpression, method); + } + return false; + } + + private static boolean typeCastExpressionMustRecurse(PsiTypeCastExpression expression, PsiMethod method) { + final PsiExpression operand = expression.getOperand(); + return expressionMustRecurse(operand, method); + } + + private static boolean assignmentExpressionMustRecurse(PsiAssignmentExpression assignmentExpression, PsiMethod method) { + final PsiExpression rhs = assignmentExpression.getRExpression(); + final PsiExpression lhs = assignmentExpression.getLExpression(); + return expressionMustRecurse(rhs, method) || + expressionMustRecurse(lhs, method); + } + + private static boolean newExpressionMustRecurse(PsiNewExpression exp, PsiMethod method) { + final PsiExpression[] arrayDimensions = exp.getArrayDimensions(); + if (arrayDimensions != null) { + for (int i = 0; i < arrayDimensions.length; i++) { + final PsiExpression arrayDimension = arrayDimensions[i]; + if (expressionMustRecurse(arrayDimension, method)) { + return true; + } + } + } + final PsiArrayInitializerExpression arrayInitializer = exp.getArrayInitializer(); + if (expressionMustRecurse(arrayInitializer, method)) { + return true; + } + final PsiExpression qualifier = exp.getQualifier(); + if (expressionMustRecurse(qualifier, method)) { + return true; + } + final PsiExpressionList argumentList = exp.getArgumentList(); + if (argumentList != null) { + final PsiExpression[] args = argumentList.getExpressions(); + for (int i = 0; i < args.length; i++) { + final PsiExpression arg = args[i]; + if (expressionMustRecurse(arg, method)) { + return true; + } + } + } + return false; + } + + private static boolean methodCallExpressionMustRecurse(PsiMethodCallExpression exp, PsiMethod method) { + final PsiMethod referencedMethod = exp.resolveMethod(); + if (referencedMethod == null) { + return false; + } + if (referencedMethod.equals(method)) { + return true; + } + final PsiReferenceExpression methodExpression = exp.getMethodExpression(); + if (methodExpression != null) { + final PsiExpression qualifier = methodExpression.getQualifierExpression(); + if (expressionMustRecurse(qualifier, method)) { + return true; + } + } + final PsiExpressionList argumentList = exp.getArgumentList(); + if (argumentList != null) { + final PsiExpression[] args = argumentList.getExpressions(); + for (int i = 0; i < args.length; i++) { + final PsiExpression arg = args[i]; + if (expressionMustRecurse(arg, method)) { + return true; + } + } + } + return false; + } + + private static boolean statementMustRecurse(PsiStatement statement, PsiMethod method) { + if (statement == null) { + return false; + } + if (statement instanceof PsiBreakStatement || + statement instanceof PsiContinueStatement || + statement instanceof PsiThrowStatement || + statement instanceof PsiEmptyStatement || + statement instanceof PsiAssertStatement) { + return false; + } else if (statement instanceof PsiExpressionListStatement) { + final PsiExpressionList expressionList = ((PsiExpressionListStatement) statement).getExpressionList(); + if (expressionList == null) { + return false; + } + final PsiExpression[] expressions = expressionList.getExpressions(); + for (int i = 0; i < expressions.length; i++) { + final PsiExpression expression = expressions[i]; + if (expressionMustRecurse(expression, method)) { + return true; + } + } + return false; + } else if (statement instanceof PsiExpressionStatement) { + final PsiExpression expression = ((PsiExpressionStatement) statement).getExpression(); + return expressionMustRecurse(expression, method); + } else if (statement instanceof PsiDeclarationStatement) { + final PsiDeclarationStatement declaration = (PsiDeclarationStatement) statement; + final PsiElement[] declaredElements = declaration.getDeclaredElements(); + if (declaredElements == null) { + return false; + } + for (int i = 0; i < declaredElements.length; i++) { + final PsiElement declaredElement = declaredElements[i]; + if (declaredElement instanceof PsiLocalVariable) { + final PsiLocalVariable variable = (PsiLocalVariable) declaredElement; + final PsiExpression initializer = variable.getInitializer(); + if (expressionMustRecurse(initializer, method)) { + return true; + } + } + } + return false; + } else if (statement instanceof PsiReturnStatement) { + final PsiReturnStatement returnStatement = (PsiReturnStatement) statement; + final PsiExpression returnValue = returnStatement.getReturnValue(); + if (returnValue != null) { + if (expressionMustRecurse(returnValue, method)) { + return true; + } + } + return false; + } else if (statement instanceof PsiForStatement) { + return forStatementMustRecurse((PsiForStatement) statement, method); + } else if (statement instanceof PsiForeachStatement) { + return foreachStatementMustRecurse((PsiForeachStatement) statement, method); + } else if (statement instanceof PsiWhileStatement) { + return whileStatementMustRecurse((PsiWhileStatement) statement, method); + } else if (statement instanceof PsiDoWhileStatement) { + return doWhileStatementMustRecurse((PsiDoWhileStatement) statement, method); + } else if (statement instanceof PsiSynchronizedStatement) { + final PsiCodeBlock body = ((PsiSynchronizedStatement) statement).getBody(); + return codeBlockMustRecurse(body, method); + } else if (statement instanceof PsiBlockStatement) { + final PsiCodeBlock codeBlock = ((PsiBlockStatement) statement).getCodeBlock(); + return codeBlockMustRecurse(codeBlock, method); + } else if (statement instanceof PsiLabeledStatement) { + return labeledStatementMustRecurse((PsiLabeledStatement) statement, method); + } else if (statement instanceof PsiIfStatement) { + return ifStatementMustRecurse((PsiIfStatement) statement, method); + } else if (statement instanceof PsiTryStatement) { + return tryStatementMustRecurse((PsiTryStatement) statement, method); + } else if (statement instanceof PsiSwitchStatement) { + return switchStatementMustRecurse((PsiSwitchStatement) statement, method); + } else // unknown statement type + { + return false; + } + } + + private static boolean switchStatementMustRecurse(PsiSwitchStatement switchStatement, PsiMethod method) { + final PsiExpression switchExpression = switchStatement.getExpression(); + return expressionMustRecurse(switchExpression, method); + } + + private static boolean tryStatementMustRecurse(PsiTryStatement tryStatement, PsiMethod method) { + final PsiCodeBlock tryBlock = tryStatement.getTryBlock(); + if (codeBlockMustRecurse(tryBlock, method)) { + return true; + } + final PsiCodeBlock finallyBlock = tryStatement.getFinallyBlock(); + if (codeBlockMustRecurse(finallyBlock, method)) { + return true; + } + return false; + } + + private static boolean codeBlockMustRecurse(PsiCodeBlock block, PsiMethod method) { + if (block == null) { + return false; + } + final PsiStatement[] statements = block.getStatements(); + if (statements == null) { + return false; + } + for (int i = 0; i < statements.length; i++) { + final PsiStatement statement = statements[i]; + if (statementMustRecurse(statement, method)) { + return true; + } + } + return false; + } + + private static boolean ifStatementMustRecurse(PsiIfStatement ifStatement, PsiMethod method) { + final PsiExpression condition = ifStatement.getCondition(); + if (expressionMustRecurse(condition, method)) { + return true; + } + final PsiStatement thenBranch = ifStatement.getThenBranch(); + final PsiStatement elseBranch = ifStatement.getElseBranch(); + if (thenBranch == null || elseBranch == null) { + return false; + } + return statementMustRecurse(thenBranch, method) && + statementMustRecurse(elseBranch, method); + } + + private static boolean forStatementMustRecurse(PsiForStatement forStatement, PsiMethod method) { + final PsiStatement initialization = forStatement.getInitialization(); + if (statementMustRecurse(initialization, method)) { + return true; + } + final PsiExpression condition = forStatement.getCondition(); + if (expressionMustRecurse(condition, method)) { + return true; + } + if (BoolUtils.isTrue(condition)) { + final PsiStatement body = forStatement.getBody(); + return statementMustRecurse(body, method); + } + return false; + } + + private static boolean foreachStatementMustRecurse(PsiForeachStatement foreachStatement, PsiMethod method) { + final PsiExpression iteration = foreachStatement.getIteratedValue(); + if (expressionMustRecurse(iteration, method)) { + return true; + } + return false; + } + + private static boolean whileStatementMustRecurse(PsiWhileStatement whileStatement, PsiMethod method) { + + final PsiExpression condition = whileStatement.getCondition(); + if (expressionMustRecurse(condition, method)) { + return true; + } + if (BoolUtils.isTrue(condition)) { + final PsiStatement body = whileStatement.getBody(); + return statementMustRecurse(body, method); + } + return false; + } + + private static boolean doWhileStatementMustRecurse(PsiDoWhileStatement doWhileStatement, PsiMethod method) { + + final PsiStatement body = doWhileStatement.getBody(); + if (statementMustRecurse(body, method)) { + return true; + } + final PsiExpression condition = doWhileStatement.getCondition(); + return expressionMustRecurse(condition, method); + } + + private static boolean labeledStatementMustRecurse(PsiLabeledStatement labeledStatement, PsiMethod method) { + final PsiStatement body = labeledStatement.getStatement(); + return statementMustRecurse(body, method); + } + + public static boolean methodMustRecurseBeforeReturning(PsiMethod method) { + final PsiCodeBlock body = method.getBody(); + if (body == null) { + return false; + } + return !codeBlockMayReturnBeforeRecursing(body, method, true); + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/psiutils/RecursionVisitor.java b/plugins/InspectionGadgets/src/com/siyeh/ig/psiutils/RecursionVisitor.java new file mode 100644 index 000000000000..942886e388ef --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/psiutils/RecursionVisitor.java @@ -0,0 +1,38 @@ +package com.siyeh.ig.psiutils; + +import com.intellij.psi.*; + +public class RecursionVisitor extends PsiRecursiveElementVisitor { + private boolean m_recursive = false; + private final PsiMethod m_method; + + public RecursionVisitor(PsiMethod method) { + super(); + m_method = method; + } + + 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 psiMethodCallExpression) { + super.visitMethodCallExpression(psiMethodCallExpression); + final PsiMethod method = psiMethodCallExpression.resolveMethod(); + if (method != null) { + if (method.equals(m_method)) { + m_recursive = true; + } + } + } + + public boolean isRecursive() { + return m_recursive; + } +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/psiutils/SerializationUtils.java b/plugins/InspectionGadgets/src/com/siyeh/ig/psiutils/SerializationUtils.java new file mode 100644 index 000000000000..9ca62bc5b076 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/psiutils/SerializationUtils.java @@ -0,0 +1,141 @@ +package com.siyeh.ig.psiutils; + +import com.intellij.openapi.project.Project; +import com.intellij.psi.*; +import com.intellij.psi.search.GlobalSearchScope; +import com.intellij.psi.util.InheritanceUtil; +import com.intellij.psi.util.TypeConversionUtil; + +public class SerializationUtils { + private static final String SERIALIZABLE_CLASS_NAME = "java.io.Serializable"; + private static final String EXTERNALIZABLE_CLASS_NAME = "java.io.Externalizable"; + + private SerializationUtils() { + super(); + } + + + public static boolean isSerializable(PsiClass aClass) { + final PsiManager manager = aClass.getManager(); + final Project project = manager.getProject(); + final GlobalSearchScope scope = GlobalSearchScope.allScope(project); + final PsiClass serializable = manager.findClass(SERIALIZABLE_CLASS_NAME, scope); + return InheritanceUtil.isInheritorOrSelf(aClass, serializable, true); + } + + public static boolean isExternalizable(PsiClass aClass) { + final PsiManager manager = aClass.getManager(); + final Project project = manager.getProject(); + final GlobalSearchScope scope = GlobalSearchScope.allScope(project); + final PsiClass serializable = manager.findClass(EXTERNALIZABLE_CLASS_NAME, scope); + return InheritanceUtil.isInheritorOrSelf(aClass, serializable, true); + } + + + public static boolean isDirectlySerializable(PsiClass aClass) { + final PsiReferenceList implementsList = aClass.getImplementsList(); + if (implementsList != null) { + final PsiJavaCodeReferenceElement[] interfaces = implementsList.getReferenceElements(); + for (int i = 0; i < interfaces.length; i++) { + final PsiClass implemented = (PsiClass) interfaces[i].resolve(); + if (implemented != null) { + final String name = implemented.getQualifiedName(); + if (SERIALIZABLE_CLASS_NAME.equals(name)) { + return true; + } + } + } + } + return false; + } + + public static boolean isReadObject(PsiMethod method) { + final String methodName = method.getName(); + if (!"readObject".equals(methodName)) { + return false; + } + final PsiParameterList parameterList = method.getParameterList(); + final PsiParameter[] parameters = parameterList.getParameters(); + if (parameters.length != 1) { + return false; + } + final PsiType argType = parameters[0].getType(); + if (!TypeUtils.typeEquals("java.io.ObjectInputStream", argType)) { + return false; + } + final PsiType returnType = method.getReturnType(); + if (!TypeUtils.typeEquals("void", returnType)) { + return false; + } + return true; + } + + public static boolean isWriteObject(PsiMethod method) { + final String methodName = method.getName(); + if (!"writeObject".equals(methodName)) { + return false; + } + final PsiParameterList parameterList = method.getParameterList(); + final PsiParameter[] parameters = parameterList.getParameters(); + if (parameters.length != 1) { + return false; + } + final PsiType argType = parameters[0].getType(); + if (!TypeUtils.typeEquals("java.io.ObjectOutputStream", argType)) { + return false; + } + final PsiType returnType = method.getReturnType(); + if (!TypeUtils.typeEquals("void", returnType)) { + return false; + } + return true; + } + + public static boolean isReadResolve(PsiMethod method) { + final String methodName = method.getName(); + if (!"readResolve".equals(methodName)) { + return false; + } + final PsiParameterList parameterList = method.getParameterList(); + final PsiParameter[] parameters = parameterList.getParameters(); + if (parameters.length != 0) { + return false; + } + final PsiType returnType = method.getReturnType(); + if (!TypeUtils.isJavaLangObject(returnType)) { + return false; + } + return true; + } + + public static boolean isWriteReplace(PsiMethod method) { + final String methodName = method.getName(); + if (!"writeReplace".equals(methodName)) { + return false; + } + final PsiParameterList parameterList = method.getParameterList(); + final PsiParameter[] parameters = parameterList.getParameters(); + if (parameters.length != 0) { + return false; + } + final PsiType returnType = method.getReturnType(); + if (!TypeUtils.isJavaLangObject(returnType)) { + return false; + } + return true; + } + + public static boolean typeIsSerializable(PsiType type) { + final PsiType componentType = type.getDeepComponentType(); + if (TypeConversionUtil.isPrimitiveAndNotNull(componentType)) { + return true; + } + final PsiType[] superTypes = componentType.getSuperTypes(); + for (int i = 0; i < superTypes.length; i++) { + if (TypeUtils.typeEquals(SERIALIZABLE_CLASS_NAME, superTypes[i])) { + return true; + } + } + return false; + } +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/psiutils/SideEffectChecker.java b/plugins/InspectionGadgets/src/com/siyeh/ig/psiutils/SideEffectChecker.java new file mode 100644 index 000000000000..d3640520f2c2 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/psiutils/SideEffectChecker.java @@ -0,0 +1,68 @@ +package com.siyeh.ig.psiutils; + +import com.intellij.psi.*; + +public class SideEffectChecker { + private SideEffectChecker() { + super(); + + } + + public static boolean mayHaveSideEffects(PsiExpression exp) { + final SideEffectsVisitor visitor = new SideEffectsVisitor(); + exp.accept(visitor); + return visitor.mayHaveSideEffects(); + } + + private static class SideEffectsVisitor extends PsiRecursiveElementVisitor { + private boolean m_mayHaveSideEffects = false; + + private boolean mayHaveSideEffects() { + return m_mayHaveSideEffects; + } + + public void visitReferenceExpression(PsiReferenceExpression expression) { + final PsiExpression qualifier = expression.getQualifierExpression(); + if (qualifier != null) { + qualifier.accept(this); + } + final PsiReferenceParameterList typeParameters = expression.getParameterList(); + if (typeParameters != null) { + typeParameters.accept(this); + } + } + + public void visitAssignmentExpression(PsiAssignmentExpression expression) { + super.visitAssignmentExpression(expression); + m_mayHaveSideEffects = true; + } + + public void visitMethodCallExpression(PsiMethodCallExpression expression) { + super.visitMethodCallExpression(expression); + m_mayHaveSideEffects = true; + } + + public void visitNewExpression(PsiNewExpression expression) { + super.visitNewExpression(expression); + m_mayHaveSideEffects = true; + } + + public void visitPostfixExpression(PsiPostfixExpression expression) { + super.visitPostfixExpression(expression); + final PsiJavaToken sign = expression.getOperationSign(); + if (sign.getTokenType() == JavaTokenType.PLUSPLUS || + sign.getTokenType() == JavaTokenType.PLUSPLUS) { + m_mayHaveSideEffects = true; + } + } + + public void visitPrefixExpression(PsiPrefixExpression expression) { + super.visitPrefixExpression(expression); + final PsiJavaToken sign = expression.getOperationSign(); + if (sign.getTokenType() == JavaTokenType.PLUSPLUS || + sign.getTokenType() == JavaTokenType.PLUSPLUS) { + m_mayHaveSideEffects = true; + } + } + } +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/psiutils/SingletonUtil.java b/plugins/InspectionGadgets/src/com/siyeh/ig/psiutils/SingletonUtil.java new file mode 100644 index 000000000000..2767bbd7a6b6 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/psiutils/SingletonUtil.java @@ -0,0 +1,72 @@ +package com.siyeh.ig.psiutils; + +import com.intellij.psi.*; + +public class SingletonUtil { + private SingletonUtil() { + super(); + } + + public static boolean isSingleton(PsiClass aClass) { + if (aClass.isInterface() || aClass.isEnum() || aClass.isAnnotationType()) { + return false; + } + if (!hasConstructor(aClass)) { + return false; + } + if (hasVisibleConstructor(aClass)) { + return false; + } + if (!containsOneStaticSelfInstance(aClass)) { + return false; + } + return true; + } + + private static boolean containsOneStaticSelfInstance(PsiClass aClass) { + final PsiField[] fields = aClass.getFields(); + int numSelfInstances = 0; + for (int i = 0; i < fields.length; i++) { + final PsiField field = fields[i]; + final String className = aClass.getQualifiedName(); + if (field.hasModifierProperty(PsiModifier.STATIC)) { + final PsiType type = field.getType(); + if (type != null) { + final String fieldTypeName = type.getCanonicalText(); + if (fieldTypeName.equals(className)) { + numSelfInstances++; + } + } + } + } + return numSelfInstances == 1; + } + + private static boolean hasConstructor(PsiClass aClass) { + final PsiMethod[] methods = aClass.getMethods(); + for (int i = 0; i < methods.length; i++) { + final PsiMethod method = methods[i]; + if (method.isConstructor()) { + return true; + } + } + return false; + } + + private static boolean hasVisibleConstructor(PsiClass aClass) { + final PsiMethod[] methods = aClass.getMethods(); + for (int i = 0; i < methods.length; i++) { + final PsiMethod method = methods[i]; + if (method.isConstructor()) { + if (method.hasModifierProperty(PsiModifier.PUBLIC)) { + return true; + } + if (!method.hasModifierProperty(PsiModifier.PRIVATE) && + !method.hasModifierProperty(PsiModifier.PROTECTED)) { + return true; + } + } + } + return false; + } +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/psiutils/TypeUtils.java b/plugins/InspectionGadgets/src/com/siyeh/ig/psiutils/TypeUtils.java new file mode 100644 index 000000000000..1a2fa6414366 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/psiutils/TypeUtils.java @@ -0,0 +1,61 @@ +package com.siyeh.ig.psiutils; + +import com.intellij.psi.PsiExpression; +import com.intellij.psi.PsiType; + +public class TypeUtils { + private TypeUtils() { + super(); + } + + public static boolean expressionHasType(String typeName, PsiExpression expression) { + if (expression == null) { + return false; + } + final PsiType type = expression.getType(); + if (type == null) { + return false; + } + final String text = type.getCanonicalText(); + return typeName.equals(text); + } + + public static boolean typeEquals(String typeName, PsiType targetType) { + if (targetType == null) { + return false; + } + final String text = targetType.getCanonicalText(); + return typeName.equals(text); + } + + public static boolean isJavaLangObject(PsiType targetType) { + return typeEquals("java.lang.Object", targetType); + } + + public static boolean isJavaLangString(PsiType targetType) { + return typeEquals("java.lang.String", targetType); + } + + public static boolean expressionHasTypeOrSubtype(String typeName, PsiExpression expression) { + if (expression == null) { + return false; + } + final PsiType type = expression.getType(); + if (type == null) { + return false; + } + final String text = type.getCanonicalText(); + if(typeName.equals(text)) + { + return true; + } + final PsiType[] superTypes = type.getSuperTypes(); + for (int i = 0; i < superTypes.length; i++) { + final String superTypeName = superTypes[i].getCanonicalText(); + if (typeName.equals(superTypeName)) { + return true; + } + } + return false; + } +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/psiutils/UtilityClassUtil.java b/plugins/InspectionGadgets/src/com/siyeh/ig/psiutils/UtilityClassUtil.java new file mode 100644 index 000000000000..2cf0e90f82db --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/psiutils/UtilityClassUtil.java @@ -0,0 +1,54 @@ +package com.siyeh.ig.psiutils; + +import com.intellij.psi.*; + +public class UtilityClassUtil { + private UtilityClassUtil() { + super(); + } + + public static boolean isUtilityClass(PsiClass aClass) { + if (aClass.isInterface() || aClass.isEnum() || aClass.isAnnotationType()) { + return false; + } + final PsiReferenceList extendsList = aClass.getExtendsList(); + if (extendsList != null + && extendsList.getReferenceElements().length > 0) { + return false; + } + if (!allMethodsStatic(aClass)) { + return false; + } + if (!allFieldsStatic(aClass)) { + return false; + } + if (aClass.getMethods().length == 0 && aClass.getFields().length == 0) { + return false; + } + return true; + } + + private static boolean allFieldsStatic(PsiClass aClass) { + boolean allFieldsStatic = true; + final PsiField[] fields = aClass.getFields(); + for (int i = 0; i < fields.length; i++) { + final PsiField field = fields[i]; + if (!field.hasModifierProperty(PsiModifier.STATIC)) { + allFieldsStatic = false; + } + } + return allFieldsStatic; + } + + private static boolean allMethodsStatic(PsiClass aClass) { + final PsiMethod[] methods = aClass.getMethods(); + for (int i = 0; i < methods.length; i++) { + final PsiMethod method = methods[i]; + if (!(method.isConstructor() || + method.hasModifierProperty(PsiModifier.STATIC))) { + return false; + } + } + return true; + } +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/psiutils/VariableAccessUtils.java b/plugins/InspectionGadgets/src/com/siyeh/ig/psiutils/VariableAccessUtils.java new file mode 100644 index 000000000000..2d0128477773 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/psiutils/VariableAccessUtils.java @@ -0,0 +1,54 @@ +package com.siyeh.ig.psiutils; + +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiLocalVariable; +import com.intellij.psi.PsiVariable; + +public class VariableAccessUtils { + private VariableAccessUtils() { + super(); + } + + public static boolean variableIsAssignedFrom(PsiVariable variable, PsiElement context) { + final VariableAssignedFromVisitor visitor = new VariableAssignedFromVisitor(variable); + context.accept(visitor); + return visitor.isAssignedFrom(); + } + + public static boolean variableIsPassedAsMethodArgument(PsiVariable variable, PsiElement context) { + final VariablePassedAsArgumentVisitor visitor = new VariablePassedAsArgumentVisitor(variable); + context.accept(visitor); + return visitor.isPassed(); + } + + public static boolean variableIsAssigned(PsiVariable variable, PsiElement context) { + final VariableAssignedVisitor visitor = new VariableAssignedVisitor(variable); + context.accept(visitor); + return visitor.isAssigned(); + } + + public static boolean variableIsReturned(PsiVariable variable, PsiElement context) { + final VariableReturnedVisitor visitor = new VariableReturnedVisitor(variable); + context.accept(visitor); + return visitor.isReturned(); + } + + public static boolean arrayContentsAreAccessed(PsiVariable variable, PsiElement context) { + final ArrayContentsAccessedVisitor visitor = new ArrayContentsAccessedVisitor(variable); + context.accept(visitor); + return visitor.isAccessed(); + } + + public static boolean arrayContentsAreAssigned(PsiVariable variable, PsiElement context) { + final ArrayContentsAssignedVisitor visitor = new ArrayContentsAssignedVisitor(variable); + context.accept(visitor); + return visitor.isAssigned(); + } + + public static boolean variableIsUsedInInnerClass(PsiLocalVariable variable, PsiElement context) { + final VariableUsedInInnerClassVisitor visitor = + new VariableUsedInInnerClassVisitor(variable); + context.accept(visitor); + return visitor.isUsedInInnerClass(); + } +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/psiutils/VariableAssignedFromVisitor.java b/plugins/InspectionGadgets/src/com/siyeh/ig/psiutils/VariableAssignedFromVisitor.java new file mode 100644 index 000000000000..ce462ce91a32 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/psiutils/VariableAssignedFromVisitor.java @@ -0,0 +1,64 @@ +package com.siyeh.ig.psiutils; + +import com.intellij.psi.*; + +public class VariableAssignedFromVisitor extends PsiRecursiveElementVisitor { + private boolean assignedFrom = false; + private final PsiVariable variable; + + public VariableAssignedFromVisitor(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); + } + } + + public void visitAssignmentExpression(PsiAssignmentExpression assignment) { + super.visitAssignmentExpression(assignment); + final PsiExpression arg = assignment.getRExpression(); + if (arg == null) { + return; + } + if (!(arg instanceof PsiReferenceExpression)) { + return; + } + final PsiElement referent = ((PsiReference) arg).resolve(); + if (referent == null) { + return; + } + if (referent.equals(variable)) { + assignedFrom = true; + } + } + + public void visitVariable(PsiVariable var) { + super.visitVariable(var); + final PsiExpression arg = var.getInitializer(); + if (arg == null) { + return; + } + if (!(arg instanceof PsiReferenceExpression)) { + return; + } + final PsiElement referent = ((PsiReference) arg).resolve(); + if (referent == null) { + return; + } + if (referent.equals(variable)) { + assignedFrom = true; + } + } + + public boolean isAssignedFrom() { + return assignedFrom; + } +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/psiutils/VariableAssignedVisitor.java b/plugins/InspectionGadgets/src/com/siyeh/ig/psiutils/VariableAssignedVisitor.java new file mode 100644 index 000000000000..b1a260e07d41 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/psiutils/VariableAssignedVisitor.java @@ -0,0 +1,43 @@ +package com.siyeh.ig.psiutils; + +import com.intellij.psi.*; + +public class VariableAssignedVisitor extends PsiRecursiveElementVisitor { + private boolean assigned = false; + private final PsiVariable variable; + + public VariableAssignedVisitor(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); + } + } + + public void visitAssignmentExpression(PsiAssignmentExpression assignment) { + super.visitAssignmentExpression(assignment); + final PsiExpression arg = assignment.getLExpression(); + if (!(arg instanceof PsiReferenceExpression)) { + return; + } + final PsiElement referent = ((PsiReference) arg).resolve(); + if (referent == null) { + return; + } + if (referent.equals(variable)) { + assigned = true; + } + } + + public boolean isAssigned() { + return assigned; + } +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/psiutils/VariablePassedAsArgumentVisitor.java b/plugins/InspectionGadgets/src/com/siyeh/ig/psiutils/VariablePassedAsArgumentVisitor.java new file mode 100644 index 000000000000..f682f9318eb2 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/psiutils/VariablePassedAsArgumentVisitor.java @@ -0,0 +1,72 @@ +package com.siyeh.ig.psiutils; + +import com.intellij.psi.*; + +public class VariablePassedAsArgumentVisitor extends PsiRecursiveElementVisitor { + private boolean passed = false; + private final PsiVariable variable; + + public VariablePassedAsArgumentVisitor(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); + } + } + + public void visitMethodCallExpression(PsiMethodCallExpression call) { + super.visitMethodCallExpression(call); + final PsiExpressionList argumentList = call.getArgumentList(); + if (argumentList == null) { + return; + } + + final PsiExpression[] args = argumentList.getExpressions(); + if (args == null) { + return; + } + for (int i = 0; i < args.length; i++) { + final PsiExpression arg = args[i]; + if (arg instanceof PsiReferenceExpression) { + final PsiElement referent = ((PsiReference) arg).resolve(); + if (referent != null && referent.equals(variable)) { + passed = true; + } + } + } + } + + public void visitNewExpression(PsiNewExpression newExpression) { + super.visitNewExpression(newExpression); + final PsiExpressionList argumentList = newExpression.getArgumentList(); + if (argumentList == null) { + return; + } + final PsiExpression[] args = argumentList.getExpressions(); + if (args == null) { + return; + } + for (int i = 0; i < args.length; i++) { + final PsiExpression arg = args[i]; + if (arg instanceof PsiReferenceExpression) { + final PsiElement referent = ((PsiReference) arg).resolve(); + if (referent.equals(variable)) { + passed = true; + } + } + } + + } + + public boolean isPassed() { + return passed; + } +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/psiutils/VariableReturnedVisitor.java b/plugins/InspectionGadgets/src/com/siyeh/ig/psiutils/VariableReturnedVisitor.java new file mode 100644 index 000000000000..1dba78f91cdd --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/psiutils/VariableReturnedVisitor.java @@ -0,0 +1,46 @@ +package com.siyeh.ig.psiutils; + +import com.intellij.psi.*; + +public class VariableReturnedVisitor extends PsiRecursiveElementVisitor { + private boolean returned = false; + private final PsiVariable variable; + + public VariableReturnedVisitor(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); + } + } + + public void visitReturnStatement(PsiReturnStatement returnStatement) { + super.visitReturnStatement(returnStatement); + final PsiExpression returnValue = returnStatement.getReturnValue(); + if (returnValue == null) { + return; + } + if (!(returnValue instanceof PsiReferenceExpression)) { + return; + } + final PsiElement referent = ((PsiReference) returnValue).resolve(); + if (referent == null) { + return; + } + if (referent.equals(variable)) { + returned = true; + } + } + + public boolean isReturned() { + return returned; + } +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/psiutils/VariableSearchUtils.java b/plugins/InspectionGadgets/src/com/siyeh/ig/psiutils/VariableSearchUtils.java new file mode 100644 index 000000000000..31ace66e7eaf --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/psiutils/VariableSearchUtils.java @@ -0,0 +1,100 @@ +package com.siyeh.ig.psiutils; + +import com.intellij.psi.*; +import com.intellij.psi.util.PsiTreeUtil; + +public class VariableSearchUtils { + private VariableSearchUtils() { + super(); + } + + public static boolean existsLocalOrParameter(String varName, PsiElement expression) { + if (existsParameter(varName, expression)) { + return true; + } + if (existsLocal(varName, expression)) { + return true; + } + if (existsForLoopLocal(varName, expression)) { + return true; + } + return existsForeachLoopLocal(varName, expression); + } + + private static boolean existsParameter(String varName, PsiElement element) { + PsiMethod ancestor = (PsiMethod) PsiTreeUtil.getParentOfType(element, PsiMethod.class); + while (ancestor != null) { + final PsiParameterList paramList = ancestor.getParameterList(); + final PsiParameter[] parameters = paramList.getParameters(); + for (int i = 0; i < parameters.length; i++) { + final PsiParameter parameter = parameters[i]; + final String paramName = parameter.getName(); + if (paramName.equals(varName)) { + return true; + } + } + ancestor = (PsiMethod) PsiTreeUtil.getParentOfType(ancestor, PsiMethod.class); + } + return false; + } + + private static boolean existsLocal(String varName, PsiElement element) { + PsiCodeBlock ancestor = (PsiCodeBlock) PsiTreeUtil.getParentOfType(element, PsiCodeBlock.class); + while (ancestor != null) { + final PsiStatement[] statements = ancestor.getStatements(); + for (int i = 0; i < statements.length; i++) { + final PsiStatement statement = statements[i]; + if (statement instanceof PsiDeclarationStatement) { + final PsiDeclarationStatement decl = (PsiDeclarationStatement) statement; + final PsiElement[] elements = decl.getDeclaredElements(); + for (int j = 0; j < elements.length; j++) { + if (!(elements[j] instanceof PsiLocalVariable)) { + continue; + } + final PsiLocalVariable localVar = (PsiLocalVariable) elements[j]; + final String localVarName = localVar.getName(); + if (localVarName.equals(varName)) { + return true; + } + } + } + } + ancestor = (PsiCodeBlock) PsiTreeUtil.getParentOfType(ancestor, PsiCodeBlock.class); + } + return false; + } + + private static boolean existsForLoopLocal(String varName, PsiElement element) { + PsiForStatement forLoopAncestor = (PsiForStatement) PsiTreeUtil.getParentOfType(element, PsiForStatement.class); + while (forLoopAncestor != null) { + final PsiStatement initialization = forLoopAncestor.getInitialization(); + + if (initialization instanceof PsiDeclarationStatement) { + final PsiDeclarationStatement decl = (PsiDeclarationStatement) initialization; + final PsiElement[] elements = decl.getDeclaredElements(); + for (int j = 0; j < elements.length; j++) { + final PsiLocalVariable localVar = (PsiLocalVariable) elements[j]; + final String localVarName = localVar.getName(); + if (localVarName.equals(varName)) { + return true; + } + } + } + forLoopAncestor = (PsiForStatement) PsiTreeUtil.getParentOfType(forLoopAncestor, PsiForStatement.class); + } + return false; + } + + private static boolean existsForeachLoopLocal(String varName, PsiElement element) { + PsiForeachStatement forLoopAncestor = (PsiForeachStatement) PsiTreeUtil.getParentOfType(element, PsiForeachStatement.class); + while (forLoopAncestor != null) { + final PsiParameter parameter = forLoopAncestor.getIterationParameter(); + + if (parameter.getName().equals(varName)) { + return true; + } + forLoopAncestor = (PsiForeachStatement) PsiTreeUtil.getParentOfType(forLoopAncestor, PsiForeachStatement.class); + } + return false; + } +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/psiutils/VariableUsedInInnerClassVisitor.java b/plugins/InspectionGadgets/src/com/siyeh/ig/psiutils/VariableUsedInInnerClassVisitor.java new file mode 100644 index 000000000000..1fc860ca2663 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/psiutils/VariableUsedInInnerClassVisitor.java @@ -0,0 +1,43 @@ +package com.siyeh.ig.psiutils; + +import com.intellij.psi.*; + +public class VariableUsedInInnerClassVisitor extends PsiRecursiveElementVisitor { + private final PsiVariable m_variable; + private boolean m_usedInInnerClass = false; + private boolean m_inInnerClass = false; + + public VariableUsedInInnerClassVisitor(PsiVariable variable) { + super(); + m_variable = variable; + } + + public void visitAnonymousClass(PsiAnonymousClass psiAnonymousClass) { + final boolean wasInInnerClass = m_inInnerClass; + m_inInnerClass = true; + super.visitAnonymousClass(psiAnonymousClass); + m_inInnerClass = wasInInnerClass; + } + + 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); + } + if (!m_inInnerClass) { + return; + } + final PsiElement element = ref.resolve(); + if (m_variable.equals(element)) { + m_usedInInnerClass = true; + } + } + + public boolean isUsedInInnerClass() { + return m_usedInInnerClass; + } +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/security/CloneableClassInSecureContextInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/security/CloneableClassInSecureContextInspection.java new file mode 100644 index 000000000000..fe9ea2a26fea --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/security/CloneableClassInSecureContextInspection.java @@ -0,0 +1,57 @@ +package com.siyeh.ig.security; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.psi.PsiClass; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiMethod; +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.CloneUtils; +import com.siyeh.ig.psiutils.ControlFlowUtils; + +public class CloneableClassInSecureContextInspection extends ClassInspection { + + public String getDisplayName() { + return "Cloneable class in secure context"; + } + + public String getGroupDisplayName() { + return GroupNames.SECURITY_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "Class #ref may be cloned, compromising security #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new CloneableClassInSecureContextVisitor(this, inspectionManager, onTheFly); + } + + private static class CloneableClassInSecureContextVisitor extends BaseInspectionVisitor { + private CloneableClassInSecureContextVisitor(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 (!CloneUtils.isCloneable(aClass)) { + return; + } + final PsiMethod[] methods = aClass.getMethods(); + for (int i = 0; i < methods.length; i++) { + final PsiMethod method = methods[i]; + if (CloneUtils.isClone(method)) { + if (ControlFlowUtils.methodAlwaysThrowsException(method)) { + return; + } + } + } + registerClassError(aClass); + } + } +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/security/DeserializableClassInSecureContextInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/security/DeserializableClassInSecureContextInspection.java new file mode 100644 index 000000000000..d8ec9ebde467 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/security/DeserializableClassInSecureContextInspection.java @@ -0,0 +1,57 @@ +package com.siyeh.ig.security; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.psi.PsiClass; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiMethod; +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.ControlFlowUtils; +import com.siyeh.ig.psiutils.SerializationUtils; + +public class DeserializableClassInSecureContextInspection extends ClassInspection { + + public String getDisplayName() { + return "Deserializable class in secure context"; + } + + public String getGroupDisplayName() { + return GroupNames.SECURITY_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "Class #ref may be deserialized, compromising security #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new DeserializableClassInSecureContextVisitor(this, inspectionManager, onTheFly); + } + + private static class DeserializableClassInSecureContextVisitor extends BaseInspectionVisitor { + private DeserializableClassInSecureContextVisitor(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 PsiMethod[] methods = aClass.getMethods(); + for (int i = 0; i < methods.length; i++) { + final PsiMethod method = methods[i]; + if (SerializationUtils.isReadObject(method)) { + if (ControlFlowUtils.methodAlwaysThrowsException(method)) { + return; + } + } + } + registerClassError(aClass); + } + } +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/security/NonStaticInnerClassInSecureContextInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/security/NonStaticInnerClassInSecureContextInspection.java new file mode 100644 index 000000000000..713862b42a90 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/security/NonStaticInnerClassInSecureContextInspection.java @@ -0,0 +1,50 @@ +package com.siyeh.ig.security; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.psi.PsiClass; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiModifier; +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 NonStaticInnerClassInSecureContextInspection extends ClassInspection { + + public String getDisplayName() { + return "Non-static inner class in secure context"; + } + + public String getGroupDisplayName() { + return GroupNames.SECURITY_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "Non-static inner class #ref, compromising security #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new NonStaticInnerClassInSecureContextVisitor(this, inspectionManager, onTheFly); + } + + private static class NonStaticInnerClassInSecureContextVisitor extends BaseInspectionVisitor { + private NonStaticInnerClassInSecureContextVisitor(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 (aClass.hasModifierProperty(PsiModifier.STATIC)) { + return; + } + if (!ClassUtils.isInnerClass(aClass)) { + return; + } + registerClassError(aClass); + } + } +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/security/SerializableClassInSecureContextInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/security/SerializableClassInSecureContextInspection.java new file mode 100644 index 000000000000..fe417d1860bc --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/security/SerializableClassInSecureContextInspection.java @@ -0,0 +1,57 @@ +package com.siyeh.ig.security; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.psi.PsiClass; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiMethod; +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.ControlFlowUtils; +import com.siyeh.ig.psiutils.SerializationUtils; + +public class SerializableClassInSecureContextInspection extends ClassInspection { + + public String getDisplayName() { + return "Serializable class in secure context"; + } + + public String getGroupDisplayName() { + return GroupNames.SECURITY_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "Class #ref may be serialized, compromising security #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new SerializableClassInSecureContextVisitor(this, inspectionManager, onTheFly); + } + + private static class SerializableClassInSecureContextVisitor extends BaseInspectionVisitor { + private SerializableClassInSecureContextVisitor(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 PsiMethod[] methods = aClass.getMethods(); + for (int i = 0; i < methods.length; i++) { + final PsiMethod method = methods[i]; + if (SerializationUtils.isWriteObject(method)) { + if (ControlFlowUtils.methodAlwaysThrowsException(method)) { + return; + } + } + } + registerError(aClass); + } + } +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/serialization/ExternalizableWithSerializationMethodsInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/serialization/ExternalizableWithSerializationMethodsInspection.java new file mode 100644 index 000000000000..2275ec8a3772 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/serialization/ExternalizableWithSerializationMethodsInspection.java @@ -0,0 +1,81 @@ +package com.siyeh.ig.serialization; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.psi.PsiClass; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiMethod; +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 ExternalizableWithSerializationMethodsInspection extends ClassInspection { + + public String getDisplayName() { + return "Externalizable class with 'readObject()' or 'writeObject()'"; + } + + public String getGroupDisplayName() { + return GroupNames.SERIALIZATION_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + final PsiClass aClass = (PsiClass) location.getParent(); + final PsiMethod[] methods = aClass.getMethods(); + boolean hasReadObject = false; + boolean hasWriteObject = false; + for (int i = 0; i < methods.length; i++) { + final PsiMethod method = methods[i]; + if (SerializationUtils.isReadObject(method)) { + hasReadObject = true; + } else if (SerializationUtils.isWriteObject(method)) { + hasWriteObject = true; + } + } + if (hasReadObject && hasWriteObject) { + return "Externalizable class #ref defines readObject() and writeObject() #loc"; + } else if (hasWriteObject) { + return "Externalizable class #ref defines writeObject() #loc"; + } else { + return "Externalizable class #ref defines readObject() #loc"; + } + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new ExternalizableDefinesSerializationMethodsVisitor(this, inspectionManager, onTheFly); + } + + private static class ExternalizableDefinesSerializationMethodsVisitor extends BaseInspectionVisitor { + private ExternalizableDefinesSerializationMethodsVisitor(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.isExternalizable(aClass)) { + return; + } + final PsiMethod[] methods = aClass.getMethods(); + boolean hasReadObject = false; + boolean hasWriteObject = false; + for (int i = 0; i < methods.length; i++) { + final PsiMethod method = methods[i]; + if (SerializationUtils.isReadObject(method)) { + hasReadObject = true; + } else if (SerializationUtils.isWriteObject(method)) { + hasWriteObject = true; + } + } + if (!hasWriteObject && !hasReadObject) { + return; + } + registerClassError(aClass); + } + + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/serialization/NonSerializableWithSerialVersionUIDFieldInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/serialization/NonSerializableWithSerialVersionUIDFieldInspection.java new file mode 100644 index 000000000000..ec53c74602a1 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/serialization/NonSerializableWithSerialVersionUIDFieldInspection.java @@ -0,0 +1,67 @@ +package com.siyeh.ig.serialization; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.psi.PsiClass; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiField; +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 NonSerializableWithSerialVersionUIDFieldInspection extends ClassInspection { + + public String getDisplayName() { + return "Non-serializable class with serialVersionUID"; + } + + public String getGroupDisplayName() { + return GroupNames.SERIALIZATION_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "Non-serializable class #ref defines a serialVersionUID field #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(); + boolean hasSerialVersionUID = false; + for (int i = 0; i < fields.length; i++) { + final PsiField field = fields[i]; + if (isSerialVersionUID(field)) { + hasSerialVersionUID = true; + } + } + if (!hasSerialVersionUID) { + return; + } + registerClassError(aClass); + } + + private static boolean isSerialVersionUID(PsiField field) { + final String methodName = field.getName(); + return "serialVersionUID".equals(methodName); + } + + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/serialization/NonSerializableWithSerializationMethodsInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/serialization/NonSerializableWithSerializationMethodsInspection.java new file mode 100644 index 000000000000..86a6a01face2 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/serialization/NonSerializableWithSerializationMethodsInspection.java @@ -0,0 +1,81 @@ +package com.siyeh.ig.serialization; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.psi.PsiClass; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiMethod; +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 NonSerializableWithSerializationMethodsInspection extends ClassInspection { + + public String getDisplayName() { + return "Non-serializable class with 'readObject()' or 'writeObject()'"; + } + + public String getGroupDisplayName() { + return GroupNames.SERIALIZATION_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + final PsiClass aClass = (PsiClass) location.getParent(); + final PsiMethod[] methods = aClass.getMethods(); + boolean hasReadObject = false; + boolean hasWriteObject = false; + for (int i = 0; i < methods.length; i++) { + final PsiMethod method = methods[i]; + if (SerializationUtils.isReadObject(method)) { + hasReadObject = true; + } else if (SerializationUtils.isWriteObject(method)) { + hasWriteObject = true; + } + } + if (hasReadObject && hasWriteObject) { + return "Non-serializable class #ref defines readObject() and writeObject() #loc"; + } else if (hasWriteObject) { + return "Non-serializable class #ref defines writeObject() #loc"; + } else { + return "Non-serializable class #ref defines readObject() #loc"; + } + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new NonserializableDefinesSerializationMethodsVisitor(this, inspectionManager, onTheFly); + } + + private static class NonserializableDefinesSerializationMethodsVisitor extends BaseInspectionVisitor { + private NonserializableDefinesSerializationMethodsVisitor(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 PsiMethod[] methods = aClass.getMethods(); + boolean hasReadObject = false; + boolean hasWriteObject = false; + for (int i = 0; i < methods.length; i++) { + final PsiMethod method = methods[i]; + if (SerializationUtils.isReadObject(method)) { + hasReadObject = true; + } else if (SerializationUtils.isWriteObject(method)) { + hasWriteObject = true; + } + } + if (!hasWriteObject && !hasReadObject) { + return; + } + registerClassError(aClass); + } + + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/serialization/ReadObjectAndWriteObjectPrivateInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/serialization/ReadObjectAndWriteObjectPrivateInspection.java new file mode 100644 index 000000000000..e9166e4b43a6 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/serialization/ReadObjectAndWriteObjectPrivateInspection.java @@ -0,0 +1,80 @@ +package com.siyeh.ig.serialization; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.codeInspection.ProblemDescriptor; +import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.project.Project; +import com.intellij.psi.*; +import com.intellij.util.IncorrectOperationException; +import com.siyeh.ig.*; +import com.siyeh.ig.psiutils.SerializationUtils; + +public class ReadObjectAndWriteObjectPrivateInspection extends MethodInspection { + private static final Logger s_logger = Logger.getInstance("ReadObjectAndWriteObjectPrivateInspection"); + private final MakePrivateFix fix = new MakePrivateFix(); + + public String getDisplayName() { + return "'readObject()' or 'writeObject()' not declared 'private'"; + } + + public String getGroupDisplayName() { + return GroupNames.SERIALIZATION_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "#ref not declared 'private' #loc "; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new ReadObjectWriteObjectPrivateVisitor(this, inspectionManager, onTheFly); + } + + public InspectionGadgetsFix buildFix(PsiElement location) { + return fix; + } + + private static class MakePrivateFix extends InspectionGadgetsFix { + public String getName() { + return "Make 'private'"; + } + + public void applyFix(Project project, ProblemDescriptor descriptor) { + try { + final PsiElement methodNameToken = descriptor.getPsiElement(); + final PsiMethod method = (PsiMethod) methodNameToken.getParent(); + final PsiModifierList modifiers = method.getModifierList(); + modifiers.setModifierProperty(PsiModifier.PUBLIC, false); + modifiers.setModifierProperty(PsiModifier.PROTECTED, false); + modifiers.setModifierProperty(PsiModifier.PRIVATE, true); + } catch (IncorrectOperationException e) { + s_logger.error(e); + } + } + } + + private static class ReadObjectWriteObjectPrivateVisitor extends BaseInspectionVisitor { + private ReadObjectWriteObjectPrivateVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitMethod(PsiMethod method) { + // no call to super, so it doesn't drill down + final PsiClass aClass = method.getContainingClass(); + if (aClass.isInterface() || aClass.isAnnotationType()) { + return; + } + if (!SerializationUtils.isSerializable(aClass)) { + return; + } + if (!SerializationUtils.isReadObject(method) && + !SerializationUtils.isWriteObject(method)) { + return; + } + if (method.hasModifierProperty(PsiModifier.PRIVATE)) { + return; + } + registerMethodError(method); + } + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/serialization/ReadObjectInitializationInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/serialization/ReadObjectInitializationInspection.java new file mode 100644 index 000000000000..6226b9489ac3 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/serialization/ReadObjectInitializationInspection.java @@ -0,0 +1,70 @@ +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.FieldInspection; +import com.siyeh.ig.GroupNames; +import com.siyeh.ig.psiutils.InitializationUtils; +import com.siyeh.ig.psiutils.SerializationUtils; + +public class ReadObjectInitializationInspection extends FieldInspection { + + public String getDisplayName() { + return "Instance variable may not be initialized by readObject"; + } + + public String getGroupDisplayName() { + return GroupNames.SERIALIZATION_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "Instance variable #ref may not be initialized during call to readObject #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new ReadObjectInitializationVisitor(this, inspectionManager, onTheFly); + } + + private static class ReadObjectInitializationVisitor extends BaseInspectionVisitor { + private ReadObjectInitializationVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitMethod(PsiMethod method) { + // no call to super, so it doesn't drill down + final PsiClass aClass = method.getContainingClass(); + if (aClass.isInterface() || aClass.isAnnotationType()) { + return; + } + if (!SerializationUtils.isSerializable(aClass)) { + return; + } + + if (!SerializationUtils.isReadObject(method)) { + return; + } + final PsiField[] fields = aClass.getFields(); + for (int i = 0; i < fields.length; i++) { + final PsiField field = fields[i]; + if (!isFieldInitialized(field, method)) { + registerFieldError(field); + } + } + + } + + public static boolean isFieldInitialized(PsiField field, PsiMethod method) { + if (field.hasModifierProperty(PsiModifier.STATIC)) { + return true; + } + if (field.hasModifierProperty(PsiModifier.FINAL) && field.getInitializer() != null) { + return true; + } + final PsiCodeBlock body = method.getBody(); + return InitializationUtils.blockMustAssignVariable(field, body); + } + + } +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/serialization/ReadResolveAndWriteReplaceProtectedInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/serialization/ReadResolveAndWriteReplaceProtectedInspection.java new file mode 100644 index 000000000000..969388daac32 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/serialization/ReadResolveAndWriteReplaceProtectedInspection.java @@ -0,0 +1,84 @@ +package com.siyeh.ig.serialization; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.codeInspection.ProblemDescriptor; +import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.project.Project; +import com.intellij.psi.*; +import com.intellij.util.IncorrectOperationException; +import com.siyeh.ig.*; +import com.siyeh.ig.psiutils.SerializationUtils; + +public class ReadResolveAndWriteReplaceProtectedInspection extends MethodInspection { + private static final Logger s_logger = + Logger.getInstance("ReadResolveAndWriteReplaceProtectedInspection "); + private final MakeProtectedFix fix = new MakeProtectedFix(); + + public String getDisplayName() { + return "'readResolve()' or 'writeReplace()' not declared 'protected'"; + } + + public String getGroupDisplayName() { + return GroupNames.SERIALIZATION_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "#ref() not declared 'protected' #loc"; + + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new ReadResolveWriteReplaceProtectedVisitor(this, inspectionManager, onTheFly); + } + + public InspectionGadgetsFix buildFix(PsiElement location) { + return fix; + } + + private static class MakeProtectedFix extends InspectionGadgetsFix { + public String getName() { + return "Make 'protected'"; + } + + public void applyFix(Project project, ProblemDescriptor descriptor) { + try { + final PsiElement methodNameToken = descriptor.getPsiElement(); + final PsiMethod method = + (PsiMethod) methodNameToken.getParent(); + final PsiModifierList modifiers = method.getModifierList(); + modifiers.setModifierProperty(PsiModifier.PUBLIC, false); + modifiers.setModifierProperty(PsiModifier.PRIVATE, false); + modifiers.setModifierProperty(PsiModifier.PROTECTED, true); + } catch (IncorrectOperationException e) { + s_logger.error(e); + } + } + } + + private static class ReadResolveWriteReplaceProtectedVisitor extends BaseInspectionVisitor { + private ReadResolveWriteReplaceProtectedVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitMethod(PsiMethod method) { + // no call to super, so it doesn't drill down + final PsiClass aClass = method.getContainingClass(); + if (aClass.isInterface() || aClass.isAnnotationType()) { + return; + } + if (!SerializationUtils.isSerializable(aClass)) { + return; + } + + if (!SerializationUtils.isReadResolve(method) && + !SerializationUtils.isWriteReplace(method)) { + return; + } + if (method.hasModifierProperty(PsiModifier.PROTECTED)) { + return; + } + registerMethodError(method); + } + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/serialization/SerialVersionUIDNotStaticFinalInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/serialization/SerialVersionUIDNotStaticFinalInspection.java new file mode 100644 index 000000000000..db7f64586dd8 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/serialization/SerialVersionUIDNotStaticFinalInspection.java @@ -0,0 +1,91 @@ +package com.siyeh.ig.serialization; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.codeInspection.ProblemDescriptor; +import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.project.Project; +import com.intellij.psi.*; +import com.intellij.util.IncorrectOperationException; +import com.siyeh.ig.*; +import com.siyeh.ig.psiutils.SerializationUtils; + +public class SerialVersionUIDNotStaticFinalInspection extends ClassInspection { + private static final Logger s_logger = Logger.getInstance("SerialVersionUIDNotStaticFinalInspection"); + private final MakeStaticFinalFix fix = new MakeStaticFinalFix(); + + public String getDisplayName() { + return "'serialVersionUID' field not declared 'static final'"; + } + + public String getGroupDisplayName() { + return GroupNames.SERIALIZATION_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "#ref field of a Serializable class is not declared 'static' and 'final' #loc "; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new SerializableDefinesSerialVersionUIDVisitor(this, inspectionManager, onTheFly); + } + + public InspectionGadgetsFix buildFix(PsiElement location) { + return fix; + } + + private static class MakeStaticFinalFix extends InspectionGadgetsFix { + public String getName() { + return "Make 'static final'"; + } + + public void applyFix(Project project, ProblemDescriptor descriptor) { + try { + final PsiElement fieldNameToken = descriptor.getPsiElement(); + final PsiField field = (PsiField) fieldNameToken.getParent(); + final PsiModifierList modifiers = field.getModifierList(); + if (!modifiers.hasModifierProperty(PsiModifier.STATIC)) { + modifiers.setModifierProperty(PsiModifier.STATIC, true); + } + if (!modifiers.hasModifierProperty(PsiModifier.FINAL)) { + modifiers.setModifierProperty(PsiModifier.FINAL, true); + } + } catch (IncorrectOperationException e) { + s_logger.error(e); + } + } + } + + 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 (isSerialVersionUID(field)) { + if (!field.hasModifierProperty(PsiModifier.STATIC) || + !field.hasModifierProperty(PsiModifier.FINAL)) { + registerFieldError(field); + } + } + } + } + + private static boolean isSerialVersionUID(PsiField field) { + final String fieldName = field.getName(); + return "serialVersionUID".equals(fieldName); + } + + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/serialization/SerializableHasSerialVersionUIDFieldInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/serialization/SerializableHasSerialVersionUIDFieldInspection.java new file mode 100644 index 000000000000..e07b96698158 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/serialization/SerializableHasSerialVersionUIDFieldInspection.java @@ -0,0 +1,82 @@ +package com.siyeh.ig.serialization; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.psi.PsiClass; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiField; +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; +import com.siyeh.ig.ui.SingleCheckboxOptionsPanel; + +import javax.swing.*; + +public class SerializableHasSerialVersionUIDFieldInspection extends ClassInspection { + public boolean m_ignoreSerializableDueToInheritance = true; + + public String getDisplayName() { + return "Serializable class without serialVersionUID"; + } + + public String getGroupDisplayName() { + return GroupNames.SERIALIZATION_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "#ref doesn't define a serialVersionUID field #loc"; + } + + public JComponent createOptionsPanel() { + return new SingleCheckboxOptionsPanel("Ignore classes serializable due to inheritance", + this, "m_ignoreSerializableDueToInheritance"); + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new SerializableDefinesSerialVersionUIDVisitor(this, inspectionManager, onTheFly); + } + + private 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 (m_ignoreSerializableDueToInheritance) { + if (!SerializationUtils.isDirectlySerializable(aClass)) { + return; + } + } else { + if (!SerializationUtils.isSerializable(aClass)) { + return; + } + } + final PsiField[] fields = aClass.getFields(); + boolean hasSerialVersionUID = false; + for (int i = 0; i < fields.length; i++) { + final PsiField field = fields[i]; + if (isSerialVersionUID(field)) { + hasSerialVersionUID = true; + } + } + if (hasSerialVersionUID) { + return; + } + registerClassError(aClass); + } + + private boolean isSerialVersionUID(PsiField field) { + final String methodName = field.getName(); + return "serialVersionUID".equals(methodName); + } + + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/serialization/SerializableHasSerializationMethodsInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/serialization/SerializableHasSerializationMethodsInspection.java new file mode 100644 index 000000000000..3d0ca76ec53b --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/serialization/SerializableHasSerializationMethodsInspection.java @@ -0,0 +1,96 @@ +package com.siyeh.ig.serialization; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.psi.PsiClass; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiMethod; +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; +import com.siyeh.ig.ui.SingleCheckboxOptionsPanel; + +import javax.swing.*; + +public class SerializableHasSerializationMethodsInspection extends ClassInspection { + public boolean m_ignoreSerializableDueToInheritance = false; + + public String getDisplayName() { + return "Serializable class without 'readObject()' and 'writeObject()'"; + } + + public String getGroupDisplayName() { + return GroupNames.SERIALIZATION_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + final PsiClass aClass = (PsiClass) location.getParent(); + final PsiMethod[] methods = aClass.getMethods(); + boolean hasReadObject = false; + boolean hasWriteObject = false; + for (int i = 0; i < methods.length; i++) { + final PsiMethod method = methods[i]; + if (SerializationUtils.isReadObject(method)) { + hasReadObject = true; + } else if (SerializationUtils.isWriteObject(method)) { + hasWriteObject = true; + } + } + if (!hasReadObject && !hasWriteObject) { + return "#ref doesn't define readObject() or writeObject() #loc"; + } else if (hasReadObject) { + return "#ref doesn't define writeObject() #loc"; + } else { + return "#ref doesn't define readObject() #loc"; + } + } + + public JComponent createOptionsPanel() { + return new SingleCheckboxOptionsPanel("Ignore classes serializable due to inheritance", + this, "m_ignoreSerializableDueToInheritance"); + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new SerializableDefinesMethodsVisitor(this, inspectionManager, onTheFly); + } + + private class SerializableDefinesMethodsVisitor extends BaseInspectionVisitor { + private SerializableDefinesMethodsVisitor(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 (m_ignoreSerializableDueToInheritance) { + if (!SerializationUtils.isDirectlySerializable(aClass)) { + return; + } + } else { + if (!SerializationUtils.isSerializable(aClass)) { + return; + } + } + final PsiMethod[] methods = aClass.getMethods(); + boolean hasReadObject = false; + boolean hasWriteObject = false; + for (int i = 0; i < methods.length; i++) { + final PsiMethod method = methods[i]; + if (SerializationUtils.isReadObject(method)) { + hasReadObject = true; + } else if (SerializationUtils.isWriteObject(method)) { + hasWriteObject = true; + } + } + if (hasWriteObject && hasReadObject) { + return; + } + registerClassError(aClass); + } + + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/serialization/SerializableInnerClassHasSerialVersionUIDFieldInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/serialization/SerializableInnerClassHasSerialVersionUIDFieldInspection.java new file mode 100644 index 000000000000..b760e868c58f --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/serialization/SerializableInnerClassHasSerialVersionUIDFieldInspection.java @@ -0,0 +1,91 @@ +package com.siyeh.ig.serialization; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.psi.PsiClass; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiField; +import com.intellij.psi.PsiModifier; +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; +import com.siyeh.ig.ui.SingleCheckboxOptionsPanel; + +import javax.swing.*; + +public class SerializableInnerClassHasSerialVersionUIDFieldInspection extends ClassInspection { + public boolean m_ignoreSerializableDueToInheritance = true; + + public String getDisplayName() { + return "Serializable non-static inner class without serialVersionUID"; + } + + public String getGroupDisplayName() { + return GroupNames.SERIALIZATION_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "Inner class #ref doesn't define a serialVersionUID field #loc"; + } + + public JComponent createOptionsPanel() { + return new SingleCheckboxOptionsPanel("Ignore classes serializable due to inheritance", + this, "m_ignoreSerializableDueToInheritance"); + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new SerializableDefinesSerialVersionUIDVisitor(this, inspectionManager, onTheFly); + } + + private 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; + } + final PsiClass containingClass = aClass.getContainingClass(); + if(containingClass==null) + { + return; + } + if(aClass.hasModifierProperty(PsiModifier.STATIC)) + { + return; + } + if (m_ignoreSerializableDueToInheritance) { + if (!SerializationUtils.isDirectlySerializable(aClass)) { + return; + } + } else { + if (!SerializationUtils.isSerializable(aClass)) { + return; + } + } + if (hasSerialVersionUIDField(aClass)) { + return; + } + registerClassError(aClass); + } + + private boolean hasSerialVersionUIDField(PsiClass aClass) { + final PsiField[] fields = aClass.getFields(); + boolean hasSerialVersionUID = false; + for (int i = 0; i < fields.length; i++) { + final String fieldName = fields[i].getName(); + if ("serialVersionUID".equals(fieldName)) { + hasSerialVersionUID = true; + } + } + return hasSerialVersionUID; + } + + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/serialization/SerializableInnerClassWithNonSerializableOuterClassInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/serialization/SerializableInnerClassWithNonSerializableOuterClassInspection.java new file mode 100644 index 000000000000..c6fc81ea130c --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/serialization/SerializableInnerClassWithNonSerializableOuterClassInspection.java @@ -0,0 +1,78 @@ +package com.siyeh.ig.serialization; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.psi.PsiClass; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiModifier; +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; +import com.siyeh.ig.ui.SingleCheckboxOptionsPanel; + +import javax.swing.*; + +public class SerializableInnerClassWithNonSerializableOuterClassInspection extends ClassInspection { + public boolean m_ignoreSerializableDueToInheritance = true; + + public String getDisplayName() { + return "Serializable non-static inner class without non-Serializable outer class"; + } + + public String getGroupDisplayName() { + return GroupNames.SERIALIZATION_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "Inner class #ref is serializable while it's outer class is not #loc"; + } + + public JComponent createOptionsPanel() { + return new SingleCheckboxOptionsPanel("Ignore classes serializable due to inheritance", + this, "m_ignoreSerializableDueToInheritance"); + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new SerializableDefinesSerialVersionUIDVisitor(this, inspectionManager, onTheFly); + } + + private 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; + } + final PsiClass containingClass = aClass.getContainingClass(); + if(containingClass==null) + { + return; + } + if(aClass.hasModifierProperty(PsiModifier.STATIC)) + { + return; + } + if (m_ignoreSerializableDueToInheritance) { + if (!SerializationUtils.isDirectlySerializable(aClass)) { + return; + } + } else { + if (!SerializationUtils.isSerializable(aClass)) { + return; + } + } + if (SerializationUtils.isSerializable(containingClass)) { + return; + } + registerClassError(aClass); + } + + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/serialization/SerializableWithUnconstructableAncestorInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/serialization/SerializableWithUnconstructableAncestorInspection.java new file mode 100644 index 000000000000..6b945c6a266a --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/serialization/SerializableWithUnconstructableAncestorInspection.java @@ -0,0 +1,91 @@ +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; + +import java.util.Set; +import java.util.HashSet; + +public class SerializableWithUnconstructableAncestorInspection extends ClassInspection { + + public String getDisplayName() { + return "Serializable class with unconstructable ancestor"; + } + + public String getGroupDisplayName() { + return GroupNames.SERIALIZATION_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + final PsiClass aClass = (PsiClass) location.getParent(); + PsiClass ancestor = aClass.getSuperClass(); + while (SerializationUtils.isSerializable(ancestor)) { + ancestor = ancestor.getSuperClass(); + } + return "#ref has an non-serializable ancestor " + ancestor.getName() + " without a no-arg constructor #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new SerializableWithUnconstructableAncestorVisitor(this, inspectionManager, onTheFly); + } + + private static class SerializableWithUnconstructableAncestorVisitor extends BaseInspectionVisitor { + private SerializableWithUnconstructableAncestorVisitor(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; + } + PsiClass ancestor = aClass.getSuperClass(); + final Set visitedClasses = new HashSet(); + while (ancestor != null && SerializationUtils.isSerializable(ancestor)) { + ancestor = ancestor.getSuperClass(); + if (!visitedClasses.add(ancestor)) { + return; + } + } + if (ancestor == null) { + return; // can't happen, since Object isn't serializable, + //// but I don't trust the PSI as far as I can throw it + } + if (classHasNoArgConstructor(ancestor)) { + return; + } + registerClassError(aClass); + } + + private static boolean classHasNoArgConstructor(PsiClass ancestor) { + boolean hasConstructor = false; + boolean hasNoArgConstructor = false; + final PsiMethod[] methods = ancestor.getMethods(); + for (int i = 0; i < methods.length; i++) { + final PsiMethod method = methods[i]; + if (method.isConstructor()) { + hasConstructor = true; + final PsiParameterList params = method.getParameterList(); + if (params != null) { + if (params.getParameters().length == 0 + && method.hasModifierProperty(PsiModifier.PUBLIC)) { + hasNoArgConstructor = true; + } + } + } + + } + return hasNoArgConstructor || !hasConstructor; + } + } +} \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/serialization/TransientFieldInNonSerializableClassInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/serialization/TransientFieldInNonSerializableClassInspection.java new file mode 100644 index 000000000000..30b6ea23011d --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/serialization/TransientFieldInNonSerializableClassInspection.java @@ -0,0 +1,76 @@ +package com.siyeh.ig.serialization; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.codeInspection.ProblemDescriptor; +import com.intellij.openapi.project.Project; +import com.intellij.psi.*; +import com.siyeh.ig.*; +import com.siyeh.ig.psiutils.SerializationUtils; + +public class TransientFieldInNonSerializableClassInspection extends ClassInspection { + private final TransientFieldInNonSerializableClassFix fix = new TransientFieldInNonSerializableClassFix(); + + public String getDisplayName() { + return "Transient field in non-serializable class"; + } + + public String getGroupDisplayName() { + return GroupNames.SERIALIZATION_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + final PsiModifierList fieldModifierList = (PsiModifierList) location.getParent(); + final PsiField field = (PsiField) fieldModifierList.getParent(); + return "Field " + field.getName() + " is marked '#ref', in non-Serializable class #loc "; + } + + public InspectionGadgetsFix buildFix(PsiElement location) { + return fix; + } + + private static class TransientFieldInNonSerializableClassFix extends InspectionGadgetsFix { + public String getName() { + return "Remove 'transient'"; + } + + public void applyFix(Project project, ProblemDescriptor descriptor) { + final PsiElement transientModifier = descriptor.getPsiElement(); + deleteElement(transientModifier); + } + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new TransientFieldInNonSerializableClassVisitor(this, inspectionManager, onTheFly); + } + + private static class TransientFieldInNonSerializableClassVisitor extends BaseInspectionVisitor { + private boolean m_inClass = false; + + private TransientFieldInNonSerializableClassVisitor(BaseInspection inspection, + InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitClass(PsiClass aClass) { + final boolean wasInClass = m_inClass; + if (!m_inClass) { + + m_inClass = true; + super.visitClass(aClass); + } + m_inClass = wasInClass; + } + + public void visitField(PsiField field) { + if (!field.hasModifierProperty(PsiModifier.TRANSIENT)) { + return; + } + final PsiClass aClass = field.getContainingClass(); + if (SerializationUtils.isSerializable(aClass)) { + return; + } + registerModifierError(PsiModifier.TRANSIENT, field); + } + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/style/CStyleArrayDeclarationInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/style/CStyleArrayDeclarationInspection.java new file mode 100644 index 000000000000..22d963f25238 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/style/CStyleArrayDeclarationInspection.java @@ -0,0 +1,85 @@ +package com.siyeh.ig.style; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.codeInspection.ProblemDescriptor; +import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.project.Project; +import com.intellij.psi.*; +import com.intellij.util.IncorrectOperationException; +import com.siyeh.ig.*; + +public class CStyleArrayDeclarationInspection extends ClassInspection { + private final CStyleArrayDeclarationFix cStyleArrayDeclarationFix = new CStyleArrayDeclarationFix(); + + public String getDisplayName() { + return "C-style array declaration"; + } + + public String getGroupDisplayName() { + return GroupNames.STYLE_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "C-style array declaration #ref #loc"; + } + + public InspectionGadgetsFix buildFix(PsiElement location) { + return cStyleArrayDeclarationFix; + } + + private static class CStyleArrayDeclarationFix extends InspectionGadgetsFix { + public String getName() { + return "Replace with Java-style array declaration"; + } + + public void applyFix(Project project, ProblemDescriptor descriptor) { + final PsiElement nameElement = descriptor.getPsiElement(); + final PsiVariable var = (PsiVariable) nameElement.getParent(); + try { + var.normalizeDeclaration(); + } catch (IncorrectOperationException e) { + final Class aClass = getClass(); + final String className = aClass.getName(); + final Logger logger = Logger.getInstance(className); + logger.error(e); + } + } + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new CStyleArrayDeclarationVisitor(this, inspectionManager, onTheFly); + } + + private static class CStyleArrayDeclarationVisitor extends BaseInspectionVisitor { + private boolean m_inClass = false; + + private CStyleArrayDeclarationVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitClass(PsiClass aClass) { + final boolean wasInClass = m_inClass; + if (!m_inClass) { + + m_inClass = true; + super.visitClass(aClass); + } + m_inClass = wasInClass; + } + + public void visitVariable(PsiVariable var) { + super.visitVariable(var); + final PsiTypeElement typeElement = var.getTypeElement(); + if (typeElement == null) { + return; // Could be true for enum constants. + } + final PsiType elementType = typeElement.getType(); + final PsiType declared = var.getType(); + if (elementType.equals(declared)) { + return; + } + registerVariableError(var); + } + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/style/ConstantOnLHSOfComparisonInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/style/ConstantOnLHSOfComparisonInspection.java new file mode 100644 index 000000000000..6a7bb2f3f621 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/style/ConstantOnLHSOfComparisonInspection.java @@ -0,0 +1,90 @@ +package com.siyeh.ig.style; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.codeInspection.ProblemDescriptor; +import com.intellij.openapi.project.Project; +import com.intellij.psi.PsiBinaryExpression; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiExpression; +import com.intellij.psi.PsiJavaToken; +import com.intellij.psi.util.PsiUtil; +import com.siyeh.ig.*; +import com.siyeh.ig.psiutils.ComparisonUtils; + +public class ConstantOnLHSOfComparisonInspection extends ExpressionInspection { + private final SwapComparisonFix fix = new SwapComparisonFix(); + + public String getDisplayName() { + return "Constant on left side of comparison"; + } + + public String getGroupDisplayName() { + return GroupNames.STYLE_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "#ref: constant on left side of comparison #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new ConstantOnLHSOfComparisonVisitor(this, inspectionManager, onTheFly); + } + + public InspectionGadgetsFix buildFix(PsiElement location) { + return fix; + } + + private static class SwapComparisonFix extends InspectionGadgetsFix { + public String getName() { + return "Flip comparison"; + } + + public void applyFix(Project project, ProblemDescriptor descriptor) { + final PsiBinaryExpression expression = (PsiBinaryExpression) descriptor.getPsiElement(); + final PsiExpression rhs = expression.getROperand(); + final PsiExpression lhs = expression.getLOperand(); + final PsiJavaToken operation = expression.getOperationSign(); + final String sign = operation.getText(); + final String flippedSign = ComparisonUtils.getFlippedComparison(sign); + final String rhsText = rhs.getText(); + final String lhsText = lhs.getText(); + replaceExpression(project, expression, + rhsText + ' ' + flippedSign + ' ' + lhsText); + + } + + } + + private static class ConstantOnLHSOfComparisonVisitor extends BaseInspectionVisitor { + private ConstantOnLHSOfComparisonVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitBinaryExpression(PsiBinaryExpression expression) { + super.visitBinaryExpression(expression); + final PsiJavaToken sign = expression.getOperationSign(); + if (sign == null) { + return; + } + final String operator = sign.getText(); + if (!ComparisonUtils.isComparison(operator)) { + return; + } + final PsiExpression lhs = expression.getLOperand(); + if (lhs == null) { + return; + } + final PsiExpression rhs = expression.getROperand(); + if (rhs == null) { + return; + } + if (!PsiUtil.isConstantExpression(lhs) + || PsiUtil.isConstantExpression(rhs)) { + return; + } + registerError(expression); + + } + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/style/ConstantOnRHSOfComparisonInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/style/ConstantOnRHSOfComparisonInspection.java new file mode 100644 index 000000000000..a96cf75b36e4 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/style/ConstantOnRHSOfComparisonInspection.java @@ -0,0 +1,87 @@ +package com.siyeh.ig.style; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.codeInspection.ProblemDescriptor; +import com.intellij.openapi.project.Project; +import com.intellij.psi.PsiBinaryExpression; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiExpression; +import com.intellij.psi.PsiJavaToken; +import com.intellij.psi.util.PsiUtil; +import com.siyeh.ig.*; +import com.siyeh.ig.psiutils.ComparisonUtils; + +public class ConstantOnRHSOfComparisonInspection extends ExpressionInspection { + private final SwapComparisonFix fix = new SwapComparisonFix(); + + public String getDisplayName() { + return "Constant on right side of comparison"; + } + + public String getGroupDisplayName() { + return GroupNames.STYLE_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "#ref: constant on right side of comparison #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new ConstantOnRHSOfComparisonVisitor(this, inspectionManager, onTheFly); + } + + public InspectionGadgetsFix buildFix(PsiElement location) { + return fix; + } + + private static class SwapComparisonFix extends InspectionGadgetsFix { + public String getName() { + return "Flip comparison"; + } + + public void applyFix(Project project, ProblemDescriptor descriptor) { + final PsiBinaryExpression expression = (PsiBinaryExpression) descriptor.getPsiElement(); + final PsiExpression rhs = expression.getROperand(); + final PsiExpression lhs = expression.getLOperand(); + final PsiJavaToken sign = expression.getOperationSign(); + final String signText = sign.getText(); + final String rhsText = rhs.getText(); + final String flippedComparison = ComparisonUtils.getFlippedComparison(signText); + final String lhsText = lhs.getText(); + replaceExpression(project, expression, + rhsText + ' ' + flippedComparison + ' ' + lhsText); + } + } + + private static class ConstantOnRHSOfComparisonVisitor extends BaseInspectionVisitor { + private ConstantOnRHSOfComparisonVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitBinaryExpression(PsiBinaryExpression expression) { + super.visitBinaryExpression(expression); + final PsiJavaToken sign = expression.getOperationSign(); + if (sign == null) { + return; + } + final String operator = sign.getText(); + if (!ComparisonUtils.isComparison(operator)) { + return; + } + final PsiExpression lhs = expression.getLOperand(); + if (lhs == null) { + return; + } + final PsiExpression rhs = expression.getROperand(); + if (rhs == null) { + return; + } + if (!PsiUtil.isConstantExpression(rhs) || + PsiUtil.isConstantExpression(lhs)) { + return; + } + registerError(expression); + } + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/style/LiteralAsArgToStringEqualsInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/style/LiteralAsArgToStringEqualsInspection.java new file mode 100644 index 000000000000..7a64a505c8c8 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/style/LiteralAsArgToStringEqualsInspection.java @@ -0,0 +1,102 @@ +package com.siyeh.ig.style; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.codeInspection.ProblemDescriptor; +import com.intellij.openapi.project.Project; +import com.intellij.psi.*; +import com.siyeh.ig.*; +import com.siyeh.ig.psiutils.ParenthesesUtils; +import com.siyeh.ig.psiutils.TypeUtils; + +public class LiteralAsArgToStringEqualsInspection extends ExpressionInspection { + private final SwapEqualsFix swapEqualsFix = new SwapEqualsFix(); + + public String getDisplayName() { + return "expression.equals(\"literal\") rather than \"literal\".equals(expression)"; + } + + public String getGroupDisplayName() { + return GroupNames.STYLE_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + final PsiMethodCallExpression expression = (PsiMethodCallExpression) location; + final PsiReferenceExpression methodExpression = expression.getMethodExpression(); + final String methodName = methodExpression.getReferenceName(); + return "#ref: String literal is argument of ." + methodName + "(), instead of the target."; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new LiteralAsArgToEqualsVisitor(this, inspectionManager, onTheFly); + } + + public InspectionGadgetsFix buildFix(PsiElement location) { + return swapEqualsFix; + } + + private static class SwapEqualsFix extends InspectionGadgetsFix { + public String getName() { + return "Flip .equals()"; + } + + public void applyFix(Project project, ProblemDescriptor descriptor) { + final PsiMethodCallExpression expression = (PsiMethodCallExpression) descriptor.getPsiElement(); + final PsiReferenceExpression methodExpression = expression.getMethodExpression(); + final PsiExpression target = methodExpression.getQualifierExpression(); + final String methodName = methodExpression.getReferenceName(); + final PsiExpressionList argumentList = expression.getArgumentList(); + final PsiExpression arg = argumentList.getExpressions()[0]; + + final PsiExpression strippedTarget = ParenthesesUtils.stripParentheses(target); + final PsiExpression strippedArg = ParenthesesUtils.stripParentheses(arg); + final String callString; + if (ParenthesesUtils.getPrecendence(strippedArg) > + ParenthesesUtils.METHOD_CALL_PRECEDENCE) { + callString = '(' + strippedArg.getText() + ")." + methodName + '(' + strippedTarget.getText() + ')'; + } else { + callString = strippedArg.getText() + '.' + methodName + '(' + strippedTarget.getText() + ')'; + } + replaceExpression(project, expression, callString); + } + } + + private static class LiteralAsArgToEqualsVisitor extends BaseInspectionVisitor { + private LiteralAsArgToEqualsVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitMethodCallExpression(PsiMethodCallExpression expression) { + super.visitMethodCallExpression(expression); + final PsiReferenceExpression methodExpression = expression.getMethodExpression(); + final String methodName = methodExpression.getReferenceName(); + if (!"equals".equals(methodName) && !"equalsIgnoreCase".equals(methodName)) { + return; + } + final PsiExpressionList argList = expression.getArgumentList(); + if (argList == null) { + return; + } + final PsiExpression[] args = argList.getExpressions(); + if (args.length != 1) { + return; + } + final PsiExpression arg = args[0]; + final PsiType argType = arg.getType(); + if (argType == null) { + return; + } + if (!(arg instanceof PsiLiteralExpression)) { + return; + } + if (!TypeUtils.isJavaLangString(argType)) { + return; + } + final PsiExpression target = methodExpression.getQualifierExpression(); + if (target instanceof PsiLiteralExpression) { + return; + } + registerError(expression); + } + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/style/MissortedModifiersInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/style/MissortedModifiersInspection.java new file mode 100644 index 000000000000..77a19961d002 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/style/MissortedModifiersInspection.java @@ -0,0 +1,193 @@ +package com.siyeh.ig.style; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.codeInspection.ProblemDescriptor; +import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.project.Project; +import com.intellij.psi.*; +import com.intellij.util.IncorrectOperationException; +import com.siyeh.ig.*; + +import java.util.*; + +public class MissortedModifiersInspection extends ClassInspection { + private static final Logger s_logger = Logger.getInstance("MissortedModifiersInspection"); + + private static final int NUM_MODIFIERS = 11; + private static final Map s_modifierOrder = new HashMap(NUM_MODIFIERS); + private final SortModifiersFix fix = new SortModifiersFix(); + + static { + s_modifierOrder.put("public", new Integer(0)); + s_modifierOrder.put("protected", new Integer(1)); + s_modifierOrder.put("private", new Integer(2)); + s_modifierOrder.put("static", new Integer(3)); + s_modifierOrder.put("abstract", new Integer(4)); + s_modifierOrder.put("final", new Integer(5)); + s_modifierOrder.put("transient", new Integer(6)); + s_modifierOrder.put("volatile", new Integer(7)); + s_modifierOrder.put("synchronized", new Integer(8)); + s_modifierOrder.put("native", new Integer(9)); + s_modifierOrder.put("strictfp", new Integer(10)); + } + + public String getDisplayName() { + return "Missorted modifers"; + } + + public String getGroupDisplayName() { + return GroupNames.STYLE_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "Missorted modifers '#ref' #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new MissortedModifiersVisitor(this, inspectionManager, onTheFly); + } + + public InspectionGadgetsFix buildFix(PsiElement location) { + return fix; + } + + private static class SortModifiersFix extends InspectionGadgetsFix { + public String getName() { + return "Sort modifers"; + } + + public void applyFix(Project project, ProblemDescriptor descriptor) { + final PsiModifierList modifierList = (PsiModifierList) descriptor.getPsiElement(); + final List simpleModifiers = new ArrayList(); + final PsiElement[] children = modifierList.getChildren(); + for (int i = 0; i < children.length; i++) { + final PsiElement child = children[i]; + + if (child instanceof PsiJavaToken) { + simpleModifiers.add(child.getText()); + } + if (child instanceof PsiAnnotation) { + } + } + Collections.sort(simpleModifiers, new ModifierComparator()); + clearModifiers(simpleModifiers, modifierList); + addModifiersInOrder(simpleModifiers, modifierList); + } + + private static void addModifiersInOrder(List modifiers, + PsiModifierList modifierList) { + for (Iterator iterator = modifiers.iterator(); iterator.hasNext();) { + final String modifier = (String) iterator.next(); + try { + modifierList.setModifierProperty(modifier, true); + } catch (IncorrectOperationException e) { + s_logger.error(e); + } + } + } + + private static void clearModifiers(List modifiers, + PsiModifierList modifierList) { + for (Iterator iterator = modifiers.iterator(); iterator.hasNext();) { + final String modifier = (String) iterator.next(); + try { + modifierList.setModifierProperty(modifier, false); + } catch (IncorrectOperationException e) { + s_logger.error(e); + } + } + } + } + + private static class MissortedModifiersVisitor + extends BaseInspectionVisitor { + private boolean m_isInClass = false; + + private MissortedModifiersVisitor(BaseInspection inspection, + InspectionManager inspectionManager, + boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitClass(PsiClass aClass) { + if (!m_isInClass) { + m_isInClass = true; + super.visitClass(aClass); + checkForMissortedModifiers(aClass); + m_isInClass = false; + } + } + + public void visitClassInitializer(PsiClassInitializer initializer) { + super.visitClassInitializer(initializer); + checkForMissortedModifiers(initializer); + } + + public void visitLocalVariable(PsiLocalVariable variable) { + super.visitLocalVariable(variable); + checkForMissortedModifiers(variable); + } + + public void visitParameter(PsiParameter parameter) { + super.visitParameter(parameter); + checkForMissortedModifiers(parameter); + } + + public void visitMethod(PsiMethod method) { + super.visitMethod(method); + checkForMissortedModifiers(method); + } + + public void visitField(PsiField field) { + super.visitField(field); + checkForMissortedModifiers(field); + } + + private void checkForMissortedModifiers(PsiModifierListOwner listOwner) { + final PsiModifierList modifierList = listOwner.getModifierList(); + if (isModifierListMissorted(modifierList)) { + registerError(modifierList); + } + } + + private static boolean isModifierListMissorted(PsiModifierList modifierList) { + if (modifierList == null) { + return false; + } + + final List simpleModifiers = new ArrayList(); + final PsiElement[] children = modifierList.getChildren(); + for (int i = 0; i < children.length; i++) { + final PsiElement child = children[i]; + + if (child instanceof PsiJavaToken) { + simpleModifiers.add(child); + } + if (child instanceof PsiAnnotation) { + if (simpleModifiers.size() != 0) { + return true; //things aren't in order, since annotations come first + } + } + } + int currentModifierIndex = -1; + + for (Iterator iterator = simpleModifiers.iterator(); + iterator.hasNext();) { + final PsiJavaToken token = (PsiJavaToken) iterator.next(); + final String text = token.getText(); + final Integer modifierIndex = (Integer) s_modifierOrder.get(text); + if (modifierIndex == null) { + return false; + } + final int nextModifierIndex = modifierIndex.intValue(); + if (currentModifierIndex >= nextModifierIndex) { + return true; + } + currentModifierIndex = nextModifierIndex; + } + return false; + } + + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/style/MultipleDeclarationInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/style/MultipleDeclarationInspection.java new file mode 100644 index 000000000000..b8d425db3240 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/style/MultipleDeclarationInspection.java @@ -0,0 +1,91 @@ +package com.siyeh.ig.style; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.psi.*; +import com.siyeh.ig.*; +import com.siyeh.ig.fixes.NormalizeDeclarationFix; + +public class MultipleDeclarationInspection extends VariableInspection { + private final NormalizeDeclarationFix fix = new NormalizeDeclarationFix(); + + public String getDisplayName() { + return "Multiple variables in one declaration"; + } + + public String getGroupDisplayName() { + return GroupNames.STYLE_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "Multiple variables in one declaration #loc"; + } + + public InspectionGadgetsFix buildFix(PsiElement location) { + return fix; + } + + protected boolean buildQuickFixesOnlyForBatchErrors() { + return true; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new MultipleDeclarationVisitor(this, inspectionManager, onTheFly); + } + + private static class MultipleDeclarationVisitor extends BaseInspectionVisitor { + private MultipleDeclarationVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitDeclarationStatement(PsiDeclarationStatement statement) { + super.visitDeclarationStatement(statement); + if (statement.getDeclaredElements().length <= 1) { + return; + } + final PsiElement parent = statement.getParent(); + if (parent instanceof PsiForStatement) { + final PsiForStatement forStatement = (PsiForStatement) parent; + final PsiStatement initialization = forStatement.getInitialization(); + if (statement.equals(initialization)) { + return; + } + } + final PsiElement[] declaredVars = statement.getDeclaredElements(); + for (int i = 1; i < declaredVars.length; i++) { //skip the first one; + final PsiLocalVariable var = (PsiLocalVariable) declaredVars[i]; + registerVariableError(var); + } + } + + public void visitField(PsiField field) { + super.visitField(field); + if (childrenContainTypeElement(field)) { + return; + } + final PsiClass containingClass = field.getContainingClass(); + if (containingClass != null && containingClass.isEnum()) { + final PsiType type = field.getType(); + if (type != null) { + final String text = type.getCanonicalText(); + final String className = containingClass.getQualifiedName(); + if (text.equals(className)) { + return; + } + } + } + registerFieldError(field); + } + + public static boolean childrenContainTypeElement(PsiElement field) { + final PsiElement[] children = field.getChildren(); + for (int i = 0; i < children.length; i++) { + if (children[i] instanceof PsiTypeElement) { + return true; + } + } + return false; + } + + + } +} \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/style/MultipleTypedDeclarationInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/style/MultipleTypedDeclarationInspection.java new file mode 100644 index 000000000000..cc8b77ec0ae4 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/style/MultipleTypedDeclarationInspection.java @@ -0,0 +1,125 @@ +package com.siyeh.ig.style; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.psi.*; +import com.intellij.psi.util.PsiTreeUtil; +import com.siyeh.ig.*; +import com.siyeh.ig.fixes.NormalizeDeclarationFix; + +import java.util.ArrayList; +import java.util.List; + +public class MultipleTypedDeclarationInspection extends VariableInspection { + private final NormalizeDeclarationFix fix = new NormalizeDeclarationFix(); + + public String getDisplayName() { + return "Variables of different types in one declaration"; + } + + public String getGroupDisplayName() { + return GroupNames.STYLE_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "Variables of different types in one declaration #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new MultiplyTypedDeclarationVisitor(this, inspectionManager, + onTheFly); + } + + public InspectionGadgetsFix buildFix(PsiElement location) { + return fix; + } + + protected boolean buildQuickFixesOnlyForBatchErrors() { + return true; + } + + private static class MultiplyTypedDeclarationVisitor + extends BaseInspectionVisitor { + private MultiplyTypedDeclarationVisitor(BaseInspection inspection, + InspectionManager inspectionManager, + boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitDeclarationStatement(PsiDeclarationStatement statement) { + super.visitDeclarationStatement(statement); + final PsiElement[] elements = statement.getDeclaredElements(); + if (elements.length > 1) { + final PsiType baseType = ((PsiVariable) elements[0]).getType(); + boolean hasMultipleTypes = false; + for (int i = 1; i < elements.length; i++) { + final PsiLocalVariable var = (PsiLocalVariable) elements[i]; + final PsiType variableType = var.getType(); + if (!variableType.equals(baseType)) { + hasMultipleTypes = true; + } + } + if (hasMultipleTypes) { + for (int i = 1; i < elements.length; i++) { + final PsiLocalVariable var = (PsiLocalVariable) elements[i]; + registerVariableError(var); + } + } + } + } + + public void visitField(PsiField field) { + super.visitField(field); + if (!childrenContainTypeElement(field)) { + return; + } + final List fields = getSiblingFields(field); + + if (fields.size() > 1) { + final PsiType baseType = ((PsiVariable) fields.get(0)).getType(); + boolean hasMultipleTypes = false; + for (int i = 1; i < fields.size(); i++) { + final PsiField var = (PsiField) fields.get(i); + final PsiType varType = var.getType(); + if (!varType.equals(baseType)) { + hasMultipleTypes = true; + } + } + if (hasMultipleTypes) { + for (int i = 1; i < fields.size(); i++) { + final PsiField var = (PsiField) fields.get(i); + registerVariableError(var); + } + } + } + } + + public static List getSiblingFields(PsiField field) { + final List out = new ArrayList(5); + out.add(field); + PsiField nextfield = + (PsiField) PsiTreeUtil.getNextSiblingOfType(field, + PsiField.class); + while (nextfield != null && + nextfield.getTypeElement().equals(field.getTypeElement())) { + out.add(nextfield); + nextfield = + (PsiField) PsiTreeUtil.getNextSiblingOfType(nextfield, + PsiField.class); + } + + return out; + } + + public static boolean childrenContainTypeElement(PsiElement field) { + final PsiElement[] children = field.getChildren(); + for (int i = 0; i < children.length; i++) { + if (children[i] instanceof PsiTypeElement) { + return true; + } + } + return false; + } + + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/style/ReturnThisInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/style/ReturnThisInspection.java new file mode 100644 index 000000000000..c4ddc4e0ba98 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/style/ReturnThisInspection.java @@ -0,0 +1,53 @@ +package com.siyeh.ig.style; + +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 ReturnThisInspection extends ExpressionInspection { + + public String getDisplayName() { + return "Return of 'this'"; + } + + public String getGroupDisplayName() { + return GroupNames.STYLE_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "Return of '#ref' #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new ReturnThisVisitor(this, inspectionManager, onTheFly); + } + + private static class ReturnThisVisitor extends BaseInspectionVisitor { + private ReturnThisVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + + public void visitThisExpression(PsiThisExpression thisValue) { + super.visitThisExpression(thisValue); + if (thisValue.getQualifier() != null) { + return; + } + PsiElement parent = thisValue.getParent(); + while (parent != null && + (parent instanceof PsiParenthesizedExpression || + parent instanceof PsiConditionalExpression || + parent instanceof PsiTypeCastExpression)) { + parent = parent.getParent(); + } + if (parent == null || !(parent instanceof PsiReturnStatement)) { + return; + } + registerError(thisValue); + } + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/style/UnnecessarilyQualifiedStaticUsageInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/style/UnnecessarilyQualifiedStaticUsageInspection.java new file mode 100644 index 000000000000..22a354032840 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/style/UnnecessarilyQualifiedStaticUsageInspection.java @@ -0,0 +1,218 @@ +package com.siyeh.ig.style; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.codeInspection.ProblemDescriptor; +import com.intellij.openapi.project.Project; +import com.intellij.psi.*; +import com.intellij.psi.util.PsiTreeUtil; +import com.siyeh.ig.*; +import com.siyeh.ig.psiutils.ClassUtils; + +import javax.swing.JComponent; +import javax.swing.JPanel; +import javax.swing.JCheckBox; +import javax.swing.ButtonModel; +import javax.swing.event.ChangeListener; +import javax.swing.event.ChangeEvent; +import java.awt.GridBagLayout; +import java.awt.GridBagConstraints; + +public class UnnecessarilyQualifiedStaticUsageInspection extends ExpressionInspection { + public boolean m_ignoreStaticFieldAccesses = false; + public boolean m_ignoreStaticMethodCalls = false; + private final UnnecessarilyQualifiedStaticCallFix fix = new UnnecessarilyQualifiedStaticCallFix(); + + public String getDisplayName() { + return "Unnecessarily qualified static usage"; + } + + public String getGroupDisplayName() { + return GroupNames.STYLE_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + final PsiElement parent = location.getParent(); + if (parent instanceof PsiMethodCallExpression) { + return "Unnecessarily qualified static method call '#ref()' #loc"; + } else { + return "Unnecessarily qualified static field access '#ref' #loc"; + } + } + + public JComponent createOptionsPanel() { + final JPanel panel = new JPanel(new GridBagLayout()); + final JCheckBox ignoreFieldAccessesCheckBox = new JCheckBox("Ignore unnecessarily qualified field accesses", + m_ignoreStaticFieldAccesses); + final ButtonModel ignoreFieldAccessesModel = ignoreFieldAccessesCheckBox.getModel(); + ignoreFieldAccessesModel.addChangeListener(new ChangeListener() { + public void stateChanged(ChangeEvent e) { + m_ignoreStaticFieldAccesses = ignoreFieldAccessesModel.isSelected(); + } + }); + final JCheckBox ignoreMethodCallsCheckBox = new JCheckBox("Ignore unnecessarily qualified method calls", + m_ignoreStaticMethodCalls); + final ButtonModel ignoreMethodCallsModel = ignoreMethodCallsCheckBox.getModel(); + ignoreMethodCallsModel.addChangeListener(new ChangeListener() { + public void stateChanged(ChangeEvent e) { + m_ignoreStaticMethodCalls = ignoreMethodCallsModel.isSelected(); + } + }); + final GridBagConstraints constraints = new GridBagConstraints(); + constraints.gridx = 0; + constraints.gridy = 0; + constraints.weightx = 1.0; + constraints.anchor = GridBagConstraints.CENTER; + constraints.fill = GridBagConstraints.HORIZONTAL; + panel.add(ignoreFieldAccessesCheckBox, constraints); + constraints.gridy = 1; + panel.add(ignoreMethodCallsCheckBox, constraints); + return panel; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new UnnecessarilyQualifiedStaticCallVisitor(this, inspectionManager, onTheFly); + } + + public InspectionGadgetsFix buildFix(PsiElement location) { + return fix; + } + + private static class UnnecessarilyQualifiedStaticCallFix extends InspectionGadgetsFix { + public String getName() { + return "Remove unnecessary qualifier"; + } + + public void applyFix(Project project, ProblemDescriptor descriptor) { + final PsiReferenceExpression expression = + (PsiReferenceExpression) descriptor.getPsiElement(); + final String newExpression = expression.getReferenceName(); + replaceExpression(project, expression, newExpression); + } + } + + private class UnnecessarilyQualifiedStaticCallVisitor extends BaseInspectionVisitor { + + private UnnecessarilyQualifiedStaticCallVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitMethodCallExpression(PsiMethodCallExpression expression) { + super.visitMethodCallExpression(expression); + if (m_ignoreStaticMethodCalls) { + return; + } + final PsiReferenceExpression methodExpression = expression.getMethodExpression(); + if (!isUnnecessarilyQualifiedMethodCall(methodExpression)) { + return; + } + registerError(methodExpression); + } + + public void visitReferenceExpression(PsiReferenceExpression expression) { + super.visitReferenceExpression(expression); + if (m_ignoreStaticFieldAccesses) { + return; + } + final PsiElement element = expression.resolve(); + if (!(element instanceof PsiField)) { + return; + } + if (!isUnnecessarilyQualifiedFieldAccess(expression)) { + return; + } + registerError(expression); + } + + private boolean isUnnecessarilyQualifiedFieldAccess(PsiReferenceExpression expression) { + final PsiElement element = expression.resolve(); + if (!(element instanceof PsiField) && !(element instanceof PsiMethod)) { + return false; + } + final PsiMember member = (PsiMember) element; + if (!member.hasModifierProperty(PsiModifier.STATIC)) { + return false; + } + final PsiExpression qualifierExpression = expression.getQualifierExpression(); + if (!(qualifierExpression instanceof PsiJavaCodeReferenceElement)) { + return false; + } + final PsiElement qualifierElement = + ((PsiReference) qualifierExpression).resolve(); + if (!(qualifierElement instanceof PsiClass)) { + return false; + } + final String referenceName = expression.getReferenceName(); + PsiClass parentClass = ClassUtils.getContainingClass(expression); + PsiClass containingClass = parentClass; + while (parentClass != null) { + containingClass = parentClass; + final PsiField[] fields = containingClass.getAllFields(); + for (int i = 0; i < fields.length; i++) { + final PsiField field = fields[i]; + final String name = field.getName(); + if (referenceName.equals(name) && !containingClass.equals(qualifierElement)) { + return false; + } + } + parentClass = ClassUtils.getContainingClass(containingClass); + } + PsiMethod containingMethod = + (PsiMethod) PsiTreeUtil.getParentOfType(expression, PsiMethod.class); + while (containingMethod != null) { + final PsiParameterList parameterList = containingMethod.getParameterList(); + final PsiParameter[] parameters = parameterList.getParameters(); + for (int i = 0; i < parameters.length; i++) { + final PsiParameter parameter = parameters[i]; + final String name = parameter.getName(); + if (referenceName.equals(name)) { + return false; + } + } + containingMethod = + (PsiMethod) PsiTreeUtil.getParentOfType(containingMethod, PsiMethod.class); + } + if (!qualifierElement.equals(containingClass)) { + return false; + } + return true; + } + + private boolean isUnnecessarilyQualifiedMethodCall(PsiReferenceExpression expression) { + final PsiElement element = expression.resolve(); + if (!(element instanceof PsiField) && !(element instanceof PsiMethod)) { + return false; + } + final PsiMember member = (PsiMember) element; + if (!member.hasModifierProperty(PsiModifier.STATIC)) { + return false; + } + final PsiExpression qualifierExpression = expression.getQualifierExpression(); + if (!(qualifierExpression instanceof PsiJavaCodeReferenceElement)) { + return false; + } + final PsiElement qualifierElement = ((PsiJavaCodeReferenceElement) qualifierExpression).resolve(); + if (!(qualifierElement instanceof PsiClass)) { + return false; + } + final String referenceName = expression.getReferenceName(); + PsiClass parentClass = ClassUtils.getContainingClass(expression); + PsiClass containingClass = parentClass; + while (parentClass != null) { + containingClass = parentClass; + final PsiMethod[] methods = containingClass.getAllMethods(); + for (int i = 0; i < methods.length; i++) { + final PsiMethod method = methods[i]; + final String name = method.getName(); + if (referenceName.equals(name) && !containingClass.equals(qualifierElement)) { + return false; + } + } + parentClass = ClassUtils.getContainingClass(containingClass); + } + if (!qualifierElement.equals(containingClass)) { + return false; + } + return true; + } + } +} \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/style/UnqualifiedStaticUsageInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/style/UnqualifiedStaticUsageInspection.java new file mode 100644 index 000000000000..53e6186f6617 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/style/UnqualifiedStaticUsageInspection.java @@ -0,0 +1,155 @@ +package com.siyeh.ig.style; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.codeInspection.ProblemDescriptor; +import com.intellij.openapi.project.Project; +import com.intellij.psi.*; +import com.siyeh.ig.*; + +import javax.swing.JComponent; +import javax.swing.JPanel; +import javax.swing.JCheckBox; +import javax.swing.ButtonModel; +import javax.swing.event.ChangeListener; +import javax.swing.event.ChangeEvent; +import java.awt.GridBagLayout; +import java.awt.GridBagConstraints; + +public class UnqualifiedStaticUsageInspection extends ExpressionInspection { + public boolean m_ignoreStaticFieldAccesses = false; + public boolean m_ignoreStaticMethodCalls = false; + + public String getDisplayName() { + return "Unqualified static usage"; + } + + public String getGroupDisplayName() { + return GroupNames.STYLE_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + if (location.getParent() instanceof PsiMethodCallExpression) { + return "Unqualified static method call '#ref()' #loc"; + } else { + return "Unqualified static field access '#ref' #loc"; + } + } + + public JComponent createOptionsPanel() { + final JPanel panel = new JPanel(new GridBagLayout()); + final JCheckBox ignoreFieldAccessesCheckBox = new JCheckBox("Ignore unqualified field accesses", + m_ignoreStaticFieldAccesses); + final ButtonModel ignoreFieldAccessesModel = ignoreFieldAccessesCheckBox.getModel(); + ignoreFieldAccessesModel.addChangeListener(new ChangeListener() { + public void stateChanged(ChangeEvent e) { + m_ignoreStaticFieldAccesses = ignoreFieldAccessesModel.isSelected(); + } + }); + final JCheckBox ignoreMethodCallsCheckBox = new JCheckBox("Ignore unqualified method calls", + m_ignoreStaticMethodCalls); + final ButtonModel ignoreMethodCallsModel = ignoreMethodCallsCheckBox.getModel(); + ignoreMethodCallsModel.addChangeListener(new ChangeListener() { + public void stateChanged(ChangeEvent e) { + m_ignoreStaticMethodCalls = ignoreMethodCallsModel.isSelected(); + } + }); + final GridBagConstraints constraints = new GridBagConstraints(); + constraints.gridx = 0; + constraints.gridy = 0; + constraints.weightx = 1.0; + constraints.anchor = GridBagConstraints.CENTER; + constraints.fill = GridBagConstraints.HORIZONTAL; + panel.add(ignoreFieldAccessesCheckBox, constraints); + constraints.gridy = 1; + panel.add(ignoreMethodCallsCheckBox, constraints); + return panel; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new UnqualifiedStaticCallVisitor(this, inspectionManager, onTheFly); + } + + public InspectionGadgetsFix buildFix(PsiElement location) { + if (location.getParent() instanceof PsiMethodCallExpression) { + return new UnqualifiedStaticAccessFix(false); + } else { + return new UnqualifiedStaticAccessFix(true); + } + } + + private static class UnqualifiedStaticAccessFix extends InspectionGadgetsFix { + private boolean m_fixField; + + UnqualifiedStaticAccessFix(boolean fixField) { + super(); + m_fixField = fixField; + } + + public String getName() { + if (m_fixField) { + return "Qualify static field access"; + } else { + return "Qualify static method call"; + } + } + + public void applyFix(Project project, ProblemDescriptor descriptor) { + final PsiReferenceExpression expression = + (PsiReferenceExpression) descriptor.getPsiElement(); + final PsiMember member = (PsiMember) expression.resolve(); + final PsiClass containingClass = member.getContainingClass(); + final String className = containingClass.getName(); + final String text = expression.getText(); + replaceExpression(project, expression, className + '.' + text); + } + } + + private class UnqualifiedStaticCallVisitor extends BaseInspectionVisitor { + private UnqualifiedStaticCallVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitMethodCallExpression(PsiMethodCallExpression expression) { + super.visitMethodCallExpression(expression); + if (m_ignoreStaticMethodCalls) { + return; + } + final PsiReferenceExpression methodExpression = expression.getMethodExpression(); + if (!isUnqualifiedStaticAccess(methodExpression)) { + return; + } + registerError(methodExpression); + } + + public void visitReferenceExpression(PsiReferenceExpression expression) { + super.visitReferenceExpression(expression); + if (m_ignoreStaticFieldAccesses) { + return; + } + final PsiElement element = expression.resolve(); + if (!(element instanceof PsiField)) { + return; + } + if (!isUnqualifiedStaticAccess(expression)) { + return; + } + registerError(expression); + } + + private boolean isUnqualifiedStaticAccess(PsiReferenceExpression expression) { + final PsiElement element = expression.resolve(); + if (!(element instanceof PsiField) && !(element instanceof PsiMethod)) { + return false; + } + final PsiMember member = (PsiMember) element; + if (!member.hasModifierProperty(PsiModifier.STATIC)) { + return false; + } + final PsiExpression qualifierExpression = expression.getQualifierExpression(); + if (qualifierExpression != null) { + return false; + } + return true; + } + } +} \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/threading/BusyWaitInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/threading/BusyWaitInspection.java new file mode 100644 index 000000000000..f60b81f013be --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/threading/BusyWaitInspection.java @@ -0,0 +1,64 @@ +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.ExpressionInspection; +import com.siyeh.ig.GroupNames; +import com.siyeh.ig.psiutils.ClassUtils; +import com.siyeh.ig.psiutils.ControlFlowUtils; + +public class BusyWaitInspection extends ExpressionInspection { + + public String getDisplayName() { + return "Busy wait"; + } + + public String getGroupDisplayName() { + return GroupNames.THREADING_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "Call to Thread.#ref() in a loop, probably busy-waiting #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new BusyWaitVisitor(this, inspectionManager, onTheFly); + } + + private static class BusyWaitVisitor extends BaseInspectionVisitor { + private BusyWaitVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitMethodCallExpression(PsiMethodCallExpression expression) { + super.visitMethodCallExpression(expression); + final PsiReferenceExpression methodExpression = expression.getMethodExpression(); + if (methodExpression == null) { + return; + } + final String methodName = methodExpression.getReferenceName(); + if (!"sleep".equals(methodName)) { + return; + } + if (!ControlFlowUtils.isInLoop(expression)) { + return; + } + + final PsiMethod method = expression.resolveMethod(); + if (method == null) { + return; + } + final PsiClass methodClass = method.getContainingClass(); + final boolean isThreadSubclass = + ClassUtils.isSubclass(methodClass, "java.lang.Thread"); + if (!isThreadSubclass) { + return; + } + registerMethodCallError(expression); + } + + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/threading/DoubleCheckedLockingInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/threading/DoubleCheckedLockingInspection.java new file mode 100644 index 000000000000..d52d298f9e28 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/threading/DoubleCheckedLockingInspection.java @@ -0,0 +1,77 @@ +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.ExpressionInspection; +import com.siyeh.ig.GroupNames; +import com.siyeh.ig.psiutils.ControlFlowUtils; +import com.siyeh.ig.psiutils.ExpressionEquivalenceChecker; +import com.siyeh.ig.psiutils.SideEffectChecker; + +public class DoubleCheckedLockingInspection extends ExpressionInspection { + + public String getDisplayName() { + return "Double-checked locking"; + } + + public String getGroupDisplayName() { + return GroupNames.THREADING_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "Double-checked locking #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new DoubleCheckedLockingVisitor(this, inspectionManager, onTheFly); + } + + private static class DoubleCheckedLockingVisitor extends BaseInspectionVisitor { + private DoubleCheckedLockingVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitIfStatement(PsiIfStatement statement) { + super.visitIfStatement(statement); + final PsiExpression outerCondition = statement.getCondition(); + if (outerCondition == null) { + return; + } + if (SideEffectChecker.mayHaveSideEffects(outerCondition)) { + return; + } + PsiStatement thenBranch = statement.getThenBranch(); + if (thenBranch == null) { + return; + } + thenBranch = ControlFlowUtils.stripBraces(thenBranch); + if (!(thenBranch instanceof PsiSynchronizedStatement)) { + return; + } + final PsiSynchronizedStatement syncStatement = + (PsiSynchronizedStatement) thenBranch; + final PsiCodeBlock body = syncStatement.getBody(); + if (body == null) { + return; + } + final PsiStatement[] statements = body.getStatements(); + if (statements == null) { + return; + } + if (statements.length != 1) { + return; + } + if (!(statements[0] instanceof PsiIfStatement)) { + return; + } + final PsiIfStatement innerIf = (PsiIfStatement) statements[0]; + final PsiExpression innerCondition = innerIf.getCondition(); + if (!ExpressionEquivalenceChecker.expressionsAreEquivalent(innerCondition, outerCondition)) { + return; + } + registerStatementError(statement); + } + } +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/threading/EmptySynchronizedStatementInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/threading/EmptySynchronizedStatementInspection.java new file mode 100644 index 000000000000..577473a6b6e6 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/threading/EmptySynchronizedStatementInspection.java @@ -0,0 +1,53 @@ +package com.siyeh.ig.threading; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.psi.PsiCodeBlock; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiStatement; +import com.intellij.psi.PsiSynchronizedStatement; +import com.siyeh.ig.BaseInspection; +import com.siyeh.ig.BaseInspectionVisitor; +import com.siyeh.ig.GroupNames; +import com.siyeh.ig.StatementInspection; + +public class EmptySynchronizedStatementInspection extends StatementInspection { + public String getDisplayName() { + return "Empty 'synchronized' statement"; + } + + public String getGroupDisplayName() { + return GroupNames.THREADING_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "Empty #ref statement #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new EmptySynchronizedStatementVisitor(this, inspectionManager, onTheFly); + } + + private static class EmptySynchronizedStatementVisitor extends BaseInspectionVisitor { + private EmptySynchronizedStatementVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitSynchronizedStatement(PsiSynchronizedStatement statement) { + super.visitSynchronizedStatement(statement); + final PsiCodeBlock body = statement.getBody(); + if (body == null) { + return; + } + final PsiStatement[] statements = body.getStatements(); + if (statements == null) { + return; + } + if (statements.length > 0) { + return; + } + registerStatementError(statement); + } + + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/threading/FieldAccessedSynchronizedAndUnsynchronizedInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/threading/FieldAccessedSynchronizedAndUnsynchronizedInspection.java new file mode 100644 index 000000000000..a8d8eee693b7 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/threading/FieldAccessedSynchronizedAndUnsynchronizedInspection.java @@ -0,0 +1,53 @@ +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.ClassInspection; +import com.siyeh.ig.GroupNames; + +import java.util.Iterator; +import java.util.Set; + +public class FieldAccessedSynchronizedAndUnsynchronizedInspection extends ClassInspection { + public String getDisplayName() { + return "Field accessed in both synchronized and unsynchronized contexts"; + } + + public String getGroupDisplayName() { + return GroupNames.THREADING_GROUP_NAME; + } + + protected String buildErrorString(PsiElement location) { + return "Field #ref is accessed in both synchronized and unsynchronized contexts #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new FieldAccessedSynchronizedAndUnsynchronizedVisitor(this, inspectionManager, onTheFly); + } + + private static class FieldAccessedSynchronizedAndUnsynchronizedVisitor extends BaseInspectionVisitor { + private FieldAccessedSynchronizedAndUnsynchronizedVisitor(BaseInspection inspection, + InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitClass(PsiClass aClass) { + final VariableAccessVisitor visitor = new VariableAccessVisitor(); + aClass.accept(visitor); + final Set fields = visitor.getInappropriatelyAccessedFields(); + for (Iterator iterator = fields.iterator(); iterator.hasNext();) { + final PsiField field = (PsiField) iterator.next(); + if (!field.hasModifierProperty(PsiModifier.FINAL)) { + final PsiClass containingClass = field.getContainingClass(); + if (aClass.equals(containingClass)) { + registerFieldError(field); + } + } + } + } + + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/threading/NakedNotifyInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/threading/NakedNotifyInspection.java new file mode 100644 index 000000000000..78c141478d4d --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/threading/NakedNotifyInspection.java @@ -0,0 +1,92 @@ +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.MethodInspection; + +public class NakedNotifyInspection extends MethodInspection { + + public String getDisplayName() { + return "'notify()' or 'notifyAll()' without corresponding state change"; + } + + public String getGroupDisplayName() { + return GroupNames.THREADING_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "Call to #ref() without corresponding state change #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new NakedNotifyVisitor(this, inspectionManager, onTheFly); + } + + private static class NakedNotifyVisitor extends BaseInspectionVisitor { + private NakedNotifyVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitMethod(PsiMethod method) { + super.visitMethod(method); + if (!method.hasModifierProperty(PsiModifier.SYNCHRONIZED)) { + return; + } + final PsiCodeBlock body = method.getBody(); + if (body != null) { + checkBody(body); + } + } + + public void visitSynchronizedStatement(PsiSynchronizedStatement statement) { + super.visitSynchronizedStatement(statement); + final PsiCodeBlock body = statement.getBody(); + if (body != null) { + checkBody(body); + } + } + + private void checkBody(PsiCodeBlock body) { + final PsiStatement[] statements = body.getStatements(); + if (statements == null) { + return; + } + if (statements.length == 0) { + return; + } + final PsiStatement firstStatement = statements[0]; + if (!(firstStatement instanceof PsiExpressionStatement)) { + return; + } + final PsiExpression firstExpression = + ((PsiExpressionStatement) firstStatement).getExpression(); + if (!(firstExpression instanceof PsiMethodCallExpression)) { + return; + } + final PsiMethodCallExpression methodCallExpression = + (PsiMethodCallExpression) firstExpression; + final PsiReferenceExpression methodExpression = + methodCallExpression.getMethodExpression(); + if (methodExpression == null) { + return; + } + final String methodName = methodExpression.getReferenceName(); + + if (!"notify".equals(methodName) && !"notifyAll".equals(methodName)) { + return; + } + final PsiExpressionList argumentList = methodCallExpression.getArgumentList(); + if (argumentList == null) { + return; + } + if (argumentList.getExpressions().length != 0) { + return; + } + registerMethodCallError(methodCallExpression); + } + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/threading/NestedSynchronizedStatementInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/threading/NestedSynchronizedStatementInspection.java new file mode 100644 index 000000000000..41343b6afd5b --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/threading/NestedSynchronizedStatementInspection.java @@ -0,0 +1,45 @@ +package com.siyeh.ig.threading; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiSynchronizedStatement; +import com.intellij.psi.util.PsiTreeUtil; +import com.siyeh.ig.BaseInspection; +import com.siyeh.ig.BaseInspectionVisitor; +import com.siyeh.ig.GroupNames; +import com.siyeh.ig.StatementInspection; + +public class NestedSynchronizedStatementInspection extends StatementInspection { + + public String getDisplayName() { + return "Nested 'synchronized' statement"; + } + + public String getGroupDisplayName() { + return GroupNames.THREADING_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "Nested #ref statement #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new NestedSynchronizedStatementVisitor(this, inspectionManager, onTheFly); + } + + private static class NestedSynchronizedStatementVisitor extends BaseInspectionVisitor { + private NestedSynchronizedStatementVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitSynchronizedStatement(PsiSynchronizedStatement statement) { + super.visitSynchronizedStatement(statement); + if (PsiTreeUtil.getParentOfType(statement, PsiSynchronizedStatement.class) == null) { + return; + } + registerStatementError(statement); + } + + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/threading/NonSynchronizedMethodOverridesSynchronizedMethodInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/threading/NonSynchronizedMethodOverridesSynchronizedMethodInspection.java new file mode 100644 index 000000000000..c323b426398e --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/threading/NonSynchronizedMethodOverridesSynchronizedMethodInspection.java @@ -0,0 +1,58 @@ +package com.siyeh.ig.threading; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiMethod; +import com.intellij.psi.PsiModifier; +import com.intellij.psi.util.PsiSuperMethodUtil; +import com.siyeh.ig.BaseInspection; +import com.siyeh.ig.BaseInspectionVisitor; +import com.siyeh.ig.GroupNames; +import com.siyeh.ig.MethodInspection; + +public class NonSynchronizedMethodOverridesSynchronizedMethodInspection extends MethodInspection { + + public String getDisplayName() { + return "Non-synchronized method overrides synchronized method"; + } + + public String getGroupDisplayName() { + return GroupNames.THREADING_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "Non-synchronized method '#ref' overrides synchronized method #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new NonSynchronizedMethodOverridesSynchronizedMethodVisitor(this, inspectionManager, onTheFly); + } + + private static class NonSynchronizedMethodOverridesSynchronizedMethodVisitor extends BaseInspectionVisitor { + private NonSynchronizedMethodOverridesSynchronizedMethodVisitor(BaseInspection inspection, + InspectionManager inspectionManager, + boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitMethod(PsiMethod method) { + //no call to super, so we don't drill into anonymous classes + if (method.isConstructor()) { + return; + } + if (method.hasModifierProperty(PsiModifier.SYNCHRONIZED)) { + return; + } + final PsiMethod[] superMethods = PsiSuperMethodUtil.findSuperMethods(method); + for (int i = 0; i < superMethods.length; i++) { + final PsiMethod superMethod = superMethods[i]; + if (superMethod.hasModifierProperty(PsiModifier.SYNCHRONIZED)) { + registerMethodError(method); + return; + } + } + } + + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/threading/NotifyNotInSynchronizedContextInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/threading/NotifyNotInSynchronizedContextInspection.java new file mode 100644 index 000000000000..c0ec93d292d1 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/threading/NotifyNotInSynchronizedContextInspection.java @@ -0,0 +1,85 @@ +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 NotifyNotInSynchronizedContextInspection extends StatementInspection { + + public String getDisplayName() { + return "'notify()' or 'notifyAll()' while not synced"; + } + + public String getGroupDisplayName() { + return GroupNames.THREADING_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "Call to #ref() is made outside of 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 PsiReferenceExpression methodExpression = expression.getMethodExpression(); + if (methodExpression == null) { + return; + } + final String methodName = methodExpression.getReferenceName(); + if (!"notify".equals(methodName) && !"notifyAll".equals(methodName)) { + return; + } + final PsiMethod method = expression.resolveMethod(); + if (method == null) { + return; + } + final PsiParameterList paramList = method.getParameterList(); + if (paramList == null) { + return; + } + final PsiParameter[] parameters = paramList.getParameters(); + final int numParams = parameters.length; + if (numParams != 0) { + 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/threading/ObjectNotifyInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/threading/ObjectNotifyInspection.java new file mode 100644 index 000000000000..a0aae26724f5 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/threading/ObjectNotifyInspection.java @@ -0,0 +1,79 @@ +package com.siyeh.ig.threading; + +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 ObjectNotifyInspection extends ExpressionInspection { + private final ObjectNotifyFix fix = new ObjectNotifyFix(); + + public String getDisplayName() { + return "Call to notify() instead of notifyAll()"; + } + + public String getGroupDisplayName() { + return GroupNames.THREADING_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "#ref should probably be replaced by notifyAll() #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new ObjectNotifyVisitor(this, inspectionManager, onTheFly); + } + + public InspectionGadgetsFix buildFix(PsiElement location) { + return fix; + } + + private static class ObjectNotifyFix extends InspectionGadgetsFix { + public String getName() { + return "Replace with notifyAll()"; + } + + public void applyFix(Project project, ProblemDescriptor descriptor) { + final PsiElement methodNameElement = descriptor.getPsiElement(); + final PsiReferenceExpression methodExpression = + (PsiReferenceExpression) methodNameElement.getParent(); + final PsiExpression qualifier = methodExpression.getQualifierExpression(); + if (qualifier == null) { + replaceExpression(project, methodExpression, "notifyAll"); + } else { + final String qualifierText = qualifier.getText(); + replaceExpression(project, methodExpression, qualifierText + ".notifyAll"); + } + } + + } + + private static class ObjectNotifyVisitor extends BaseInspectionVisitor { + private ObjectNotifyVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitMethodCallExpression(PsiMethodCallExpression expression) { + super.visitMethodCallExpression(expression); + final PsiReferenceExpression methodExpression = expression.getMethodExpression(); + if (methodExpression == null) { + return; + } + final String methodName = methodExpression.getReferenceName(); + + if (!"notify".equals(methodName)) { + return; + } + final PsiExpressionList argumentList = expression.getArgumentList(); + if (argumentList == null) { + return; + } + if (argumentList.getExpressions().length != 0) { + return; + } + registerMethodCallError(expression); + } + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/threading/PublicFieldAccessedInSynchronizedContextInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/threading/PublicFieldAccessedInSynchronizedContextInspection.java new file mode 100644 index 000000000000..58b37bd887e1 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/threading/PublicFieldAccessedInSynchronizedContextInspection.java @@ -0,0 +1,73 @@ +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.ExpressionInspection; +import com.siyeh.ig.GroupNames; + +public class PublicFieldAccessedInSynchronizedContextInspection extends ExpressionInspection { + + public String getDisplayName() { + return "Non-private field accessed in synchronized context"; + } + + public String getGroupDisplayName() { + return GroupNames.THREADING_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "Non-private field #ref accessed in synchronized context #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new PublicFieldAccessedInSynchronizedContextVisitor(this, inspectionManager, onTheFly); + } + + private static class PublicFieldAccessedInSynchronizedContextVisitor extends BaseInspectionVisitor { + private boolean m_inSynchronizedContext = false; + + private PublicFieldAccessedInSynchronizedContextVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitReferenceExpression(PsiReferenceExpression expression) { + super.visitReferenceExpression(expression); + if (!m_inSynchronizedContext) { + return; + } + final PsiElement element = expression.resolve(); + if (!(element instanceof PsiField)) { + return; + } + final PsiField field = (PsiField) element; + if (field.hasModifierProperty(PsiModifier.PRIVATE) || + field.hasModifierProperty(PsiModifier.FINAL)) { + return; + } + registerError(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/threading/SynchronizeOnLockInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/threading/SynchronizeOnLockInspection.java new file mode 100644 index 000000000000..920ab1430506 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/threading/SynchronizeOnLockInspection.java @@ -0,0 +1,62 @@ +package com.siyeh.ig.threading; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.openapi.project.Project; +import com.intellij.psi.*; +import com.intellij.psi.search.GlobalSearchScope; +import com.siyeh.ig.BaseInspection; +import com.siyeh.ig.BaseInspectionVisitor; +import com.siyeh.ig.GroupNames; +import com.siyeh.ig.MethodInspection; + +public class SynchronizeOnLockInspection extends MethodInspection { + + public String getDisplayName() { + return "Synchronization on a java.util.concurrent.locks.Lock object"; + } + + public String getGroupDisplayName() { + return GroupNames.THREADING_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "Synchronization on a java.util.concurrent.locks.Lock object is unlikely to be intentional #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new SynchronizeOnLockVisitor(this, inspectionManager, onTheFly); + } + + private static class SynchronizeOnLockVisitor extends BaseInspectionVisitor { + private SynchronizeOnLockVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitSynchronizedStatement(PsiSynchronizedStatement statement) { + super.visitSynchronizedStatement(statement); + final PsiExpression lockExpression = statement.getLockExpression(); + if (lockExpression == null) { + return; + } + final PsiType type = lockExpression.getType(); + if (type == null) { + return; + } + final PsiManager manager = lockExpression.getManager(); + final Project project = manager.getProject(); + final GlobalSearchScope scope = GlobalSearchScope.allScope(project); + final PsiClass javaUtilLockClass = + manager.findClass("java.util.concurrent.locks.Lock", scope); + if (javaUtilLockClass == null) { + return; + } + final PsiElementFactory elementFactory = manager.getElementFactory(); + final PsiClassType javaUtilLockType = elementFactory.createType(javaUtilLockClass); + if (!javaUtilLockType.isAssignableFrom(type)) { + return; + } + registerError(lockExpression); + } + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/threading/SynchronizeOnNonFinalFieldInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/threading/SynchronizeOnNonFinalFieldInspection.java new file mode 100644 index 000000000000..c10519eb8bf8 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/threading/SynchronizeOnNonFinalFieldInspection.java @@ -0,0 +1,61 @@ +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.MethodInspection; + +public class SynchronizeOnNonFinalFieldInspection extends MethodInspection { + + public String getDisplayName() { + return "Synchronization on a non-final field"; + } + + public String getGroupDisplayName() { + return GroupNames.THREADING_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "Synchronization on a non-final field #ref is unlikely to have useful semantics #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new SynchronizeOnNonFinalFieldVisitor(this, inspectionManager, onTheFly); + } + + private static class SynchronizeOnNonFinalFieldVisitor extends BaseInspectionVisitor { + private SynchronizeOnNonFinalFieldVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitSynchronizedStatement(PsiSynchronizedStatement statement) { + super.visitSynchronizedStatement(statement); + final PsiExpression lockExpression = statement.getLockExpression(); + if (lockExpression == null) { + return; + } + if (!(lockExpression instanceof PsiReferenceExpression)) { + return; + } + final PsiReference reference = lockExpression.getReference(); + if (reference == null) { + return; + } + final PsiElement element = reference.resolve(); + if (element == null) { + return; + } + if (!(element instanceof PsiField)) { + return; + } + final PsiField field = (PsiField) element; + if (field.hasModifierProperty(PsiModifier.FINAL)) { + return; + } + registerError(lockExpression); + } + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/threading/SynchronizeOnThisInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/threading/SynchronizeOnThisInspection.java new file mode 100644 index 000000000000..82693c525111 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/threading/SynchronizeOnThisInspection.java @@ -0,0 +1,49 @@ +package com.siyeh.ig.threading; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiExpression; +import com.intellij.psi.PsiSynchronizedStatement; +import com.intellij.psi.PsiThisExpression; +import com.siyeh.ig.BaseInspection; +import com.siyeh.ig.BaseInspectionVisitor; +import com.siyeh.ig.GroupNames; +import com.siyeh.ig.MethodInspection; + +public class SynchronizeOnThisInspection extends MethodInspection { + + public String getDisplayName() { + return "Synchronization on 'this'"; + } + + public String getGroupDisplayName() { + return GroupNames.THREADING_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "Synchronization on '#ref' may have unforseen side-effects #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new SynchronizeOnThisVisitor(this, inspectionManager, onTheFly); + } + + private static class SynchronizeOnThisVisitor extends BaseInspectionVisitor { + private SynchronizeOnThisVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitSynchronizedStatement(PsiSynchronizedStatement statement) { + super.visitSynchronizedStatement(statement); + final PsiExpression lockExpression = statement.getLockExpression(); + if (lockExpression == null) { + return; + } + if (!(lockExpression instanceof PsiThisExpression)) { + return; + } + registerError(lockExpression); + } + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/threading/SynchronizedMethodInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/threading/SynchronizedMethodInspection.java new file mode 100644 index 000000000000..950780664fdc --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/threading/SynchronizedMethodInspection.java @@ -0,0 +1,61 @@ +package com.siyeh.ig.threading; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiMethod; +import com.intellij.psi.PsiModifier; +import com.intellij.psi.PsiModifierList; +import com.siyeh.ig.BaseInspection; +import com.siyeh.ig.BaseInspectionVisitor; +import com.siyeh.ig.GroupNames; +import com.siyeh.ig.MethodInspection; +import com.siyeh.ig.ui.SingleCheckboxOptionsPanel; + +import javax.swing.*; + +public class SynchronizedMethodInspection extends MethodInspection { + public boolean m_includeNativeMethods = true; + + public String getDisplayName() { + return "'synchronized' method"; + } + + public String getGroupDisplayName() { + return GroupNames.THREADING_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + final PsiModifierList modifierList = (PsiModifierList) location.getParent(); + final PsiMethod method = (PsiMethod) modifierList.getParent(); + return "Method " + method.getName() + "() declared '#ref' #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new SynchronizedMethodVisitor(this, inspectionManager, onTheFly); + } + + public JComponent createOptionsPanel() { + return new SingleCheckboxOptionsPanel("Include native methods", + this, "m_includeNativeMethods"); + } + + private class SynchronizedMethodVisitor extends BaseInspectionVisitor { + private SynchronizedMethodVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitMethod(PsiMethod method) { + //no call to super, so we don't drill into anonymous classes + if (!method.hasModifierProperty(PsiModifier.SYNCHRONIZED)) { + return; + } + if (!m_includeNativeMethods && + method.hasModifierProperty(PsiModifier.NATIVE)) { + return; + } + registerModifierError(PsiModifier.SYNCHRONIZED, method); + } + + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/threading/ThreadRunInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/threading/ThreadRunInspection.java new file mode 100644 index 000000000000..45d9d665eac8 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/threading/ThreadRunInspection.java @@ -0,0 +1,91 @@ +package com.siyeh.ig.threading; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.codeInspection.ProblemDescriptor; +import com.intellij.openapi.project.Project; +import com.intellij.psi.*; +import com.siyeh.ig.*; +import com.siyeh.ig.psiutils.ClassUtils; + +public class ThreadRunInspection extends ExpressionInspection { + private final ThreadRunFix fix = new ThreadRunFix(); + + public String getDisplayName() { + return "Call to Thread.run()"; + } + + public String getGroupDisplayName() { + return GroupNames.THREADING_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "Calls to #ref() should probably be replace by start() #loc"; + } + + public InspectionGadgetsFix buildFix(PsiElement location) { + return fix; + } + + private static class ThreadRunFix extends InspectionGadgetsFix { + public String getName() { + return "Replace with start()"; + } + + public void applyFix(Project project, ProblemDescriptor descriptor) { + final PsiElement methodNameIdentifier = descriptor.getPsiElement(); + final PsiReferenceExpression methodExpression = + (PsiReferenceExpression) methodNameIdentifier.getParent(); + final PsiExpression qualifier = methodExpression.getQualifierExpression(); + if (qualifier == null) { + replaceExpression(project, methodExpression, "start"); + } else { + final String qualifierText = qualifier.getText(); + replaceExpression(project, methodExpression, qualifierText + ".start"); + } + } + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new ThreadRunVisitor(this, inspectionManager, onTheFly); + } + + private static class ThreadRunVisitor extends BaseInspectionVisitor { + private ThreadRunVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitMethodCallExpression(PsiMethodCallExpression expression) { + super.visitMethodCallExpression(expression); + final PsiReferenceExpression methodExpression = expression.getMethodExpression(); + if (methodExpression == null) { + return; + } + final String methodName = methodExpression.getReferenceName(); + if (!"run".equals(methodName)) { + return; + } + + final PsiMethod method = expression.resolveMethod(); + if (method == null) { + return; + } + final PsiParameterList paramList = method.getParameterList(); + if (paramList == null) { + return; + } + final PsiParameter[] parameters = paramList.getParameters(); + if (parameters.length != 0) { + return; + } + final PsiClass methodClass = method.getContainingClass(); + final boolean isThreadSubclass = + ClassUtils.isSubclass(methodClass, "java.lang.Thread"); + if (!isThreadSubclass) { + return; + } + registerMethodCallError(expression); + } + + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/threading/ThreadStartInConstructionInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/threading/ThreadStartInConstructionInspection.java new file mode 100644 index 000000000000..d56e8cb2658c --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/threading/ThreadStartInConstructionInspection.java @@ -0,0 +1,98 @@ +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.ExpressionInspection; +import com.siyeh.ig.GroupNames; +import com.siyeh.ig.psiutils.ClassUtils; + +public class ThreadStartInConstructionInspection extends ExpressionInspection { + + public String getDisplayName() { + return "Call to Thread.start() during object construction"; + } + + public String getGroupDisplayName() { + return GroupNames.THREADING_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "Call to Thread.#ref() during object construction #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new ThreadStartInConstructionVisitor(this, inspectionManager, onTheFly); + } + + private static class ThreadStartInConstructionVisitor extends BaseInspectionVisitor { + private boolean inConstruction = false; + + private ThreadStartInConstructionVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitMethod(PsiMethod method) { + boolean wasInConstructor = false; + if (method.isConstructor()) { + inConstruction = true; + wasInConstructor = inConstruction; + } + super.visitMethod(method); + if (method.isConstructor()) { + inConstruction = wasInConstructor; + } + } + + public void visitClassInitializer(PsiClassInitializer initializer) { + boolean wasInConstructor = false; + if (!initializer.hasModifierProperty(PsiModifier.STATIC)) { + inConstruction = true; + wasInConstructor = inConstruction; + } + super.visitClassInitializer(initializer); + if (!initializer.hasModifierProperty(PsiModifier.STATIC)) { + inConstruction = wasInConstructor; + } + } + + public void visitMethodCallExpression(PsiMethodCallExpression expression) { + super.visitMethodCallExpression(expression); + if(!inConstruction) + { + return; + } + final PsiReferenceExpression methodExpression = expression.getMethodExpression(); + if (methodExpression == null) { + return; + } + final String methodName = methodExpression.getReferenceName(); + if (!"start".equals(methodName)) { + return; + } + + final PsiMethod method = expression.resolveMethod(); + if (method == null) { + return; + } + final PsiParameterList paramList = method.getParameterList(); + if (paramList == null) { + return; + } + final PsiParameter[] parameters = paramList.getParameters(); + if (parameters.length != 0) { + return; + } + final PsiClass methodClass = method.getContainingClass(); + final boolean isThreadSubclass = + ClassUtils.isSubclass(methodClass, "java.lang.Thread"); + if (!isThreadSubclass) { + return; + } + registerMethodCallError(expression); + } + + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/threading/UnconditionalWaitInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/threading/UnconditionalWaitInspection.java new file mode 100644 index 000000000000..05c284e5943f --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/threading/UnconditionalWaitInspection.java @@ -0,0 +1,121 @@ +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.MethodInspection; + +public class UnconditionalWaitInspection extends MethodInspection { + + public String getDisplayName() { + return "Unconditional 'wait()' call"; + } + + public String getGroupDisplayName() { + return GroupNames.THREADING_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "Unconditional call to #ref() #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new UnconditionalWaitVisitor(this, inspectionManager, onTheFly); + } + + private static class UnconditionalWaitVisitor extends BaseInspectionVisitor { + private UnconditionalWaitVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitMethod(PsiMethod method) { + super.visitMethod(method); + if (!method.hasModifierProperty(PsiModifier.SYNCHRONIZED)) { + return; + } + final PsiCodeBlock body = method.getBody(); + if (body != null) { + checkBody(body); + } + } + + public void visitSynchronizedStatement(PsiSynchronizedStatement statement) { + super.visitSynchronizedStatement(statement); + final PsiCodeBlock body = statement.getBody(); + if (body != null) { + checkBody(body); + } + } + + private void checkBody(PsiCodeBlock body) { + final PsiStatement[] statements = body.getStatements(); + if (statements == null) { + return; + } + if (statements.length == 0) { + return; + } + for (int i = 0; i < statements.length; i++) { + final PsiStatement statement = statements[i]; + if (isConditional(statement)) { + return; + } + if (!(statement instanceof PsiExpressionStatement)) { + continue; + } + final PsiExpression firstExpression = + ((PsiExpressionStatement) statement).getExpression(); + if (!(firstExpression instanceof PsiMethodCallExpression)) { + continue; + } + final PsiMethodCallExpression methodCallExpression = + (PsiMethodCallExpression) firstExpression; + final PsiReferenceExpression methodExpression = + methodCallExpression.getMethodExpression(); + if (methodExpression == null) { + continue; + } + final String methodName = methodExpression.getReferenceName(); + + if (!"wait".equals(methodName)) { + continue; + } + final PsiMethod method = methodCallExpression.resolveMethod(); + if (method == null) { + continue; + } + final PsiParameterList paramList = method.getParameterList(); + if (paramList == null) { + continue; + } + final PsiParameter[] parameters = paramList.getParameters(); + final int numParams = parameters.length; + if (numParams > 2) { + continue; + } + if (numParams > 0) { + final PsiType parameterType = parameters[0].getType(); + if (!parameterType.equals(PsiType.LONG)) { + continue; + } + } + + if (numParams > 1) { + final PsiType parameterType = parameters[1].getType(); + if (!parameterType.equals(PsiType.INT)) { + continue; + } + } + registerMethodCallError(methodCallExpression); + } + } + + private static boolean isConditional(PsiStatement statement) { + return statement instanceof PsiIfStatement; + + } + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/threading/VariableAccessVisitor.java b/plugins/InspectionGadgets/src/com/siyeh/ig/threading/VariableAccessVisitor.java new file mode 100644 index 000000000000..d31e309177ad --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/threading/VariableAccessVisitor.java @@ -0,0 +1,88 @@ +package com.siyeh.ig.threading; + +import com.intellij.psi.*; + +import java.util.HashSet; +import java.util.Set; + +class VariableAccessVisitor extends PsiRecursiveElementVisitor { + private final Set m_synchronizedAccesses = new HashSet(2); + private final Set m_unsynchronizedAccesses = new HashSet(2); + private boolean m_inInitializer = false; + private boolean m_inSynchronizedContext = false; + + VariableAccessVisitor() { + super(); + } + + 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); + } + if (qualifier != null && !(qualifier instanceof PsiThisExpression)) { + return; + } + final PsiElement element = ref.resolve(); + if (!(element instanceof PsiField)) { + return; + } + if (m_inInitializer) { + return; + } else if (m_inSynchronizedContext) { + m_synchronizedAccesses.add(element); + } else { + m_unsynchronizedAccesses.add(element); + } + } + + public void visitSynchronizedStatement(PsiSynchronizedStatement statement) { + final boolean wasInSync = m_inSynchronizedContext; + m_inSynchronizedContext = true; + super.visitSynchronizedStatement(statement); + m_inSynchronizedContext = wasInSync; + } + + public void visitMethod(PsiMethod method) { + final boolean methodIsSynchonized = method.hasModifierProperty(PsiModifier.SYNCHRONIZED); + boolean wasInSync = false; + if (methodIsSynchonized) { + wasInSync = m_inSynchronizedContext; + m_inSynchronizedContext = true; + } + final boolean isConstructor = method.isConstructor(); + if (isConstructor) { + m_inInitializer = true; + } + super.visitMethod(method); + if (methodIsSynchonized) { + m_inSynchronizedContext = wasInSync; + } + if (isConstructor) { + m_inInitializer = false; + } + } + + public void visitClassInitializer(PsiClassInitializer initializer) { + m_inInitializer = true; + super.visitClassInitializer(initializer); + m_inInitializer = false; + } + + public void visitField(PsiField field) { + m_inInitializer = true; + super.visitField(field); //To change body of overriden methods use Options | File Templates. + m_inInitializer = false; + } + + public Set getInappropriatelyAccessedFields() { + final Set out = new HashSet(m_synchronizedAccesses); + out.retainAll(m_unsynchronizedAccesses); + return out; + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/threading/VolatileLongOrDoubleFieldInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/threading/VolatileLongOrDoubleFieldInspection.java new file mode 100644 index 000000000000..827a86bb85b6 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/threading/VolatileLongOrDoubleFieldInspection.java @@ -0,0 +1,57 @@ +package com.siyeh.ig.threading; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiField; +import com.intellij.psi.PsiModifier; +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 VolatileLongOrDoubleFieldInspection extends FieldInspection { + + public String getDisplayName() { + return "Volatile long or double field"; + } + + public String getGroupDisplayName() { + return GroupNames.THREADING_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + final PsiField field = (PsiField) location.getParent(); + final String typeString = field.getType().getPresentableText(); + return "Volatile field #ref of type " + typeString + " #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new VolatileLongOrDoubleFieldVisitor(this, inspectionManager, onTheFly); + } + + private static class VolatileLongOrDoubleFieldVisitor extends BaseInspectionVisitor { + private VolatileLongOrDoubleFieldVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitField(PsiField field) { + super.visitField(field); + if(!field.hasModifierProperty(PsiModifier.VOLATILE) ) + { + return; + } + final PsiType type = field.getType(); + if(type == null) + { + return; + } + final String text = type.getCanonicalText(); + if("double".equals(text)|| "long".equals(text)) + { + registerFieldError(field); + } + } + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/threading/WaitNotInLoopInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/threading/WaitNotInLoopInspection.java new file mode 100644 index 000000000000..a9eeae0a9a00 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/threading/WaitNotInLoopInspection.java @@ -0,0 +1,78 @@ +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; +import com.siyeh.ig.psiutils.ControlFlowUtils; + +public class WaitNotInLoopInspection extends StatementInspection { + + public String getDisplayName() { + return "'wait()' not in loop"; + } + + public String getGroupDisplayName() { + return GroupNames.THREADING_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "Call to #ref() is not made in a loop #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new WaitNotInLoopVisitor(this, inspectionManager, onTheFly); + } + + private static class WaitNotInLoopVisitor extends BaseInspectionVisitor { + private WaitNotInLoopVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitMethodCallExpression(PsiMethodCallExpression expression) { + super.visitMethodCallExpression(expression); + final PsiReferenceExpression methodExpression = expression.getMethodExpression(); + if (methodExpression == null) { + return; + } + final String methodName = methodExpression.getReferenceName(); + if (!"wait".equals(methodName)) { + return; + } + final PsiMethod method = expression.resolveMethod(); + if (method == null) { + return; + } + final PsiParameterList paramList = method.getParameterList(); + if (paramList == null) { + return; + } + final PsiParameter[] parameters = paramList.getParameters(); + final int numParams = parameters.length; + if (numParams > 2) { + return; + } + if (numParams > 0) { + final PsiType parameterType = parameters[0].getType(); + if (!parameterType.equals(PsiType.LONG)) { + return; + } + } + + if (numParams > 1) { + final PsiType parameterType = parameters[1].getType(); + if (!parameterType.equals(PsiType.INT)) { + return; + } + } + + if (ControlFlowUtils.isInLoop(expression)) { + return; + } + registerMethodCallError(expression); + } + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/threading/WaitNotInSynchronizedContextInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/threading/WaitNotInSynchronizedContextInspection.java new file mode 100644 index 000000000000..6448ecb8a0bc --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/threading/WaitNotInSynchronizedContextInspection.java @@ -0,0 +1,98 @@ +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 WaitNotInSynchronizedContextInspection extends StatementInspection { + + public String getDisplayName() { + return "'wait()' while not synced"; + } + + public String getGroupDisplayName() { + return GroupNames.THREADING_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "Call to #ref() is made outside of 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 PsiReferenceExpression methodExpression = expression.getMethodExpression(); + if (methodExpression == null) { + return; + } + final String methodName = methodExpression.getReferenceName(); + if (!"wait".equals(methodName)) { + return; + } + final PsiMethod method = expression.resolveMethod(); + if (method == null) { + return; + } + final PsiParameterList paramList = method.getParameterList(); + if (paramList == null) { + return; + } + final PsiParameter[] parameters = paramList.getParameters(); + final int numParams = parameters.length; + if (numParams > 2) { + return; + } + if (numParams > 0) { + final PsiType parameterType = parameters[0].getType(); + if (!parameterType.equals(PsiType.LONG)) { + return; + } + } + + if (numParams > 1) { + final PsiType parameterType = parameters[1].getType(); + if (!parameterType.equals(PsiType.INT)) { + 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/threading/WaitWhileHoldingTwoLocksInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/threading/WaitWhileHoldingTwoLocksInspection.java new file mode 100644 index 000000000000..b688a8e25ac6 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/threading/WaitWhileHoldingTwoLocksInspection.java @@ -0,0 +1,95 @@ +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 WaitWhileHoldingTwoLocksInspection extends StatementInspection { + + public String getDisplayName() { + return "'wait()' while holding two locks"; + } + + public String getGroupDisplayName() { + return GroupNames.THREADING_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "Call to #ref() is made while holding two locks #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new WaitWhileHoldingTwoLocksVisitor(this, inspectionManager, onTheFly); + } + + private static class WaitWhileHoldingTwoLocksVisitor extends BaseInspectionVisitor { + private int m_numLocksHeld = 0; + + private WaitWhileHoldingTwoLocksVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitMethodCallExpression(PsiMethodCallExpression expression) { + super.visitMethodCallExpression(expression); + if (m_numLocksHeld < 2) { + return; + } + final PsiReferenceExpression methodExpression = expression.getMethodExpression(); + if (methodExpression == null) { + return; + } + final String methodName = methodExpression.getReferenceName(); + if (!"wait".equals(methodName)) { + return; + } + final PsiMethod method = expression.resolveMethod(); + if (method == null) { + return; + } + final PsiParameterList paramList = method.getParameterList(); + if (paramList == null) { + return; + } + final PsiParameter[] parameters = paramList.getParameters(); + final int numParams = parameters.length; + if (numParams > 2) { + return; + } + if (numParams > 0) { + final PsiType parameterType = parameters[0].getType(); + if (!parameterType.equals(PsiType.LONG)) { + return; + } + } + + if (numParams > 1) { + final PsiType parameterType = parameters[1].getType(); + if (!parameterType.equals(PsiType.INT)) { + return; + } + } + + registerMethodCallError(expression); + } + + public void visitMethod(PsiMethod method) { + if (method.hasModifierProperty(PsiModifier.SYNCHRONIZED)) { + m_numLocksHeld++; + } + super.visitMethod(method); + if (method.hasModifierProperty(PsiModifier.SYNCHRONIZED)) { + m_numLocksHeld--; + } + } + + public void visitSynchronizedStatement(PsiSynchronizedStatement psiSynchronizedStatement) { + m_numLocksHeld++; + super.visitSynchronizedStatement(psiSynchronizedStatement); + m_numLocksHeld--; + } + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/threading/WhileLoopSpinsOnFieldInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/threading/WhileLoopSpinsOnFieldInspection.java new file mode 100644 index 000000000000..7fc7f2daeab7 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/threading/WhileLoopSpinsOnFieldInspection.java @@ -0,0 +1,143 @@ +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.MethodInspection; + +public class WhileLoopSpinsOnFieldInspection extends MethodInspection { + + public String getDisplayName() { + return "While loop spins on field"; + } + + public String getGroupDisplayName() { + return GroupNames.THREADING_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "#ref loop spins on field #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new WhileLoopSpinsOnFieldVisitor(this, inspectionManager, onTheFly); + } + + private static class WhileLoopSpinsOnFieldVisitor extends BaseInspectionVisitor { + private WhileLoopSpinsOnFieldVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitWhileStatement(PsiWhileStatement statement) { + super.visitWhileStatement(statement); + final PsiStatement body = statement.getBody(); + if (!statementIsEmpty(body)) { + return; + } + final PsiExpression condition = statement.getCondition(); + if (!isSimpleFieldComparison(condition)) { + return; + } + registerStatementError(statement); + } + + private boolean isSimpleFieldComparison(PsiExpression condition) { + if (condition == null) { + return false; + } + if (isSimpleFieldAccess(condition)) { + return true; + } + if (condition instanceof PsiPrefixExpression) { + final PsiExpression operand = + ((PsiPrefixExpression) condition).getOperand(); + return isSimpleFieldComparison(operand); + } + if (condition instanceof PsiPostfixExpression) { + final PsiExpression operand = + ((PsiPostfixExpression) condition).getOperand(); + return isSimpleFieldComparison(operand); + } + if (condition instanceof PsiParenthesizedExpression) { + final PsiExpression operand = + ((PsiParenthesizedExpression) condition).getExpression(); + return isSimpleFieldComparison(operand); + } + + if (condition instanceof PsiBinaryExpression) { + final PsiBinaryExpression binaryExpression = + (PsiBinaryExpression) condition; + final PsiExpression lOperand = binaryExpression.getLOperand(); + final PsiExpression rOperand = binaryExpression.getROperand(); + return (isSimpleFieldComparison(lOperand) && isLiteral(rOperand)) || + (isSimpleFieldComparison(rOperand) && isLiteral(lOperand)); + } + return false; + } + + private boolean isLiteral(PsiExpression expression) { + if (expression == null) { + return false; + } + if (expression instanceof PsiParenthesizedExpression) { + final PsiExpression operand = + ((PsiParenthesizedExpression) expression).getExpression(); + return isSimpleFieldAccess(operand); + } + return expression instanceof PsiLiteralExpression; + } + + private boolean isSimpleFieldAccess(PsiExpression expression) { + if (expression == null) { + return false; + } + if (expression instanceof PsiParenthesizedExpression) { + final PsiExpression operand = + ((PsiParenthesizedExpression) expression).getExpression(); + return isSimpleFieldAccess(operand); + } + if (!(expression instanceof PsiReferenceExpression)) { + return false; + } + final PsiElement referent = ((PsiReference) expression).resolve(); + if (!(referent instanceof PsiField)) { + return false; + } + final PsiField field = (PsiField) referent; + if (field.hasModifierProperty(PsiModifier.VOLATILE)) { + return false; + } + return true; + } + + private boolean statementIsEmpty(PsiStatement statement) { + if (statement == null) { + return false; + } + if (statement instanceof PsiEmptyStatement) { + return true; + } + if (statement instanceof PsiBlockStatement) { + final PsiCodeBlock codeBlock = + ((PsiBlockStatement) statement).getCodeBlock(); + if (codeBlock == null) { + return false; + } + final PsiStatement[] statements = codeBlock.getStatements(); + if (statements == null) { + return false; + } + for (int i = 0; i < statements.length; i++) { + if (!statementIsEmpty(statements[i])) { + return false; + } + } + return true; + } + return false; + } + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/verbose/ExtendsObjectInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/verbose/ExtendsObjectInspection.java new file mode 100644 index 000000000000..c978fa936cde --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/verbose/ExtendsObjectInspection.java @@ -0,0 +1,74 @@ +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 ExtendsObjectInspection extends ClassInspection { + private final ExtendsObjectFix fix = new ExtendsObjectFix(); + + public String getDisplayName() { + return "Class explicitly extends java.lang.Object"; + } + + public String getGroupDisplayName() { + return GroupNames.VERBOSE_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "Class '#ref' explicitly extends java.lang.Object #loc"; + } + + protected InspectionGadgetsFix buildFix(PsiElement location) { + return fix; + } + + private static class ExtendsObjectFix extends InspectionGadgetsFix { + public String getName() { + return "Remove redundant 'extends Object'"; + } + + public void applyFix(Project project, ProblemDescriptor problemDescriptor) { + final PsiElement extendClassIdentifier = problemDescriptor.getPsiElement(); + final PsiClass element = (PsiClass) extendClassIdentifier.getParent(); + final PsiReferenceList extendsList = element.getExtendsList(); + final PsiJavaCodeReferenceElement[] elements = extendsList.getReferenceElements(); + for (int i = 0; i < elements.length; i++) { + deleteElement(elements[i]); + } + } + + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new ExtendsObjectVisitor(this, inspectionManager, onTheFly); + } + + private static class ExtendsObjectVisitor extends BaseInspectionVisitor { + + private ExtendsObjectVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitClass(PsiClass aClass) { + if (aClass.isInterface() || aClass.isAnnotationType()) { + return; + } + final PsiReferenceList extendsList = aClass.getExtendsList(); + if (extendsList != null) { + final PsiJavaCodeReferenceElement[] elements = extendsList.getReferenceElements(); + for (int i = 0; i < elements.length; i++) { + final PsiJavaCodeReferenceElement element = elements[i]; + final String text = element.getText(); + if ("Object".equals(text) || "java.lang.Object".equals(text)) { + registerClassError(aClass); + } + } + + } + } + + } +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/verbose/ForCanBeForeachInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/verbose/ForCanBeForeachInspection.java new file mode 100644 index 000000000000..c26d9aee43b6 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/verbose/ForCanBeForeachInspection.java @@ -0,0 +1,801 @@ +package com.siyeh.ig.verbose; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.codeInspection.ProblemDescriptor; +import com.intellij.openapi.project.Project; +import com.intellij.pom.java.LanguageLevel; +import com.intellij.psi.*; +import com.intellij.psi.codeStyle.CodeStyleManager; +import com.intellij.psi.tree.IElementType; +import com.siyeh.ig.*; +import com.siyeh.ig.psiutils.ClassUtils; +import com.siyeh.ig.psiutils.ParenthesesUtils; + +public class ForCanBeForeachInspection extends StatementInspection { + private final ForCanBeForeachFix fix = new ForCanBeForeachFix(); + + public String getDisplayName() { + return "'for' loop replacable by 'for each' (J2SDK 5.0 only)"; + } + + public String getGroupDisplayName() { + return GroupNames.VERBOSE_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "'#ref' loop replacable by 'for each'"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new ForCanBeForeachVisitor(this, inspectionManager, onTheFly); + } + + public InspectionGadgetsFix buildFix(PsiElement location) { + return fix; + } + + private class ForCanBeForeachFix extends InspectionGadgetsFix { + public String getName() { + return "Replace with 'for each'"; + } + + public void applyFix(Project project, ProblemDescriptor descriptor) { + final PsiElement forElement = descriptor.getPsiElement(); + final PsiForStatement forStatement = (PsiForStatement) forElement.getParent(); + if (isArrayLoopStatement(forStatement)) { + final String newExpression = createArrayIterationText(forStatement, project); + replaceStatement(project, forStatement, newExpression); + } else if (isCollectionLoopStatement(forStatement)) { + final String newExpression = createCollectionIterationText(forStatement, project); + replaceStatement(project, forStatement, newExpression); + } + } + + private String createCollectionIterationText(PsiForStatement forStatement, Project project) { + final int length = forStatement.getText().length(); + final StringBuffer out = new StringBuffer(length); + final PsiStatement body = forStatement.getBody(); + final PsiStatement firstStatement = getFirstStatement(body); + final String contentVariableName; + final String finalString; + final PsiStatement statementToSkip; + final PsiStatement initialization = forStatement.getInitialization(); + final PsiDeclarationStatement declaration = (PsiDeclarationStatement) initialization; + final PsiLocalVariable iterator = (PsiLocalVariable) declaration.getDeclaredElements()[0]; + + final PsiMethodCallExpression initializer = + (PsiMethodCallExpression) iterator.getInitializer(); + final PsiExpression collection = initializer.getMethodExpression().getQualifierExpression(); + final String typeString = iterator.getTypeElement().getText(); + final String contentType; + if (typeString.indexOf((int) '<') >= 0) { + final int contentTypeStart = typeString.indexOf((int) '<') + 1; + final int contentTypeEnd = typeString.lastIndexOf((int) '>'); + contentType = typeString.substring(contentTypeStart, contentTypeEnd); + } else { + contentType = "Object"; + } + + final String iteratorName = iterator.getName(); + final boolean isDeclaration = isIteratorNextDeclaration(firstStatement, iteratorName); + if (isDeclaration) { + final PsiDeclarationStatement decl = (PsiDeclarationStatement) firstStatement; + final PsiElement[] declaredElements = decl.getDeclaredElements(); + final PsiLocalVariable localVar = (PsiLocalVariable) declaredElements[0]; + contentVariableName = localVar.getName(); + statementToSkip = decl; + if (localVar.hasModifierProperty(PsiModifier.FINAL)) { + finalString = "final "; + } else { + finalString = ""; + } + } else { + contentVariableName = createNewVarName(project, forStatement); + finalString = ""; + statementToSkip = null; + } + out.append("for(" + finalString + contentType + ' ' + contentVariableName + ": " + collection.getText() + ')'); + replaceIteratorNext(body, contentVariableName, iteratorName, statementToSkip, out); + return out.toString(); + } + + private String createArrayIterationText(PsiForStatement forStatement, Project project) { + final int length = forStatement.getText().length(); + final StringBuffer out = new StringBuffer(length); + final PsiBinaryExpression condition = (PsiBinaryExpression) forStatement.getCondition(); + final PsiExpression lhs = condition.getLOperand(); + final String indexName = lhs.getText(); + final PsiReferenceExpression arrayLengthExpression = (PsiReferenceExpression) condition.getROperand(); + final PsiReferenceExpression arrayReference = (PsiReferenceExpression) arrayLengthExpression.getQualifierExpression(); + final PsiArrayType arrayType = (PsiArrayType) arrayReference.getType(); + final String type = arrayType.getComponentType().getPresentableText(); + final String arrayName = arrayReference.getText(); + final PsiStatement body = forStatement.getBody(); + final PsiStatement firstStatement = getFirstStatement(body); + final String contentVariableName; + final String finalString; + final PsiStatement statementToSkip; + final boolean isDeclaration = isArrayElementDeclaration(firstStatement, arrayName, indexName); + if (isDeclaration) { + final PsiDeclarationStatement decl = (PsiDeclarationStatement) firstStatement; + final PsiElement[] declaredElements = decl.getDeclaredElements(); + final PsiLocalVariable localVar = (PsiLocalVariable) declaredElements[0]; + contentVariableName = localVar.getName(); + statementToSkip = decl; + if (localVar.hasModifierProperty(PsiModifier.FINAL)) { + finalString = "final "; + } else { + finalString = ""; + } + } else { + contentVariableName = createNewVarName(project, forStatement); + finalString = ""; + statementToSkip = null; + } + out.append("for(" + finalString + type + ' ' + contentVariableName + ": " + arrayName + ')'); + replaceArrayAccess(body, contentVariableName, arrayName, indexName, statementToSkip, out); + return out.toString(); + } + + private void replaceArrayAccess(PsiElement element, String contentVariableName, String arrayName, String indexName, + PsiElement childToSkip, StringBuffer out) { + if (isArrayLookup(element, indexName, arrayName)) { + out.append(contentVariableName); + } else { + final PsiElement[] children = element.getChildren(); + if (children.length == 0) { + out.append(element.getText()); + } else { + boolean skippingWhiteSpace = false; + for (int i = 0; i < children.length; i++) { + final PsiElement child = children[i]; + + if (child.equals(childToSkip)) { + skippingWhiteSpace = true; + } else if (child instanceof PsiWhiteSpace && skippingWhiteSpace) { + //don't do anything + } else { + skippingWhiteSpace = false; + replaceArrayAccess(child, contentVariableName, arrayName, indexName, childToSkip, out); + } + } + } + } + } + + private void replaceIteratorNext(PsiElement element, String contentVariableName, String iteratorName, + PsiElement childToSkip, StringBuffer out) { + + if (isIteratorNext(element, iteratorName)) { + out.append(contentVariableName); + } else { + final PsiElement[] children = element.getChildren(); + if (children.length == 0) { + out.append(element.getText()); + } else { + boolean skippingWhiteSpace = false; + for (int i = 0; i < children.length; i++) { + final PsiElement child = children[i]; + + if (child.equals(childToSkip)) { + skippingWhiteSpace = true; + } else if (child instanceof PsiWhiteSpace && + skippingWhiteSpace) { + //don't do anything + } else { + skippingWhiteSpace = false; + replaceIteratorNext(child, contentVariableName, + iteratorName, + childToSkip, out); + } + } + } + } + } + + private boolean isArrayElementDeclaration(PsiStatement statement, String arrayName, String indexName) { + if (!(statement instanceof PsiDeclarationStatement)) { + return false; + } + final PsiDeclarationStatement decl = (PsiDeclarationStatement) statement; + final PsiElement[] elements = decl.getDeclaredElements(); + if (elements.length != 1) { + return false; + } + if (!(elements[0] instanceof PsiLocalVariable)) { + return false; + } + final PsiLocalVariable var = (PsiLocalVariable) elements[0]; + final PsiExpression initializer = var.getInitializer(); + return isArrayLookup(initializer, indexName, arrayName); + } + + private boolean isIteratorNextDeclaration(PsiStatement statement, String iteratorName) { + if (!(statement instanceof PsiDeclarationStatement)) { + return false; + } + final PsiDeclarationStatement decl = (PsiDeclarationStatement) statement; + final PsiElement[] elements = decl.getDeclaredElements(); + if (elements.length != 1) { + return false; + } + if (!(elements[0] instanceof PsiLocalVariable)) { + return false; + } + final PsiLocalVariable var = (PsiLocalVariable) elements[0]; + final PsiExpression initializer = var.getInitializer(); + return isIteratorNext(initializer, iteratorName); + } + + private boolean isArrayLookup(PsiElement element, String indexName, String arrayName) { + if (element == null) { + return false; + } + if (!(element instanceof PsiArrayAccessExpression)) { + return false; + } + final PsiArrayAccessExpression arrayAccess = + (PsiArrayAccessExpression) element; + final PsiExpression indexExpression = arrayAccess.getIndexExpression(); + if (indexExpression == null) { + return false; + } + if (!indexName.equals(indexExpression.getText())) { + return false; + } + final PsiExpression arrayExpression = arrayAccess.getArrayExpression(); + if (arrayExpression == null) { + return false; + } + if (!arrayName.equals(arrayExpression.getText())) { + return false; + } + return true; + } + + private boolean isIteratorNext(PsiElement element, String iteratorNameName) { + if (element == null) { + return false; + } + if (!(element instanceof PsiMethodCallExpression)) { + return false; + } + final PsiMethodCallExpression callExpression = + (PsiMethodCallExpression) element; + final PsiExpressionList argumentList = callExpression.getArgumentList(); + if (argumentList == null) { + return false; + } + final PsiExpression[] args = argumentList.getExpressions(); + if (args == null || args.length != 0) { + return false; + } + final PsiReferenceExpression reference = callExpression.getMethodExpression(); + if (reference == null) { + return false; + } + final PsiExpression qualifier = reference.getQualifierExpression(); + if (qualifier == null) { + return false; + } + if (!iteratorNameName.equals(qualifier.getText())) { + return false; + } + final String referenceName = reference.getReferenceName(); + if (!"next".equals(referenceName)) { + return false; + } + return true; + } + + private String createNewVarName(Project project, PsiElement position) { + final CodeStyleManager codeStyleManager = CodeStyleManager.getInstance(project); + return codeStyleManager.suggestUniqueVariableName("value", position, true); + } + + private PsiStatement getFirstStatement(PsiStatement body) { + if (body instanceof PsiBlockStatement) { + final PsiBlockStatement block = (PsiBlockStatement) body; + return block.getCodeBlock().getStatements()[0]; + } else { + return body; + } + } + + } + + private class ForCanBeForeachVisitor extends BaseInspectionVisitor { + private ForCanBeForeachVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitForStatement(PsiForStatement forStatement) { + super.visitForStatement(forStatement); + final PsiManager manager = forStatement.getManager(); + final LanguageLevel languageLevel = manager.getEffectiveLanguageLevel(); + if (languageLevel.equals(LanguageLevel.JDK_1_3) || + languageLevel.equals(LanguageLevel.JDK_1_4)) { + return; + } + if (!isArrayLoopStatement(forStatement) && + !isCollectionLoopStatement(forStatement)) { + return; + } + registerStatementError(forStatement); + } + + } + + + private boolean isArrayLoopStatement(PsiForStatement forStatement) { + final PsiStatement initialization = forStatement.getInitialization(); + if (!(initialization instanceof PsiDeclarationStatement)) { + return false; + } + final PsiDeclarationStatement declaration = (PsiDeclarationStatement) initialization; + if (declaration.getDeclaredElements().length > 1) { + return false; + } + final PsiLocalVariable indexVar = (PsiLocalVariable) declaration.getDeclaredElements()[0]; + final PsiExpression initialValue = indexVar.getInitializer(); + if (initialValue == null) { + return false; + } + final String initializerText = initialValue.getText(); + if (!"0".equals(initializerText)) { + return false; + } + final PsiExpression condition = forStatement.getCondition(); + if (!isArrayLengthComparison(condition, indexVar)) { + return false; + } + final PsiStatement update = forStatement.getUpdate(); + if (!isIncrement(update, indexVar)) { + return false; + } + final PsiReferenceExpression arrayReference = getArrayFromCondition(condition); + final PsiStatement body = forStatement.getBody(); + if (body == null) { + return false; + } + final String arrayName = arrayReference.getText(); + if (!indexVarOnlyUsedAsIndex(arrayName, indexVar, body)) { + return false; + } + if (isArrayAssigned(arrayName, body)) { + return false; + } + return true; + } + + private static boolean isArrayAssigned(String arrayReference, PsiStatement body) { + final ArrayAssignmentVisitor visitor = new ArrayAssignmentVisitor(arrayReference); + body.accept(visitor); + return visitor.isArrayAssigned(); + } + + private static boolean indexVarOnlyUsedAsIndex(String arrayName, PsiLocalVariable indexVar, PsiStatement body) { + final IndexOnlyUsedAsIndexVisitor visitor = new IndexOnlyUsedAsIndexVisitor(arrayName, indexVar); + body.accept(visitor); + return visitor.isIndexVariableUsedOnlyAsIndex(); + } + + private boolean isCollectionLoopStatement(PsiForStatement forStatement) { + final PsiStatement initialization = forStatement.getInitialization(); + if (!(initialization instanceof PsiDeclarationStatement)) { + return false; + } + final PsiDeclarationStatement declaration = (PsiDeclarationStatement) initialization; + if (declaration.getDeclaredElements().length > 1) { + return false; + } + final PsiLocalVariable declaredVar = (PsiLocalVariable) declaration.getDeclaredElements()[0]; + + final PsiType declaredVarType = declaredVar.getType(); + if (!(declaredVarType instanceof PsiClassType)) { + return false; + } + final PsiClassType classType = (PsiClassType) declaredVarType; + final PsiClass declaredClass = classType.resolve(); + if (declaredClass == null) { + return false; + } + if (!ClassUtils.isSubclass(declaredClass, "java.util.Iterator")) { + return false; + } + final PsiExpression initialValue = declaredVar.getInitializer(); + if (initialValue == null) { + return false; + } + final String iteratorName = declaredVar.getName(); + final PsiExpression condition = forStatement.getCondition(); + if (!isHasNext(condition, iteratorName)) { + return false; + } + final PsiStatement update = forStatement.getUpdate(); + if (update != null && !(update instanceof PsiEmptyStatement)) { + return false; + } + final PsiStatement body = forStatement.getBody(); + if (body == null) { + return false; + } + if (calculateCallsToIteratorNext(iteratorName, body) != 1) { + return false; + } + if (isIteratorRemoveCalled(iteratorName, body)) { + return false; + } + if (isIteratorAssigned(iteratorName, body)) { + return false; + } + return true; + } + + private static int calculateCallsToIteratorNext(String iteratorName, PsiStatement body) { + final NumCallsToIteratorNextVisitor visitor = new NumCallsToIteratorNextVisitor(iteratorName); + body.accept(visitor); + return visitor.getNumCallsToIteratorNext(); + } + + private static boolean isIteratorAssigned(String iteratorName, PsiStatement body) { + final IteratorAssignmentVisitor visitor = new IteratorAssignmentVisitor(iteratorName); + body.accept(visitor); + return visitor.isIteratorAssigned(); + } + + private static boolean isIteratorRemoveCalled(String iteratorName, PsiStatement body) { + final IteratorRemoveVisitor visitor = new IteratorRemoveVisitor(iteratorName); + body.accept(visitor); + return visitor.isRemoveCalled(); + } + + private static boolean isHasNext(PsiExpression condition, String iterator) { + if (!(condition instanceof PsiMethodCallExpression)) { + return false; + } + final PsiMethodCallExpression call = (PsiMethodCallExpression) condition; + final PsiExpressionList argumentList = call.getArgumentList(); + if (argumentList == null) { + return false; + } + final PsiExpression[] args = argumentList.getExpressions(); + if (args.length != 0) { + return false; + } + final PsiReferenceExpression methodExpression = call.getMethodExpression(); + if (methodExpression == null) { + return false; + } + final String methodName = methodExpression.getReferenceName(); + if (!"hasNext".equals(methodName)) { + return false; + } + final PsiExpression qualifier = methodExpression.getQualifierExpression(); + if (qualifier == null) { + return true; + } + final String target = qualifier.getText(); + if (!iterator.equals(target)) { + return false; + } + return true; + } + + private static PsiReferenceExpression getArrayFromCondition(PsiExpression condition) { + final PsiExpression strippedCondition = ParenthesesUtils.stripParentheses(condition); + final PsiBinaryExpression binaryExp = (PsiBinaryExpression) strippedCondition; + final PsiReferenceExpression rhs = (PsiReferenceExpression) binaryExp.getROperand(); + return (PsiReferenceExpression) rhs.getQualifierExpression(); + } + + + private static boolean isIncrement(PsiStatement statement, PsiLocalVariable var) { + if (!(statement instanceof PsiExpressionStatement)) { + return false; + } + PsiExpression exp = ((PsiExpressionStatement) statement).getExpression(); + exp = ParenthesesUtils.stripParentheses(exp); + if (exp instanceof PsiPrefixExpression) { + final PsiPrefixExpression prefixExp = (PsiPrefixExpression) exp; + final PsiJavaToken sign = prefixExp.getOperationSign(); + if (sign == null) { + return false; + } + final IElementType tokenType = sign.getTokenType(); + if (tokenType != JavaTokenType.PLUSPLUS) { + return false; + } + final PsiExpression operand = prefixExp.getOperand(); + if (!expressionIsVariableLookup(operand, var)) { + return false; + } + return true; + } else if (exp instanceof PsiPostfixExpression) { + final PsiPostfixExpression postfixExp = (PsiPostfixExpression) exp; + final PsiJavaToken sign = postfixExp.getOperationSign(); + if (sign == null) { + return false; + } + final IElementType tokenType = sign.getTokenType(); + if (!tokenType.equals(JavaTokenType.PLUSPLUS)) { + return false; + } + final PsiExpression operand = postfixExp.getOperand(); + if (!expressionIsVariableLookup(operand, var)) { + return false; + } + return true; + } + return true; + } + + private static boolean isArrayLengthComparison(PsiExpression condition, PsiLocalVariable var) { + final PsiExpression strippedCondition = ParenthesesUtils.stripParentheses(condition); + + if (!(strippedCondition instanceof PsiBinaryExpression)) { + return false; + } + final PsiBinaryExpression binaryExp = (PsiBinaryExpression) strippedCondition; + final PsiJavaToken sign = binaryExp.getOperationSign(); + if (sign == null) { + return false; + } + if (!sign.getTokenType().equals(JavaTokenType.LT)) { + return false; + } + final PsiExpression lhs = binaryExp.getLOperand(); + if (!expressionIsVariableLookup(lhs, var)) { + return false; + } + final PsiExpression rhs = binaryExp.getROperand(); + if (!expressionIsArrayLengthLookup(rhs)) { + return false; + } + return true; + } + + private static boolean expressionIsArrayLengthLookup(PsiExpression expression) { + final PsiExpression strippedExpression = ParenthesesUtils.stripParentheses(expression); + if (!(strippedExpression instanceof PsiReferenceExpression)) { + return false; + } + final PsiReferenceExpression reference = (PsiReferenceExpression) strippedExpression; + final String referenceName = reference.getReferenceName(); + if (!"length".equals(referenceName)) { + return false; + } + final PsiExpression qualifier = reference.getQualifierExpression(); + if (qualifier == null) { + return false; + } + final PsiType type = qualifier.getType(); + if (type == null) { + return false; + } + return type.getArrayDimensions() > 0; + } + + private static boolean expressionIsVariableLookup(PsiExpression expression, PsiLocalVariable var) { + final PsiExpression strippedExpression = ParenthesesUtils.stripParentheses(expression); + + final String expressionText = strippedExpression.getText(); + final String varText = var.getName(); + return expressionText.equals(varText); + } + + private static class ArrayAssignmentVisitor extends PsiRecursiveElementVisitor { + private boolean arrayAssigned = false; + private final String arrayName; + + ArrayAssignmentVisitor(String arrayName) { + super(); + this.arrayName = arrayName; + } + + 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 visitAssignmentExpression(PsiAssignmentExpression exp) { + super.visitAssignmentExpression(exp); + final PsiExpression lhs = exp.getLExpression(); + if (lhs != null) { + if (arrayName.equals(lhs.getText())) { + arrayAssigned = true; + } + } + } + + public boolean isArrayAssigned() { + return arrayAssigned; + } + } + + private static class NumCallsToIteratorNextVisitor extends PsiRecursiveElementVisitor { + private int numCallsToIteratorNext = 0; + private final String iteratorName; + + NumCallsToIteratorNextVisitor(String iteratorName) { + super(); + this.iteratorName = iteratorName; + } + + + 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 callExpression) { + super.visitMethodCallExpression(callExpression); + final PsiReferenceExpression methodExpression = + callExpression.getMethodExpression(); + if (methodExpression == null) { + return; + } + final String methodName = methodExpression.getReferenceName(); + if (!"next".equals(methodName)) { + return; + } + + final PsiExpression qualifier = methodExpression.getQualifierExpression(); + if (qualifier == null) { + return; + } + final String qualifierText = qualifier.getText(); + if (!iteratorName.equals(qualifierText)) { + return; + } + numCallsToIteratorNext++; + } + + public int getNumCallsToIteratorNext() { + return numCallsToIteratorNext; + } + } + + private static class IteratorAssignmentVisitor extends PsiRecursiveElementVisitor { + private boolean iteratorAssigned = false; + private final String iteratorName; + + IteratorAssignmentVisitor(String iteratorName) { + super(); + this.iteratorName = iteratorName; + } + + 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 visitAssignmentExpression(PsiAssignmentExpression exp) { + super.visitAssignmentExpression(exp); + final PsiExpression lhs = exp.getLExpression(); + if (lhs != null) { + final String lhsText = lhs.getText(); + if (iteratorName.equals(lhsText)) { + iteratorAssigned = true; + } + } + } + + public boolean isIteratorAssigned() { + return iteratorAssigned; + } + } + + private static class IteratorRemoveVisitor extends PsiRecursiveElementVisitor { + private boolean removeCalled = false; + private final String iteratorName; + + IteratorRemoveVisitor(String iteratorName) { + super(); + this.iteratorName = iteratorName; + } + + 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 expression) { + super.visitMethodCallExpression(expression); + final PsiReferenceExpression methodExpression = expression.getMethodExpression(); + final String name = methodExpression.getReferenceName(); + if (!"remove".equals(name)) { + return; + } + final PsiExpression qualifier = methodExpression.getQualifierExpression(); + if (qualifier != null) { + final String qualifierText = qualifier.getText(); + if (iteratorName.equals(qualifierText)) { + removeCalled = true; + } + } + } + + public boolean isRemoveCalled() { + return removeCalled; + } + } + + private static class IndexOnlyUsedAsIndexVisitor extends PsiRecursiveElementVisitor { + private boolean indexVariableUsedOnlyAsIndex = true; + private final String arrayName; + private final PsiLocalVariable indexVariable; + + IndexOnlyUsedAsIndexVisitor(String arrayName, PsiLocalVariable indexVariable) { + super(); + this.arrayName = arrayName; + this.indexVariable = indexVariable; + } + + 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 element = ref.resolve(); + if (!indexVariable.equals(element)) { + return; + } + final PsiElement parent = ref.getParent(); + if (!(parent instanceof PsiArrayAccessExpression)) { + indexVariableUsedOnlyAsIndex = false; + return; + } + final PsiArrayAccessExpression arrayAccess = (PsiArrayAccessExpression) parent; + final PsiExpression arrayExpression = arrayAccess.getArrayExpression(); + if (arrayExpression == null) { + return; + } + if (!arrayExpression.getText().equals(arrayName)) { + indexVariableUsedOnlyAsIndex = false; + return; + } + final PsiElement arrayExpressionContext = arrayAccess.getParent(); + if (arrayExpressionContext instanceof PsiAssignmentExpression) { + final PsiAssignmentExpression assignment = (PsiAssignmentExpression) arrayExpressionContext; + final PsiExpression lhs = assignment.getLExpression(); + if (lhs.equals(arrayAccess)) { + indexVariableUsedOnlyAsIndex = false; + return; + } + } + } + + public boolean isIndexVariableUsedOnlyAsIndex() { + return indexVariableUsedOnlyAsIndex; + } + } +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/verbose/ForLoopReplaceableByWhileInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/verbose/ForLoopReplaceableByWhileInspection.java new file mode 100644 index 000000000000..87025ef22dc4 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/verbose/ForLoopReplaceableByWhileInspection.java @@ -0,0 +1,71 @@ +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 ForLoopReplaceableByWhileInspection extends StatementInspection { + private final ReplaceForByWhileFix fix = new ReplaceForByWhileFix(); + + public String getDisplayName() { + return "'for' loop may be replaced by 'while' loop"; + } + + public String getGroupDisplayName() { + return GroupNames.VERBOSE_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "'#ref' loop statement may be replace by 'while' loop #loc"; + } + + public InspectionGadgetsFix buildFix(PsiElement location) { + return fix; + } + + private static class ReplaceForByWhileFix extends InspectionGadgetsFix { + public String getName() { + return "Replace with 'while'"; + } + + public void applyFix(Project project, ProblemDescriptor descriptor) { + final PsiElement forKeywordElement = descriptor.getPsiElement(); + final PsiForStatement forStatement = + (PsiForStatement) forKeywordElement.getParent(); + final PsiExpression condition = forStatement.getCondition(); + final PsiStatement body = forStatement.getBody(); + final String whileStatement; + if (condition == null) { + whileStatement = "while(true)" + body.getText(); + } else { + whileStatement = "while(" + condition.getText() + ')' + body.getText(); + } + replaceStatement(project, forStatement, whileStatement); + } + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new ForLoopReplaceableByWhileVisitor(this, inspectionManager, onTheFly); + } + + private static class ForLoopReplaceableByWhileVisitor extends BaseInspectionVisitor { + private ForLoopReplaceableByWhileVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitForStatement(PsiForStatement statement) { + super.visitForStatement(statement); + final PsiStatement initialization = statement.getInitialization(); + if (initialization != null && !(initialization instanceof PsiEmptyStatement)) { + return; + } + final PsiStatement update = statement.getUpdate(); + if (update != null && !(update instanceof PsiEmptyStatement)) { + return; + } + registerStatementError(statement); + } + } +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/verbose/PointlessArithmeticExpressionInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/verbose/PointlessArithmeticExpressionInspection.java new file mode 100644 index 000000000000..d2011d34599c --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/verbose/PointlessArithmeticExpressionInspection.java @@ -0,0 +1,160 @@ +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.intellij.psi.tree.IElementType; +import com.intellij.psi.util.ConstantExpressionUtil; +import com.intellij.psi.util.IsConstantExpressionVisitor; +import com.siyeh.ig.*; +import com.siyeh.ig.psiutils.TypeUtils; + +public class PointlessArithmeticExpressionInspection extends ExpressionInspection { + private final PointlessArithmeticFix fix = new PointlessArithmeticFix(); + + public String getDisplayName() { + return "Pointless arithmetic expression"; + } + + public String getGroupDisplayName() { + return GroupNames.VERBOSE_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "#ref can be replaced with " + + calculateReplacementExpression((PsiExpression) location) + " #loc"; + } + + private static String calculateReplacementExpression(PsiExpression expression) { + final PsiExpression lhs; + final PsiExpression rhs; + final PsiBinaryExpression exp = (PsiBinaryExpression) expression; + final PsiJavaToken sign = exp.getOperationSign(); + lhs = exp.getLOperand(); + rhs = exp.getROperand(); + final IElementType tokenType = sign.getTokenType(); + if (tokenType.equals(JavaTokenType.PLUS)) { + if (isZero(lhs)) { + return rhs.getText(); + } else { + return lhs.getText(); + } + } else if (tokenType.equals(JavaTokenType.MINUS)) { + return lhs.getText(); + } else if (tokenType.equals(JavaTokenType.ASTERISK)) { + if (isOne(lhs)) { + return rhs.getText(); + } else if (isOne(rhs)) { + return lhs.getText(); + } else { + return "0"; + } + } else if (tokenType.equals(JavaTokenType.DIV)) { + return lhs.getText(); + } else { + return ""; + } + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new PointlessArithmeticVisitor(this, inspectionManager, onTheFly); + } + + public InspectionGadgetsFix buildFix(PsiElement location) { + return fix; + } + + private static class PointlessArithmeticFix extends InspectionGadgetsFix { + public String getName() { + return "Simplify"; + } + + public void applyFix(Project project, ProblemDescriptor descriptor) { + final PsiExpression expression = (PsiExpression) descriptor.getPsiElement(); + final String newExpression = calculateReplacementExpression(expression); + replaceExpression(project, expression, newExpression); + } + + } + + private static class PointlessArithmeticVisitor extends BaseInspectionVisitor { + private PointlessArithmeticVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitBinaryExpression(PsiBinaryExpression expression) { + super.visitBinaryExpression(expression); + if (TypeUtils.expressionHasType("java.lang.String", expression)) { + return; + } + final PsiJavaToken sign = expression.getOperationSign(); + if (sign == null) { + return; + } + final PsiExpression rhs = expression.getROperand(); + final PsiExpression lhs = expression.getLOperand(); + final IElementType tokenType = sign.getTokenType(); + final boolean isPointless; + if (tokenType.equals(JavaTokenType.PLUS)) { + isPointless = additionExpressionIsPointless(lhs, rhs); + } else if (tokenType.equals(JavaTokenType.MINUS)) { + isPointless = subtractionExpressionIsPointless(rhs); + } else if (tokenType.equals(JavaTokenType.ASTERISK)) { + isPointless = multiplyExpressionIsPointless(lhs, rhs); + } else if (tokenType.equals(JavaTokenType.DIV)) { + isPointless = divideExpressionIsPointless(rhs); + } else { + isPointless = false; + } + if (!isPointless) { + return; + } + registerError(expression); + } + } + + private static boolean subtractionExpressionIsPointless(PsiExpression rhs) { + return isZero(rhs); + } + + private static boolean additionExpressionIsPointless(PsiExpression lhs, PsiExpression rhs) { + return isZero(lhs) || isZero(rhs); + } + + private static boolean multiplyExpressionIsPointless(PsiExpression lhs, PsiExpression rhs) { + return isZero(lhs) || isZero(rhs) || isOne(lhs) || isOne(rhs); + } + + private static boolean divideExpressionIsPointless(PsiExpression rhs) { + return isOne(rhs); + } + + private static boolean isZero(PsiExpression expression) { + if (expression == null) { + return false; + } + final IsConstantExpressionVisitor visitor = new IsConstantExpressionVisitor(); + expression.accept(visitor); + if (!visitor.isConstant()) { + return false; + } + final Double value = (Double) ConstantExpressionUtil.computeCastTo(expression, PsiType.DOUBLE); + return value != null && value.doubleValue() == 0.0; + } + + private static boolean isOne(PsiExpression expression) { + if (expression == null) { + return false; + } + final IsConstantExpressionVisitor visitor = + new IsConstantExpressionVisitor(); + expression.accept(visitor); + if (!visitor.isConstant()) { + return false; + } + final Double value = (Double) ConstantExpressionUtil.computeCastTo(expression, PsiType.DOUBLE); + return value != null && value.doubleValue() == 1.0; + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/verbose/PointlessBitwiseExpressionInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/verbose/PointlessBitwiseExpressionInspection.java new file mode 100644 index 000000000000..ca917497ebec --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/verbose/PointlessBitwiseExpressionInspection.java @@ -0,0 +1,226 @@ +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.intellij.psi.tree.IElementType; +import com.intellij.psi.util.IsConstantExpressionVisitor; +import com.intellij.psi.util.ConstantExpressionUtil; +import com.siyeh.ig.*; + +public class PointlessBitwiseExpressionInspection extends ExpressionInspection { + private final PointlessBitwiseFix fix = new PointlessBitwiseFix(); + + + public String getDisplayName() { + return "Pointless bitwise expression"; + } + + public String getGroupDisplayName() { + return GroupNames.VERBOSE_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "#ref can be replaced with " + + calculateReplacementExpression((PsiExpression) location) + " #loc"; + } + + private static String calculateReplacementExpression(PsiExpression expression) { + final PsiBinaryExpression exp = (PsiBinaryExpression) expression; + final PsiExpression lhs = exp.getLOperand(); + final PsiExpression rhs = exp.getROperand(); + final PsiJavaToken sign = exp.getOperationSign(); + final IElementType tokenType = sign.getTokenType(); + final PsiType expressionType = exp.getType(); + if (tokenType.equals(JavaTokenType.AND)) { + if (isZero(lhs, expressionType) || isAllOnes(rhs, expressionType)) { + return lhs.getText(); + } else { + return rhs.getText(); + } + } else if (tokenType.equals(JavaTokenType.OR)) { + if (isZero(lhs, expressionType) || isAllOnes(rhs, expressionType)) { + return rhs.getText(); + } else { + return lhs.getText(); + } + } else if (tokenType.equals(JavaTokenType.XOR)) { + if (isAllOnes(lhs, expressionType)) { + return '~' + rhs.getText(); + } else if (isAllOnes(rhs, expressionType)) { + return '~' + lhs.getText(); + } else if (isZero(rhs, expressionType)) { + return lhs.getText(); + } else { + return rhs.getText(); + } + } else if (tokenType.equals(JavaTokenType.LTLT) || + tokenType.equals(JavaTokenType.GTGT) || + tokenType.equals(JavaTokenType.GTGTGT)) { + return lhs.getText(); + } else { + return ""; + } + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new PointlessBitwiseVisitor(this, inspectionManager, onTheFly); + } + + public InspectionGadgetsFix buildFix(PsiElement location) { + return fix; + } + + private static class PointlessBitwiseFix extends InspectionGadgetsFix { + public String getName() { + return "Simplify"; + } + + public void applyFix(Project project, ProblemDescriptor descriptor) { + final PsiExpression expression = (PsiExpression) descriptor.getPsiElement(); + final String newExpression = calculateReplacementExpression(expression); + replaceExpression(project, expression, newExpression); + } + + } + + private static class PointlessBitwiseVisitor extends BaseInspectionVisitor { + private PointlessBitwiseVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitBinaryExpression(PsiBinaryExpression expression) { + super.visitBinaryExpression(expression); + final PsiType expressionType = expression.getType(); + if (expressionType == null) { + return; + } + final PsiJavaToken sign = expression.getOperationSign(); + if (sign == null) { + return; + } + final PsiExpression rhs = expression.getROperand(); + if (rhs == null) { + return; + } + + final PsiType rhsType = rhs.getType(); + if (rhsType == null) { + return; + } + if (rhsType.equals(PsiType.BOOLEAN) || + "java.lang.Boolean".equals(rhsType.getCanonicalText())) { + return; + } + final PsiExpression lhs = expression.getLOperand(); + if (lhs == null) { + return; + } + final PsiType lhsType = lhs.getType(); + if (lhsType == null) { + return; + } + if (lhsType.equals(PsiType.BOOLEAN) || + "java.lang.Boolean".equals(lhsType.getCanonicalText())) { + return; + } + final IElementType tokenType = sign.getTokenType(); + final boolean isPointless; + if (tokenType.equals(JavaTokenType.AND)) { + isPointless = andExpressionIsPointless(lhs, rhs, expressionType); + } else if (tokenType.equals(JavaTokenType.OR)) { + isPointless = orExpressionIsPointless(lhs, rhs, expressionType); + } else if (tokenType.equals(JavaTokenType.XOR)) { + isPointless = xorExpressionIsPointless(lhs, rhs, expressionType); + } else if (tokenType.equals(JavaTokenType.LTLT) || + tokenType.equals(JavaTokenType.GTGT) || + tokenType.equals(JavaTokenType.GTGTGT)) { + isPointless = shiftExpressionIsPointless(rhs, expressionType); + } else { + isPointless = false; + } + if (!isPointless) { + return; + } + registerError(expression); + } + } + + private static boolean shiftExpressionIsPointless(PsiExpression rhs, PsiType expressionType) { + return isZero(rhs, expressionType); + } + + private static boolean orExpressionIsPointless(PsiExpression lhs, PsiExpression rhs, PsiType expressionType) { + return isZero(lhs, expressionType) || isZero(rhs, expressionType) || isAllOnes(lhs, expressionType) || isAllOnes(rhs, expressionType); + } + + private static boolean xorExpressionIsPointless(PsiExpression lhs, PsiExpression rhs, PsiType expressionType) { + return isZero(lhs, expressionType) || isZero(rhs, expressionType) || isAllOnes(lhs, expressionType) || isAllOnes(rhs, expressionType); + } + + private static boolean andExpressionIsPointless(PsiExpression lhs, PsiExpression rhs, PsiType expressionType) { + return isZero(lhs, expressionType) || isZero(rhs, expressionType) || isAllOnes(lhs, expressionType) || isAllOnes(rhs, expressionType); + } + + private static boolean isZero(PsiExpression expression, PsiType expressionType) { + final IsConstantExpressionVisitor visitor = + new IsConstantExpressionVisitor(); + expression.accept(visitor); + if (!visitor.isConstant()) { + return false; + } + final Object value = + ConstantExpressionUtil.computeCastTo(expression, expressionType); + if (value == null) { + return false; + } + if (value instanceof Integer && ((Integer) value).intValue() == 0) { + return true; + } + if (value instanceof Long && ((Long) value).longValue() == 0L) { + return true; + } + if (value instanceof Short && ((Short) value).shortValue() == 0) { + return true; + } + if (value instanceof Character && ((Character) value).charValue() == 0) { + return true; + } + if (value instanceof Byte && ((Byte) value).byteValue() == 0) { + return true; + } + return false; + } + + private static boolean isAllOnes(PsiExpression expression, PsiType expressionType) { + final IsConstantExpressionVisitor visitor = + new IsConstantExpressionVisitor(); + expression.accept(visitor); + if (!visitor.isConstant()) { + return false; + } + final Object value = + ConstantExpressionUtil.computeCastTo(expression, expressionType); + if (value == null) { + return false; + } + if (value instanceof Integer && ((Integer) value).intValue() == 0xffffffff) { + return true; + } + if (value instanceof Long && ((Long) value).longValue() == 0xffffffffffffffffL) { + return true; + } + if (value instanceof Short && ((Short) value).shortValue() == (short) 0xffff) { + return true; + } + if (value instanceof Character && ((Character) value).charValue() == (char) 0xffff) { + return true; + } + if (value instanceof Byte && ((Byte) value).byteValue() == (byte) 0xff) { + return true; + } + return false; + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/verbose/PointlessBooleanExpressionInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/verbose/PointlessBooleanExpressionInspection.java new file mode 100644 index 000000000000..277fb039e4e7 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/verbose/PointlessBooleanExpressionInspection.java @@ -0,0 +1,229 @@ +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.intellij.psi.tree.IElementType; +import com.intellij.psi.util.IsConstantExpressionVisitor; +import com.intellij.psi.util.ConstantExpressionUtil; +import com.siyeh.ig.*; + +public class PointlessBooleanExpressionInspection extends ExpressionInspection { + private final BooleanLiteralComparisonFix fix = new BooleanLiteralComparisonFix(); + + public String getDisplayName() { + return "Pointless boolean expression"; + } + + public String getGroupDisplayName() { + return GroupNames.VERBOSE_GROUP_NAME; + } + + protected BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new PointlessBooleanExpressionVisitor(this, inspectionManager, onTheFly); + } + + public String buildErrorString(PsiElement location) { + if (location instanceof PsiBinaryExpression) { + return "#ref can be simplified to " + + calculateSimplifiedBinaryExpression((PsiBinaryExpression) location) + " #loc"; + } else { + return "#ref can be simplified to " + + calculateSimplifiedPrefixExpression((PsiPrefixExpression) location) + " #loc"; + } + } + + private static String calculateSimplifiedBinaryExpression(PsiBinaryExpression expression) { + final PsiJavaToken sign = expression.getOperationSign(); + final PsiExpression lhs = expression.getLOperand(); + + final PsiExpression rhs = expression.getROperand(); + if (rhs == null) { + return null; + } + final IElementType tokenType = sign.getTokenType(); + final String rhsText = rhs.getText(); + final String lhsText = lhs.getText(); + if (tokenType.equals(JavaTokenType.ANDAND) || tokenType.equals(JavaTokenType.AND)) { + if (isTrue(lhs)) { + return rhsText; + } else { + return lhsText; + } + } else if (tokenType.equals(JavaTokenType.OROR) || tokenType.equals(JavaTokenType.OR)) { + if (isFalse(lhs)) { + return rhsText; + } else { + return lhsText; + } + } else if (tokenType.equals(JavaTokenType.XOR) || tokenType.equals(JavaTokenType.NE)) { + if (isFalse(lhs)) { + return rhsText; + } else if (isFalse(rhs)) { + return lhsText; + } else if (isTrue(lhs)) { + return '!' + rhsText; + } else { + return '!' + lhsText; + } + } else if (tokenType.equals(JavaTokenType.EQEQ)) { + if (isTrue(lhs)) { + return rhsText; + } else if (isTrue(rhs)) { + return lhsText; + } else if (isFalse(lhs)) { + return '!' + rhsText; + } else { + return '!' + lhsText; + } + } else { + return ""; + } + } + + private static String calculateSimplifiedPrefixExpression(PsiPrefixExpression expression) { + final PsiExpression operand = expression.getOperand(); + if (isTrue(operand)) { + return "false"; + } else { + return "true"; + } + } + + public InspectionGadgetsFix buildFix(PsiElement location) { + return fix; + } + + private static class BooleanLiteralComparisonFix extends InspectionGadgetsFix { + public String getName() { + return "Simplify"; + } + + public void applyFix(Project project, ProblemDescriptor descriptor) { + final PsiBinaryExpression expression = (PsiBinaryExpression) descriptor.getPsiElement(); + final String replacementString = calculateSimplifiedBinaryExpression(expression); + replaceExpression(project, expression, replacementString); + } + + } + + private static class PointlessBooleanExpressionVisitor extends BaseInspectionVisitor { + private PointlessBooleanExpressionVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitBinaryExpression(PsiBinaryExpression expression) { + super.visitBinaryExpression(expression); + final PsiJavaToken sign = expression.getOperationSign(); + if (sign == null) { + return; + } + final PsiExpression rhs = expression.getROperand(); + if (rhs == null) { + return; + } + + final PsiType rhsType = rhs.getType(); + if (rhsType == null) { + return; + } + if (!rhsType.equals(PsiType.BOOLEAN) && + !"java.lang.Boolean".equals(rhsType.getCanonicalText())) { + return; + } + final PsiExpression lhs = expression.getLOperand(); + if (lhs == null) { + return; + } + final PsiType lhsType = lhs.getType(); + if (lhsType == null) { + return; + } + if (!lhsType.equals(PsiType.BOOLEAN) && + !"java.lang.Boolean".equals(lhsType.getCanonicalText())) { + return; + } + final IElementType tokenType = sign.getTokenType(); + final boolean isPointless; + if (tokenType.equals(JavaTokenType.EQEQ) || tokenType.equals(JavaTokenType.NE)) { + isPointless = equalityExpressionIsPointless(lhs, rhs); + } else if (tokenType.equals(JavaTokenType.ANDAND) || tokenType.equals(JavaTokenType.AND)) { + isPointless = andExpressionIsPointless(lhs, rhs); + } else if (tokenType.equals(JavaTokenType.OROR) || tokenType.equals(JavaTokenType.OR)) { + isPointless = orExpressionIsPointless(lhs, rhs); + } else if (tokenType.equals(JavaTokenType.XOR)) { + isPointless = xorExpressionIsPointless(lhs, rhs); + } else { + isPointless = false; + } + if (!isPointless) { + return; + } + registerError(expression); + } + + public void visitPrefixExpression(PsiPrefixExpression expression) { + super.visitPrefixExpression(expression); + final PsiJavaToken sign = expression.getOperationSign(); + if (sign == null) { + return; + } + final PsiExpression operand = expression.getOperand(); + final IElementType tokenType = sign.getTokenType(); + if (!(tokenType != JavaTokenType.EXCL || !notExpressionIsPointless(operand))) { + registerError(expression); + } + } + } + + private static boolean equalityExpressionIsPointless(PsiExpression lhs, PsiExpression rhs) { + return isTrue(lhs) || isTrue(rhs) || isFalse(lhs) || isFalse(rhs); + } + + private static boolean andExpressionIsPointless(PsiExpression lhs, PsiExpression rhs) { + return isTrue(lhs) || isTrue(rhs); + } + + private static boolean orExpressionIsPointless(PsiExpression lhs, PsiExpression rhs) { + return isFalse(lhs) || isFalse(rhs); + } + + private static boolean xorExpressionIsPointless(PsiExpression lhs, PsiExpression rhs) { + return isTrue(lhs) || isTrue(rhs) || isFalse(lhs) || isFalse(rhs); + } + + private static boolean notExpressionIsPointless(PsiExpression arg) { + return isFalse(arg) || isTrue(arg); + } + + private static boolean isTrue(PsiExpression expression) { + if (expression == null) { + return false; + } + final IsConstantExpressionVisitor visitor = + new IsConstantExpressionVisitor(); + expression.accept(visitor); + if (!visitor.isConstant()) { + return false; + } + final Boolean value = + (Boolean) ConstantExpressionUtil.computeCastTo(expression, PsiType.BOOLEAN); + return value != null && value.booleanValue(); + } + + private static boolean isFalse(PsiExpression expression) { + if (expression == null) { + return false; + } + final IsConstantExpressionVisitor visitor = + new IsConstantExpressionVisitor(); + expression.accept(visitor); + if (!visitor.isConstant()) { + return false; + } + final Boolean value = + (Boolean) ConstantExpressionUtil.computeCastTo(expression, PsiType.BOOLEAN); + return value != null && !value.booleanValue(); + } +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/verbose/RedundantImplementsInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/verbose/RedundantImplementsInspection.java new file mode 100644 index 000000000000..7fe54e3a1508 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/verbose/RedundantImplementsInspection.java @@ -0,0 +1,147 @@ +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.PsiClass; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiJavaCodeReferenceElement; +import com.intellij.psi.PsiReferenceList; +import com.siyeh.ig.*; + +public class RedundantImplementsInspection extends ClassInspection { + private final RedundantImplementsFix fix = new RedundantImplementsFix(); + + public String getDisplayName() { + return "Redundant interface declaration"; + } + + public String getGroupDisplayName() { + return GroupNames.VERBOSE_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "Redundant interface declaration '#ref' #loc"; + } + + protected InspectionGadgetsFix buildFix(PsiElement location) { + return fix; + } + + private static class RedundantImplementsFix extends InspectionGadgetsFix { + public String getName() { + return "Remove redundant interface declaration"; + } + + public void applyFix(Project project, ProblemDescriptor problemDescriptor) { + final PsiElement implementReference = problemDescriptor.getPsiElement(); + deleteElement(implementReference); + } + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new RedundantImplementsVisitor(this, inspectionManager, onTheFly); + } + + private static class RedundantImplementsVisitor extends BaseInspectionVisitor { + + private RedundantImplementsVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitClass(PsiClass aClass) { + if(aClass.isAnnotationType()) + { + return; + } + if (aClass.isInterface()) { + checkInterface(aClass); + } else { + checkConcreteClass(aClass); + } + } + + private void checkInterface(PsiClass aClass) { + final PsiReferenceList extendsList = aClass.getExtendsList(); + final PsiJavaCodeReferenceElement[] extendsElements = + extendsList.getReferenceElements(); + for (int i = 0; i < extendsElements.length; i++) { + final PsiJavaCodeReferenceElement implementsElement = extendsElements[i]; + final PsiElement referent = implementsElement.resolve(); + if (referent != null && referent instanceof PsiClass) { + final PsiClass implementedClass = (PsiClass) referent; + checkExtendedInterface(implementedClass, implementsElement, extendsElements); + } + } + } + + + private void checkConcreteClass(PsiClass aClass) { + final PsiReferenceList extendsList = aClass.getExtendsList(); + final PsiReferenceList implementsList = aClass.getImplementsList(); + if (extendsList == null || implementsList == null) { + return; + } + final PsiJavaCodeReferenceElement[] extendsElements = + extendsList.getReferenceElements(); + final PsiJavaCodeReferenceElement[] implementsElements = + implementsList.getReferenceElements(); + for (int i = 0; i < implementsElements.length; i++) { + final PsiJavaCodeReferenceElement implementsElement = implementsElements[i]; + final PsiElement referent = implementsElement.resolve(); + if (referent != null && referent instanceof PsiClass) { + final PsiClass implementedClass = (PsiClass) referent; + checkImplementedClass(implementedClass, implementsElement, extendsElements, implementsElements); + } + } + } + + private void checkImplementedClass(PsiClass implementedClass, + PsiJavaCodeReferenceElement implementsElement, + PsiJavaCodeReferenceElement[] extendsElements, PsiJavaCodeReferenceElement[] implementsElements) { + for (int j = 0; j < extendsElements.length; j++) { + final PsiJavaCodeReferenceElement extendsElement = extendsElements[j]; + final PsiElement extendsReferent = extendsElement.resolve(); + if (extendsReferent != null && extendsReferent instanceof PsiClass) { + final PsiClass extendedClass = (PsiClass) extendsReferent; + if (extendedClass.isInheritor(implementedClass, false)) { + registerError(implementsElement); + return; + } + } + } + for (int j = 0; j < implementsElements.length; j++) { + final PsiJavaCodeReferenceElement testImplementElement = implementsElements[j]; + if (!testImplementElement.equals(implementsElement)) { + final PsiElement implementsReferent = testImplementElement.resolve(); + if (implementsReferent != null && implementsReferent instanceof PsiClass) { + final PsiClass testImplementedClass = (PsiClass) implementsReferent; + if (testImplementedClass.isInheritor(implementedClass, false)) { + registerError(implementsElement); + return; + } + } + } + } + } + + private void checkExtendedInterface(PsiClass implementedClass, PsiJavaCodeReferenceElement implementsElement, + PsiJavaCodeReferenceElement[] extendsElements) { + + for (int j = 0; j < extendsElements.length; j++) { + final PsiJavaCodeReferenceElement testImplementElement = extendsElements[j]; + if (!testImplementElement.equals(implementsElement)) { + final PsiElement implementsReferent = testImplementElement.resolve(); + if (implementsReferent != null && implementsReferent instanceof PsiClass) { + final PsiClass testImplementedClass = (PsiClass) implementsReferent; + if (testImplementedClass.isInheritor(implementedClass, false)) { + registerError(implementsElement); + return; + } + } + } + } + } + + } +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/verbose/ReplaceAssignmentWithOperatorAssignmentInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/verbose/ReplaceAssignmentWithOperatorAssignmentInspection.java new file mode 100644 index 000000000000..d3ede5311e54 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/verbose/ReplaceAssignmentWithOperatorAssignmentInspection.java @@ -0,0 +1,112 @@ +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.*; +import com.siyeh.ig.psiutils.ExpressionEquivalenceChecker; +import com.siyeh.ig.psiutils.SideEffectChecker; + +public class ReplaceAssignmentWithOperatorAssignmentInspection extends ExpressionInspection { + + public String getDisplayName() { + return "Assignment replaceable with operator assignment"; + } + + public String getGroupDisplayName() { + return GroupNames.VERBOSE_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "#ref could be simplified to " + + calculateReplacementExpression((PsiAssignmentExpression) location) + " #loc"; + } + + private static String calculateReplacementExpression(PsiAssignmentExpression expression) { + final PsiBinaryExpression rhs = (PsiBinaryExpression) expression.getRExpression(); + final PsiExpression lhs = expression.getLExpression(); + final PsiJavaToken sign = rhs.getOperationSign(); + final PsiExpression rhsRhs = rhs.getROperand(); + final String newExpression = lhs.getText() + ' ' + sign.getText() + "= " + rhsRhs.getText(); + return newExpression; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new ReplaceAssignmentWithOperatorAssignmentVisitor(this, inspectionManager, onTheFly); + } + + public InspectionGadgetsFix buildFix(PsiElement location) { + return new ReplaceAssignmentWithOperatorAssignmentFix((PsiAssignmentExpression) location); + } + + private static class ReplaceAssignmentWithOperatorAssignmentFix extends InspectionGadgetsFix { + private final String m_name; + + private ReplaceAssignmentWithOperatorAssignmentFix(PsiAssignmentExpression expression) { + super(); + final PsiBinaryExpression rhs = (PsiBinaryExpression) expression.getRExpression(); + final PsiJavaToken sign = rhs.getOperationSign(); + m_name = "Replace = with " + sign.getText() + '='; + } + + public String getName() { + return m_name; + } + + public void applyFix(Project project, ProblemDescriptor descriptor) { + final PsiAssignmentExpression expression = + (PsiAssignmentExpression) descriptor.getPsiElement(); + final String newExpression = calculateReplacementExpression(expression); + replaceExpression(project, expression, newExpression); + } + + } + + private static class ReplaceAssignmentWithOperatorAssignmentVisitor extends BaseInspectionVisitor { + private ReplaceAssignmentWithOperatorAssignmentVisitor(BaseInspection inspection, + InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitAssignmentExpression(PsiAssignmentExpression assignment) { + super.visitAssignmentExpression(assignment); + final PsiJavaToken sign = assignment.getOperationSign(); + if (sign == null) { + return; + } + if (sign.getTokenType() != JavaTokenType.EQ) { + return; + } + final PsiExpression lhs = assignment.getLExpression(); + final PsiExpression rhs = assignment.getRExpression(); + if (lhs == null || rhs == null) { + return; + } + if (!(rhs instanceof PsiBinaryExpression)) { + return; + } + final PsiBinaryExpression binaryRhs = (PsiBinaryExpression) rhs; + final PsiJavaToken operatorSign = binaryRhs.getOperationSign(); + if (operatorSign.getTokenType() == JavaTokenType.OROR || + operatorSign.getTokenType() == JavaTokenType.ANDAND) { + return; + } + final PsiExpression lOperand = binaryRhs.getLOperand(); + if (lOperand == null) { + return; + } + final PsiExpression rOperand = binaryRhs.getROperand(); + if (rOperand == null) { + return; + } + if (SideEffectChecker.mayHaveSideEffects(lhs)) { + return; + } + if (!ExpressionEquivalenceChecker.expressionsAreEquivalent(lhs, lOperand)) { + return; + } + registerError(assignment); + } + } +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/verbose/TrivialIfInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/verbose/TrivialIfInspection.java new file mode 100644 index 000000000000..7e847da541cc --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/verbose/TrivialIfInspection.java @@ -0,0 +1,184 @@ +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.*; +import com.siyeh.ig.psiutils.BoolUtils; +import com.siyeh.ig.psiutils.ControlFlowUtils; +import com.siyeh.ig.psiutils.ExpressionEquivalenceChecker; + +public class TrivialIfInspection extends ExpressionInspection { + private final TrivialIfFix fix = new TrivialIfFix(); + + public String getDisplayName() { + return "Unnecessary 'if' statement"; + } + + public String getGroupDisplayName() { + return GroupNames.VERBOSE_GROUP_NAME; + } + + protected BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new TrivialIfVisitor(this, inspectionManager, onTheFly); + } + + public String buildErrorString(PsiElement location) { + final PsiIfStatement ifStatement = (PsiIfStatement) location.getParent(); + final PsiExpression condition = ifStatement.getCondition(); + return "'if(" + condition.getText() + ")...' can be simplified to '" + + calculateReplacementStatement(ifStatement) + + "' #loc"; + } + + private static String calculateReplacementStatement(PsiIfStatement statement) { + PsiStatement thenBranch = statement.getThenBranch(); + thenBranch = ControlFlowUtils.stripBraces(thenBranch); + final PsiExpression condition = statement.getCondition(); + final String replacementString; + if (thenBranch instanceof PsiReturnStatement) { + if (isReturn(thenBranch, "true")) { + replacementString = "return " + condition.getText() + ';'; + } else { + replacementString = + "return " + BoolUtils.getNegatedExpressionText(condition) + ';'; + } + } else { + final PsiExpressionStatement expressionStatement = (PsiExpressionStatement) thenBranch; + final PsiAssignmentExpression assignment = (PsiAssignmentExpression) expressionStatement.getExpression(); + + final PsiExpression lhs = assignment.getLExpression(); + final PsiJavaToken sign = assignment.getOperationSign(); + if (isAssignment(thenBranch, "true")) { + replacementString = lhs.getText() + ' ' + + sign.getText() + ' ' + condition.getText() + ';'; + } else { + replacementString = lhs.getText() + ' ' + + sign.getText() + ' ' + + BoolUtils.getNegatedExpressionText(condition) + ';'; + } + } + return replacementString; + } + + public InspectionGadgetsFix buildFix(PsiElement location) { + return fix; + } + + private static class TrivialIfFix extends InspectionGadgetsFix { + public String getName() { + return "Simplify"; + } + + public void applyFix(Project project, ProblemDescriptor descriptor) { + final PsiElement ifKeywordElement = descriptor.getPsiElement(); + final PsiIfStatement ifStatement = (PsiIfStatement) ifKeywordElement.getParent(); + final String newStatement = calculateReplacementStatement(ifStatement); + replaceStatement(project, ifStatement, newStatement); + } + } + + private static class TrivialIfVisitor extends BaseInspectionVisitor { + private TrivialIfVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitIfStatement(PsiIfStatement statement) { + super.visitIfStatement(statement); + if (statement.getCondition() == null) { + return; + } + PsiStatement thenBranch = statement.getThenBranch(); + if (thenBranch == null) { + return; + } + thenBranch = ControlFlowUtils.stripBraces(thenBranch); + PsiStatement elseBranch = statement.getElseBranch(); + if (elseBranch == null) { + return; + } + elseBranch = ControlFlowUtils.stripBraces(elseBranch); + + if (isReturn(thenBranch, "true") && isReturn(elseBranch, "false")) { + registerStatementError(statement); + return; + } + if (isReturn(thenBranch, "false") && isReturn(elseBranch, "true")) { + registerStatementError(statement); + return; + } + if (isAssignment(thenBranch, "true") && isAssignment(elseBranch, "false") && + areCompatibleAssignments(thenBranch, elseBranch)) { + registerStatementError(statement); + return; + } + if (isAssignment(thenBranch, "false") && isAssignment(elseBranch, "true") && + areCompatibleAssignments(thenBranch, elseBranch)) { + registerStatementError(statement); + return; + } + } + + } + + private static boolean isReturn(PsiStatement statement, String value) { + if (statement == null) { + return false; + } + if (!(statement instanceof PsiReturnStatement)) { + return false; + } + final PsiReturnStatement returnStatement = (PsiReturnStatement) statement; + final PsiExpression returnValue = returnStatement.getReturnValue(); + if (returnValue == null) { + return false; + } + final String returnValueString = returnValue.getText(); + return value.equals(returnValueString); + } + + private static boolean isAssignment(PsiStatement statement, String value) { + if (statement == null) { + return false; + } + if (!(statement instanceof PsiExpressionStatement)) { + return false; + } + final PsiExpression expression = ((PsiExpressionStatement) statement).getExpression(); + if (!(expression instanceof PsiAssignmentExpression)) { + return false; + } + final PsiExpression rhs = ((PsiAssignmentExpression) expression).getRExpression(); + if (rhs == null) { + return false; + } + final String rhsText = rhs.getText(); + return value.equals(rhsText); + } + + private static boolean areCompatibleAssignments(PsiStatement statement1, PsiStatement statement2) { + final PsiExpressionStatement expressionStatement1 = (PsiExpressionStatement) statement1; + final PsiAssignmentExpression expression1 = (PsiAssignmentExpression) expressionStatement1.getExpression(); + final PsiExpressionStatement expressionStatement2 = (PsiExpressionStatement) statement2; + final PsiAssignmentExpression expression2 = (PsiAssignmentExpression) expressionStatement2.getExpression(); + + final PsiJavaToken sign2 = expression2.getOperationSign(); + if (sign2 == null) { + return false; + } + final String operand2 = sign2.getText(); + final PsiJavaToken sign1 = expression1.getOperationSign(); + if (sign1 == null) { + return false; + } + final String operand1 = sign1.getText(); + if (!operand2.equals(operand1)) { + return false; + } + final PsiExpression lhs1 = expression1.getLExpression(); + final PsiExpression lhs2 = expression2.getLExpression(); + return ExpressionEquivalenceChecker.expressionsAreEquivalent(lhs1, lhs2); + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/verbose/TypeParameterExtendsObjectInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/verbose/TypeParameterExtendsObjectInspection.java new file mode 100644 index 000000000000..b760b6a61c09 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/verbose/TypeParameterExtendsObjectInspection.java @@ -0,0 +1,72 @@ +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 TypeParameterExtendsObjectInspection extends ClassInspection { + private final ExtendsObjectFix fix = new ExtendsObjectFix(); + + public String getDisplayName() { + return "Type parameter explicitly extends java.lang.Object"; + } + + public String getGroupDisplayName() { + return GroupNames.VERBOSE_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "Type parameter '#ref' explicitly extends java.lang.Object #loc"; + } + + protected InspectionGadgetsFix buildFix(PsiElement location) { + return fix; + } + + private static class ExtendsObjectFix extends InspectionGadgetsFix { + public String getName() { + return "Remove redundant 'extends Object'"; + } + + public void applyFix(Project project, ProblemDescriptor problemDescriptor) { + final PsiElement extendClassIdentifier = problemDescriptor.getPsiElement(); + final PsiTypeParameter element = (PsiTypeParameter) extendClassIdentifier.getParent(); + final PsiReferenceList extendsList = element.getExtendsList(); + final PsiJavaCodeReferenceElement[] elements = extendsList.getReferenceElements(); + for (int i = 0; i < elements.length; i++) { + deleteElement(elements[i]); + } + } + + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new ExtendsObjectVisitor(this, inspectionManager, onTheFly); + } + + private static class ExtendsObjectVisitor extends BaseInspectionVisitor { + + private ExtendsObjectVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitTypeParameter(PsiTypeParameter parameter) { + super.visitTypeParameter(parameter); + final PsiIdentifier nameIdentifier = parameter.getNameIdentifier(); + final PsiReferenceList extendsList = parameter.getExtendsList(); + if (extendsList != null) { + final PsiJavaCodeReferenceElement[] elements = extendsList.getReferenceElements(); + for (int i = 0; i < elements.length; i++) { + final PsiJavaCodeReferenceElement element = elements[i]; + final String text = element.getText(); + if ("Object".equals(text) || "java.lang.Object".equals(text)) { + registerError(nameIdentifier); + } + } + } + } + + } +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/verbose/UnnecessaryBlockStatementInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/verbose/UnnecessaryBlockStatementInspection.java new file mode 100644 index 000000000000..949d677d7a6d --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/verbose/UnnecessaryBlockStatementInspection.java @@ -0,0 +1,110 @@ +package com.siyeh.ig.verbose; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.codeInspection.ProblemDescriptor; +import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.project.Project; +import com.intellij.psi.*; +import com.intellij.psi.codeStyle.CodeStyleManager; +import com.intellij.util.IncorrectOperationException; +import com.siyeh.ig.*; + +public class UnnecessaryBlockStatementInspection extends StatementInspection { + private final UnnecessaryBlockFix fix = new UnnecessaryBlockFix(); + + public String getDisplayName() { + return "Unnecessary code block"; + } + + public String getGroupDisplayName() { + return GroupNames.VERBOSE_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "Braces around this statement are unnecessary #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new UnnecessaryBlockStatementVisitor(this, inspectionManager, onTheFly); + } + + public InspectionGadgetsFix buildFix(PsiElement location) { + return fix; + } + + private static class UnnecessaryBlockFix extends InspectionGadgetsFix { + public String getName() { + return "Unwrap block"; + } + + public void applyFix(Project project, ProblemDescriptor descriptor) { + final PsiElement leftBrace = descriptor.getPsiElement(); + final PsiCodeBlock block = (PsiCodeBlock) leftBrace.getParent(); + final PsiBlockStatement blockStatement = (PsiBlockStatement) block.getParent(); + final PsiElement containingElement = blockStatement.getParent(); + try { + final PsiManager psiManager = PsiManager.getInstance(project); + final CodeStyleManager styleManager = psiManager.getCodeStyleManager(); + + final PsiElement[] children = block.getChildren(); + for (int i = 1; i < children.length - 1; i++) { + final PsiElement child = children[i]; + final PsiElement childCopy = child.copy(); + final PsiElement copiedElement = containingElement.addBefore(childCopy, blockStatement); + styleManager.reformat(copiedElement); + } + blockStatement.delete(); + styleManager.reformat(containingElement); + } catch (IncorrectOperationException e) { + final Class aClass = getClass(); + final String className = aClass.getName(); + final Logger logger = Logger.getInstance(className); + logger.error(e); + } + } + } + + private static class UnnecessaryBlockStatementVisitor extends BaseInspectionVisitor { + private UnnecessaryBlockStatementVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitBlockStatement(PsiBlockStatement blockStatement) { + super.visitBlockStatement(blockStatement); + final PsiElement parent = blockStatement.getParent(); + if (parent == null) { + return; + } + if (!(parent instanceof PsiCodeBlock)) { + return; + } + final PsiCodeBlock codeBlock = blockStatement.getCodeBlock(); + if (codeBlock == null) { + return; + } + final PsiJavaToken brace = codeBlock.getLBrace(); + if (brace == null) { + return; + } + if (containsDeclarations(blockStatement)) { + return; + } + registerError(brace); + } + + private static boolean containsDeclarations(PsiBlockStatement blockStatement) { + final PsiCodeBlock codeBlock = blockStatement.getCodeBlock(); + final PsiStatement[] statements = codeBlock.getStatements(); + if (statements == null) { + return false; + } + for (int i = 0; i < statements.length; i++) { + final PsiStatement statement = statements[i]; + if (statement instanceof PsiDeclarationStatement) { + return true; + } + } + return false; + } + } +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/verbose/UnnecessaryBoxingInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/verbose/UnnecessaryBoxingInspection.java new file mode 100644 index 000000000000..365a74258b63 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/verbose/UnnecessaryBoxingInspection.java @@ -0,0 +1,117 @@ +package com.siyeh.ig.verbose; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.codeInspection.ProblemDescriptor; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.roots.ProjectRootManager; +import com.intellij.psi.*; +import com.intellij.pom.java.LanguageLevel; +import com.siyeh.ig.*; + +import java.util.HashMap; +import java.util.Map; + +public class UnnecessaryBoxingInspection extends ExpressionInspection { + private static final Map s_boxingArgs = new HashMap(8); + private final UnnecessaryBoxingFix fix = new UnnecessaryBoxingFix(); + + static { + s_boxingArgs.put("java.lang.Integer", "int"); + s_boxingArgs.put("java.lang.Short", "short"); + s_boxingArgs.put("java.lang.Boolean", "boolean"); + s_boxingArgs.put("java.lang.Long", "long"); + s_boxingArgs.put("java.lang.Byte", "byte"); + s_boxingArgs.put("java.lang.Float", "float"); + s_boxingArgs.put("java.lang.Double", "double"); + s_boxingArgs.put("java.lang.Long", "long"); + s_boxingArgs.put("java.lang.Character", "char"); + } + + public String getDisplayName() { + return "Unnecessary boxing (J2SDK 5.0 only)"; + } + + public String getGroupDisplayName() { + return GroupNames.VERBOSE_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "Unnecessary boxing #ref #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new UnnecessaryBoxingVisitor(this, inspectionManager, onTheFly); + } + + public InspectionGadgetsFix buildFix(PsiElement location) { + return fix; + } + + private static class UnnecessaryBoxingFix extends InspectionGadgetsFix { + public String getName() { + return "Remove boxing"; + } + + public void applyFix(Project project, ProblemDescriptor descriptor) { + final PsiNewExpression expression = (PsiNewExpression) descriptor.getPsiElement(); + final PsiExpressionList argList = expression.getArgumentList(); + final PsiExpression[] args = argList.getExpressions(); + final String newExpression = args[0].getText(); + replaceExpression(project, expression, newExpression); + } + } + + private static class UnnecessaryBoxingVisitor extends BaseInspectionVisitor { + private UnnecessaryBoxingVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitNewExpression(PsiNewExpression expression) { + super.visitNewExpression(expression); + final PsiManager manager = expression.getManager(); + final LanguageLevel languageLevel = manager.getEffectiveLanguageLevel(); + if (languageLevel.equals(LanguageLevel.JDK_1_3) || + languageLevel.equals(LanguageLevel.JDK_1_4)) { + return; + } + final PsiType constructorType = expression.getType(); + if (constructorType == null) { + return; + } + final String constructorTypeText = constructorType.getCanonicalText(); + if (!s_boxingArgs.containsKey(constructorTypeText)) { + return; + } + + final PsiMethod constructor = expression.resolveConstructor(); + if (constructor == null) { + return; + } + final PsiParameterList parameterList = constructor.getParameterList(); + + if (parameterList == null) { + return; + } + final PsiParameter[] args = parameterList.getParameters(); + if (args == null) { + return; + } + if (args.length != 1) { + return; + } + final PsiParameter arg = args[0]; + final PsiType argumentType = arg.getType(); + if (argumentType == null) { + return; + } + + final String argumentTypeText = argumentType.getCanonicalText(); + final Object boxableConstructorType = s_boxingArgs.get(constructorTypeText); + if (!boxableConstructorType.equals(argumentTypeText)) { + return; + } + registerError(expression); + } + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/verbose/UnnecessaryConditionalExpressionInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/verbose/UnnecessaryConditionalExpressionInspection.java new file mode 100644 index 000000000000..2fe16e3cc562 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/verbose/UnnecessaryConditionalExpressionInspection.java @@ -0,0 +1,100 @@ +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.PsiConditionalExpression; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiExpression; +import com.siyeh.ig.*; +import com.siyeh.ig.psiutils.BoolUtils; + +public class UnnecessaryConditionalExpressionInspection + extends ExpressionInspection { + private final TrivialConditionalFix fix = new TrivialConditionalFix(); + + public String getDisplayName() { + return "Unnecessary conditional expression"; + } + + public String getGroupDisplayName() { + return GroupNames.VERBOSE_GROUP_NAME; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new UnnecessaryConditionalExpressionVisitor(this, inspectionManager, + onTheFly); + } + + public String buildErrorString(PsiElement location) { + final PsiConditionalExpression exp = (PsiConditionalExpression) location; + return '\'' + exp.getText() + "' can be simplified to '" + + calculateReplacementExpression(exp) + + "' #loc"; + } + + private static String calculateReplacementExpression(PsiConditionalExpression exp) { + final PsiExpression thenExpression = exp.getThenExpression(); + final PsiExpression elseExpression = exp.getElseExpression(); + final PsiExpression condition = exp.getCondition(); + + if (isFalse(thenExpression) && isTrue(elseExpression)) { + return BoolUtils.getNegatedExpressionText(condition); + } else { + return condition.getText(); + } + } + + public InspectionGadgetsFix buildFix(PsiElement location) { + return fix; + } + + private static class TrivialConditionalFix extends InspectionGadgetsFix { + public String getName() { + return "Simplify"; + } + + public void applyFix(Project project, ProblemDescriptor descriptor) { + final PsiConditionalExpression expression = (PsiConditionalExpression) descriptor.getPsiElement(); + final String newExpression = calculateReplacementExpression(expression); + replaceExpression(project, expression, newExpression); + } + } + + private static class UnnecessaryConditionalExpressionVisitor + extends BaseInspectionVisitor { + private UnnecessaryConditionalExpressionVisitor(BaseInspection inspection, + InspectionManager inspectionManager, + boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitConditionalExpression(PsiConditionalExpression exp) { + super.visitConditionalExpression(exp); + final PsiExpression thenExpression = exp.getThenExpression(); + if (thenExpression == null) { + return; + } + final PsiExpression elseExpression = exp.getElseExpression(); + if (elseExpression == null) { + return; + } + if ((isFalse(thenExpression) && isTrue(elseExpression)) + || (isTrue(thenExpression) && isFalse(elseExpression))) { + registerError(exp); + } + } + } + + private static boolean isFalse(PsiExpression expression) { + final String text = expression.getText(); + return "false".equals(text); + } + + private static boolean isTrue(PsiExpression expression) { + final String text = expression.getText(); + return "true".equals(text); + } + + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/verbose/UnnecessaryContinueInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/verbose/UnnecessaryContinueInspection.java new file mode 100644 index 000000000000..1e2964820017 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/verbose/UnnecessaryContinueInspection.java @@ -0,0 +1,86 @@ +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 UnnecessaryContinueInspection extends StatementInspection { + private final UnnecessaryContinueFix fix = new UnnecessaryContinueFix(); + + public String getDisplayName() { + return "Unnecessary 'continue' statement"; + } + + public String getGroupDisplayName() { + return GroupNames.VERBOSE_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "#ref is unnecessary as the last statement in a loop #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new UnnecessaryContinueVisitor(this, inspectionManager, onTheFly); + } + + public InspectionGadgetsFix buildFix(PsiElement location) { + return fix; + } + + private static class UnnecessaryContinueFix extends InspectionGadgetsFix { + public String getName() { + return "Remove unnecessary continue"; + } + + public void applyFix(Project project, ProblemDescriptor descriptor) { + final PsiElement returnKeywordElement = descriptor.getPsiElement(); + final PsiElement continueStatement = returnKeywordElement.getParent(); + deleteElement(continueStatement); + } + + } + + private static class UnnecessaryContinueVisitor extends BaseInspectionVisitor { + private UnnecessaryContinueVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + + public void visitContinueStatement(PsiContinueStatement statement) { + final PsiIdentifier identifier = statement.getLabelIdentifier(); + if (identifier != null) { + return; + } + final PsiStatement continuedStatement = statement.findContinuedStatement(); + final PsiElement parent = statement.getParent(); + if (parent.equals(continuedStatement)) { + registerStatementError(statement); + } else if (parent instanceof PsiCodeBlock) { + final PsiCodeBlock block = (PsiCodeBlock) parent; + if (statementIsLastInBlock(block, statement)) { + final PsiElement blockStatement = block.getParent(); + final PsiElement containingStatement = blockStatement.getParent(); + if (containingStatement.equals(continuedStatement)) { + registerStatementError(statement); + } + } + } + } + + private boolean statementIsLastInBlock(PsiCodeBlock block, PsiContinueStatement statement) { + final PsiStatement[] statements = block.getStatements(); + for (int i = statements.length - 1; i >= 0; i--) { + final PsiStatement childStatement = statements[i]; + if (statement.equals(childStatement)) { + return true; + } + if (!(statement instanceof PsiEmptyStatement)) { + return false; + } + } + return false; + } + } +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/verbose/UnnecessaryDefaultInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/verbose/UnnecessaryDefaultInspection.java new file mode 100644 index 000000000000..cbcf87930cad --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/verbose/UnnecessaryDefaultInspection.java @@ -0,0 +1,111 @@ +package com.siyeh.ig.verbose; + +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 UnnecessaryDefaultInspection extends StatementInspection { + + public String getDisplayName() { + return "Unnecessary 'default'"; + } + + public String getGroupDisplayName() { + return GroupNames.VERBOSE_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "'#ref' branch is unnecessary #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new UnnecessaryDefaultVisitor(this, inspectionManager, + onTheFly); + } + + private static class UnnecessaryDefaultVisitor + extends BaseInspectionVisitor { + private UnnecessaryDefaultVisitor(BaseInspection inspection, + InspectionManager inspectionManager, + boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitSwitchStatement(PsiSwitchStatement statement) { + super.visitSwitchStatement(statement); + if (!switchStatementContainsUnnecessaryDefault(statement)) { + return; + } + final PsiCodeBlock body = statement.getBody(); + final PsiStatement[] statements = body.getStatements(); + for (int i = statements.length - 1; i >= 0; i--) { + final PsiStatement child = statements[i]; + if (child instanceof PsiSwitchLabelStatement) { + final PsiSwitchLabelStatement label = + (PsiSwitchLabelStatement) child; + if (label.isDefaultCase()) { + registerStatementError(label); + } + } + } + } + + private static boolean switchStatementContainsUnnecessaryDefault(PsiSwitchStatement statement) { + final PsiExpression expression = statement.getExpression(); + if (expression == null) { + return false; + } + final PsiType type = expression.getType(); + if (type == null) { + return false; + } + if (!(type instanceof PsiClassType)) { + return false; + } + final PsiClass aClass = ((PsiClassType) type).resolve(); + if (aClass == null) { + return false; + } + if (!aClass.isEnum()) { + return false; + } + final PsiCodeBlock body = statement.getBody(); + if (body == null) { + return false; + } + final PsiStatement[] statements = body.getStatements(); + if (statements == null) { + return false; + } + boolean containsDefault = false; + int numCases = 0; + for (int i = 0; i < statements.length; i++) { + final PsiStatement child = statements[i]; + if (child instanceof PsiSwitchLabelStatement) { + if (((PsiSwitchLabelStatement) child).isDefaultCase()) { + containsDefault = true; + } else { + numCases++; + } + } + } + if (!containsDefault) { + return false; + } + final PsiField[] fields = aClass.getFields(); + int numEnums = 0; + for (int i = 0; i < fields.length; i++) { + final PsiField field = fields[i]; + if (field.getType().equals(type)) { + numEnums++; + } + + } + return numEnums == numCases; + } + } + +} \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/verbose/UnnecessaryFinalOnLocalVariableInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/verbose/UnnecessaryFinalOnLocalVariableInspection.java new file mode 100644 index 000000000000..ed4c03d984b0 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/verbose/UnnecessaryFinalOnLocalVariableInspection.java @@ -0,0 +1,99 @@ +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.fixes.RemoveModifierFix; +import com.siyeh.ig.psiutils.VariableUsedInInnerClassVisitor; + +public class UnnecessaryFinalOnLocalVariableInspection extends MethodInspection { + public String getDisplayName() { + return "Unnecessary 'final' for local variable"; + } + + public String getGroupDisplayName() { + return GroupNames.VERBOSE_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + final PsiModifierList modifierList = (PsiModifierList) location.getParent(); + final PsiVariable parameter = (PsiVariable) modifierList.getParent(); + final String parameterName = parameter.getName(); + return "Unnecessary #ref for variable " + parameterName + " #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new UnnecessaryFinalOnLocalVariableVisitor(this, inspectionManager, onTheFly); + } + + public InspectionGadgetsFix buildFix(PsiElement location) { + return new RemoveModifierFix(location); + } + + private static class UnnecessaryFinalOnLocalVariableVisitor extends BaseInspectionVisitor { + private UnnecessaryFinalOnLocalVariableVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitDeclarationStatement(PsiDeclarationStatement statement) { + super.visitDeclarationStatement(statement); + final PsiElement[] declaredElements = + statement.getDeclaredElements(); + if (declaredElements == null || declaredElements.length == 0) { + return; + } + for (int i = 0; i < declaredElements.length; i++) { + final PsiElement declaredElement = declaredElements[i]; + if (!(declaredElement instanceof PsiLocalVariable)) { + return; + } + final PsiLocalVariable variable = (PsiLocalVariable) declaredElement; + if (!variable.hasModifierProperty(PsiModifier.FINAL)) { + return; + } + } + final PsiCodeBlock containingBlock = + (PsiCodeBlock) PsiTreeUtil.getParentOfType(statement, PsiCodeBlock.class); + if (containingBlock == null) { + return; + } + for (int i = 0; i < declaredElements.length; i++) { + final PsiLocalVariable variable = (PsiLocalVariable) declaredElements[i]; + if (variableIsUsedInInnerClass(containingBlock, variable)) { + return; + } + } + final PsiLocalVariable variable1 = (PsiLocalVariable) statement.getDeclaredElements()[0]; + registerModifierError(PsiModifier.FINAL, variable1); + } + + public void visitTryStatement(PsiTryStatement statement) { + super.visitTryStatement(statement); + final PsiParameter[] catchBlockParameters = + statement.getCatchBlockParameters(); + final PsiCodeBlock[] catchBlocks = statement.getCatchBlocks(); + final int numBlocks = Math.min(catchBlocks.length, catchBlockParameters.length); + for (int i = 0; i < numBlocks; i++) { + final PsiCodeBlock catchBlock = catchBlocks[i]; + final PsiParameter parameter = catchBlockParameters[i]; + if (parameter.hasModifierProperty(PsiModifier.FINAL) && + !variableIsUsedInInnerClass(catchBlock, parameter)) { + registerModifierError(PsiModifier.FINAL, parameter); + } + } + } + + + private static boolean variableIsUsedInInnerClass(PsiCodeBlock block, + PsiVariable variable) { + + final VariableUsedInInnerClassVisitor visitor + = new VariableUsedInInnerClassVisitor(variable); + block.accept(visitor); + return visitor.isUsedInInnerClass(); + } + + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/verbose/UnnecessaryFinalOnParameterInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/verbose/UnnecessaryFinalOnParameterInspection.java new file mode 100644 index 000000000000..bd7797076b55 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/verbose/UnnecessaryFinalOnParameterInspection.java @@ -0,0 +1,81 @@ +package com.siyeh.ig.verbose; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.psi.*; +import com.siyeh.ig.*; +import com.siyeh.ig.fixes.RemoveModifierFix; +import com.siyeh.ig.psiutils.VariableUsedInInnerClassVisitor; + +public class UnnecessaryFinalOnParameterInspection extends MethodInspection { + public String getDisplayName() { + return "Unnecessary 'final' for method parameter"; + } + + public String getGroupDisplayName() { + return GroupNames.VERBOSE_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + final PsiModifierList modifierList = (PsiModifierList) location.getParent(); + final PsiParameter parameter = (PsiParameter) modifierList.getParent(); + final String parameterName = parameter.getName(); + return "Unnecessary #ref for parameter " + parameterName + " #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new UnnecessaryFinalOnParameterVisitor(this, inspectionManager, onTheFly); + } + + public InspectionGadgetsFix buildFix(PsiElement location) { + return new RemoveModifierFix(location); + } + + private static class UnnecessaryFinalOnParameterVisitor extends BaseInspectionVisitor { + private UnnecessaryFinalOnParameterVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitMethod(PsiMethod method) { + super.visitMethod(method); + final PsiParameterList parameterList = method.getParameterList(); + if (parameterList == null) { + return; + } + final PsiParameter[] parameters = parameterList.getParameters(); + if (parameters == null) { + return; + } + for (int i = 0; i < parameters.length; i++) { + final PsiParameter parameter = parameters[i]; + checkParameter(method, parameter); + } + } + + private void checkParameter(PsiMethod method, PsiParameter parameter) { + if (!parameter.hasModifierProperty(PsiModifier.FINAL)) { + return; + } + final PsiClass containingClass = method.getContainingClass(); + + if (containingClass != null) { + if (containingClass.isInterface() || containingClass.isAnnotationType()) { + registerModifierError(PsiModifier.FINAL, parameter); + return; + } + } + + if (method.hasModifierProperty(PsiModifier.ABSTRACT)) { + registerModifierError(PsiModifier.FINAL, parameter); + return; + } + final VariableUsedInInnerClassVisitor visitor + = new VariableUsedInInnerClassVisitor(parameter); + method.accept(visitor); + if (!visitor.isUsedInInnerClass()) { + registerModifierError(PsiModifier.FINAL, parameter); + } + } + + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/verbose/UnnecessaryFullyQualifiedNameInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/verbose/UnnecessaryFullyQualifiedNameInspection.java new file mode 100644 index 000000000000..6344ef308d57 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/verbose/UnnecessaryFullyQualifiedNameInspection.java @@ -0,0 +1,152 @@ +package com.siyeh.ig.verbose; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.codeInspection.ProblemDescriptor; +import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.project.Project; +import com.intellij.psi.*; +import com.intellij.psi.codeStyle.CodeStyleManager; +import com.intellij.psi.javadoc.PsiDocTag; +import com.intellij.psi.util.PsiTreeUtil; +import com.intellij.util.IncorrectOperationException; +import com.siyeh.ig.*; +import com.siyeh.ig.psiutils.ClassUtils; +import com.siyeh.ig.psiutils.ImportUtils; +import com.siyeh.ig.ui.SingleCheckboxOptionsPanel; + +import javax.swing.*; + +public class UnnecessaryFullyQualifiedNameInspection extends ClassInspection { + public boolean m_ignoreJavaDocs = false; + private final UnnecessaryFullyQualifiedNameFix fix = new UnnecessaryFullyQualifiedNameFix(); + + public String getDisplayName() { + return "Unnecessary fully qualified name"; + } + + public String getGroupDisplayName() { + return GroupNames.VERBOSE_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "Fully qualified name #ref is unnecessary, and can be replace with an import #loc"; + } + + public JComponent createOptionsPanel() { + return new SingleCheckboxOptionsPanel("Ignore fully qualified names in javadoc comments", + this, "m_ignoreJavaDocs"); + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new UnnecessaryFullyQualifiedNameVisitor(this, inspectionManager, onTheFly); + } + + public InspectionGadgetsFix buildFix(PsiElement location) { + if (m_ignoreJavaDocs && PsiTreeUtil.getParentOfType(location, PsiDocTag.class) != null) { + return null; + } + return fix; + } + + private static class UnnecessaryFullyQualifiedNameFix extends InspectionGadgetsFix { + public String getName() { + return "Replace with import"; + } + + public void applyFix(Project project, ProblemDescriptor descriptor) { + try { + final PsiManager mgr = PsiManager.getInstance(project); + final PsiJavaCodeReferenceElement reference = (PsiJavaCodeReferenceElement) descriptor.getPsiElement(); + final CodeStyleManager styleManager = mgr.getCodeStyleManager(); + styleManager.shortenClassReferences(reference); + } catch (IncorrectOperationException e) { + final Class thisClass = getClass(); + final String className = thisClass.getName(); + final Logger logger = Logger.getInstance(className); + logger.error(e); + } + } + } + + private class UnnecessaryFullyQualifiedNameVisitor extends BaseInspectionVisitor { + private boolean m_inClass = false; + + private UnnecessaryFullyQualifiedNameVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitClass(PsiClass aClass) { + final boolean wasInClass = m_inClass; + if (!m_inClass) { + + m_inClass = true; + super.visitClass(aClass); + } + m_inClass = wasInClass; + } + + public void visitReferenceExpression(PsiReferenceExpression expression) { + final PsiExpression qualifier = expression.getQualifierExpression(); + final String expressionText = expression.getText(); + final String text = expressionText; + if (text.indexOf((int) '.') < 0) { + return; + } + final PsiElement psiElement = expression.resolve(); + if (!(psiElement instanceof PsiClass)) { + if (qualifier != null) { + qualifier.accept(this); + } + return; + } + final PsiReferenceParameterList typeParameters = expression.getParameterList(); + if(typeParameters!=null) + { + typeParameters.accept(this); + } + final PsiClass aClass = (PsiClass) psiElement; + final PsiClass outerClass = ClassUtils.getOutermostContainingClass(aClass); + final String fqName = outerClass.getQualifiedName(); + if (!expressionText.startsWith(fqName)) { + return; + } + final PsiJavaFile file = (PsiJavaFile) expression.getContainingFile(); + + if (!ImportUtils.nameCanBeImported(text, file)) { + return; + } + registerError(expression); + } + + public void visitReferenceElement(PsiJavaCodeReferenceElement element) { + final String text = element.getText(); + if (text.indexOf((int) '.') < 0) { + return; + } + if (m_ignoreJavaDocs && PsiTreeUtil.getParentOfType(element, PsiDocTag.class) != null) { + return; + } + final PsiElement psiElement = element.resolve(); + if (!(psiElement instanceof PsiClass)) { + return; + } + final PsiReferenceParameterList typeParameters = element.getParameterList(); + if (typeParameters != null) { + typeParameters.accept(this); + } + final PsiClass aClass = (PsiClass) psiElement; + final PsiClass outerClass = ClassUtils.getOutermostContainingClass(aClass); + final String fqName = outerClass.getQualifiedName(); + if (!element.getText().startsWith(fqName)) { + return; + } + final PsiJavaFile file = (PsiJavaFile) element.getContainingFile(); + if (!ImportUtils.nameCanBeImported(text, file)) { + return; + } + registerError(element); + } + + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/verbose/UnnecessaryInterfaceModifierInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/verbose/UnnecessaryInterfaceModifierInspection.java new file mode 100644 index 000000000000..b355a0ed7b98 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/verbose/UnnecessaryInterfaceModifierInspection.java @@ -0,0 +1,207 @@ +package com.siyeh.ig.verbose; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.codeInspection.ProblemDescriptor; +import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.project.Project; +import com.intellij.psi.*; +import com.intellij.util.IncorrectOperationException; +import com.siyeh.ig.*; +import com.siyeh.ig.psiutils.ClassUtils; + +public class UnnecessaryInterfaceModifierInspection extends BaseInspection { + + public String getDisplayName() { + return "Unnecessary interface modifier"; + } + + public String getGroupDisplayName() { + return GroupNames.VERBOSE_GROUP_NAME; + } + + public ProblemDescriptor[] checkClass(PsiClass aClass, InspectionManager mgr, boolean isOnTheFly) { + if (!aClass.isPhysical()) { + return super.checkClass(aClass, mgr, isOnTheFly); + } + if (isOnTheFly && !InspectionGadgetsPlugin.isEnabled()) { + return super.checkClass(aClass, mgr, isOnTheFly); + } + final BaseInspectionVisitor visitor = createVisitor(mgr, isOnTheFly); + aClass.accept(visitor); + + return visitor.getErrors(); + } + + public ProblemDescriptor[] checkMethod(PsiMethod method, InspectionManager mgr, boolean isOnTheFly) { + if (!method.isPhysical()) { + return super.checkMethod(method, mgr, isOnTheFly); + } + if (isOnTheFly && !InspectionGadgetsPlugin.isEnabled()) { + return super.checkMethod(method, mgr, isOnTheFly); + } + final BaseInspectionVisitor visitor = createVisitor(mgr, isOnTheFly); + method.accept(visitor); + return visitor.getErrors(); + } + + public ProblemDescriptor[] checkField(PsiField field, InspectionManager mgr, boolean isOnTheFly) { + if (!field.isPhysical()) { + return super.checkField(field, mgr, isOnTheFly); + } + if (isOnTheFly && !InspectionGadgetsPlugin.isEnabled()) { + return super.checkField(field, mgr, isOnTheFly); + } + final BaseInspectionVisitor visitor = createVisitor(mgr, isOnTheFly); + field.accept(visitor); + return visitor.getErrors(); + } + + public String buildErrorString(PsiElement location) { + final PsiModifierList modifierList; + if (location instanceof PsiModifierList) { + modifierList = (PsiModifierList) location; + } else { + modifierList = (PsiModifierList) location.getParent(); + } + final PsiElement parent = modifierList.getParent(); + if (parent instanceof PsiClass) { + return "Modifier '#ref' is redundant for interfaces #loc"; + } else if (parent instanceof PsiMethod) { + if (modifierList.getChildren().length > 1) { + return "Modifiers '#ref' are redundant for interface methods #loc"; + } else { + return "Modifier '#ref' is redundant for interface methods #loc"; + } + } else { + if (modifierList.getChildren().length > 1) { + return "Modifiers '#ref' are redundant for interface fields #loc"; + } else { + return "Modifier '#ref' is redundant for interface fields #loc"; + } + } + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new UnnecessaryInterfaceModifierVisitor(this, inspectionManager, onTheFly); + } + + public InspectionGadgetsFix buildFix(PsiElement location) { + return new UnnecessaryInterfaceModifersFix(location); + } + + private static class UnnecessaryInterfaceModifersFix extends InspectionGadgetsFix { + private final String m_name; + + private UnnecessaryInterfaceModifersFix(PsiElement fieldModifiers) { + super(); + m_name = "Remove '" + fieldModifiers.getText() + '\''; + } + + public String getName() { + return m_name; + } + + public void applyFix(Project project, ProblemDescriptor descriptor) { + try { + final PsiElement element = descriptor.getPsiElement(); + final PsiModifierList modifierList; + if (element instanceof PsiModifierList) { + modifierList = (PsiModifierList) element; + } else { + modifierList = (PsiModifierList) element.getParent(); + } + modifierList.setModifierProperty(PsiModifier.STATIC, false); + modifierList.setModifierProperty(PsiModifier.ABSTRACT, false); + modifierList.setModifierProperty(PsiModifier.FINAL, false); + if (!(modifierList.getParent() instanceof PsiClass)) { + modifierList.setModifierProperty(PsiModifier.PUBLIC, false); + } + } catch (IncorrectOperationException e) { + final Class aClass = getClass(); + final String className = aClass.getName(); + final Logger logger = Logger.getInstance(className); + logger.error(e); + } + } + } + + private static class UnnecessaryInterfaceModifierVisitor extends BaseInspectionVisitor { + + private UnnecessaryInterfaceModifierVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitClass(PsiClass aClass) { + if (aClass.isInterface()) { + final PsiModifierList modifiers = aClass.getModifierList(); + if (modifiers == null) { + return; + } + final PsiElement[] children = modifiers.getChildren(); + for (int i = 0; i < children.length; i++) { + final PsiElement child = children[i]; + final String text = child.getText(); + if (PsiModifier.ABSTRACT.equals(text)) { + registerError(child); + } + } + } + final PsiClass parent = ClassUtils.getContainingClass(aClass); + if (parent != null && parent.isInterface()) { + final PsiModifierList modifiers = aClass.getModifierList(); + if (modifiers == null) { + return; + } + final PsiElement[] children = modifiers.getChildren(); + for (int i = 0; i < children.length; i++) { + final PsiElement child = children[i]; + final String text = child.getText(); + if (PsiModifier.PUBLIC.equals(text) || + PsiModifier.STATIC.equals(text)) { + registerError(child); + } + } + } + } + + public void visitField(PsiField field) { + // don't call super, to keep this from drilling in + final PsiClass containingClass = field.getContainingClass(); + if (containingClass == null) { + return; + } + if (!containingClass.isInterface()) { + return; + } + final PsiModifierList modifiers = field.getModifierList(); + if (modifiers == null) { + return; + } + // the only modifiers an interface field can have (public static final) + // are unnecessary. + final int modifiersLength = modifiers.getTextLength(); + if (modifiersLength != 0) { + registerError(modifiers); + } + } + + public void visitMethod(PsiMethod method) { + // don't call super, to keep this from drilling in + final PsiClass aClass = method.getContainingClass(); + if (aClass == null) { + return; + } + if (!aClass.isInterface()) { + return; + } + final PsiModifierList modifiers = method.getModifierList(); + // the only modifiers an interface field can have (public static final) + // are unnecessary. + final int modifiersLength = modifiers.getTextLength(); + if (modifiersLength != 0) { + registerError(modifiers); + } + } + + } +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/verbose/UnnecessaryLabelOnBreakStatementInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/verbose/UnnecessaryLabelOnBreakStatementInspection.java new file mode 100644 index 000000000000..521ccb9ae05b --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/verbose/UnnecessaryLabelOnBreakStatementInspection.java @@ -0,0 +1,114 @@ +package com.siyeh.ig.verbose; + +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 UnnecessaryLabelOnBreakStatementInspection extends StatementInspection { + private final UnnecessaryLabelOnBreakStatementFix fix = new UnnecessaryLabelOnBreakStatementFix(); + + public String getDisplayName() { + return "Unnecessary label on 'break' statement"; + } + + public String getGroupDisplayName() { + return GroupNames.VERBOSE_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "Unnecessary label on #ref statement #loc"; + } + + public InspectionGadgetsFix buildFix(PsiElement location) { + return fix; + } + + private static class UnnecessaryLabelOnBreakStatementFix extends InspectionGadgetsFix { + public String getName() { + return "Remove label"; + } + + public void applyFix(Project project, ProblemDescriptor descriptor) { + final PsiElement breakKeywordElement = descriptor.getPsiElement(); + final PsiBreakStatement breakStatement = + (PsiBreakStatement) breakKeywordElement.getParent(); + replaceStatement(project, breakStatement, "break;"); + } + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new UnnecessaryLabelOnBreakStatementVisitor(this, inspectionManager, onTheFly); + } + + private static class UnnecessaryLabelOnBreakStatementVisitor extends BaseInspectionVisitor { + private PsiStatement currentContainer = null; + + private UnnecessaryLabelOnBreakStatementVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitForStatement(PsiForStatement statement) { + final PsiStatement prevContainer = currentContainer; + currentContainer = statement; + super.visitForStatement(statement); + currentContainer = prevContainer; + } + + public void visitDoWhileStatement(PsiDoWhileStatement statement) { + final PsiStatement prevContainer = currentContainer; + currentContainer = statement; + super.visitDoWhileStatement(statement); + currentContainer = prevContainer; + } + + public void visitForeachStatement(PsiForeachStatement statement) { + final PsiStatement prevContainer = currentContainer; + currentContainer = statement; + super.visitForeachStatement(statement); + currentContainer = prevContainer; + } + + public void visitWhileStatement(PsiWhileStatement statement) { + final PsiStatement prevContainer = currentContainer; + currentContainer = statement; + super.visitWhileStatement(statement); + currentContainer = prevContainer; + } + + public void visitSwitchStatement(PsiSwitchStatement statement) { + final PsiStatement prevContainer = currentContainer; + currentContainer = statement; + super.visitSwitchStatement(statement); + currentContainer = prevContainer; + } + + public void visitBreakStatement(PsiBreakStatement statement) { + super.visitBreakStatement(statement); + final PsiIdentifier labelIdentifier = statement.getLabelIdentifier(); + if (labelIdentifier == null) { + return; + } + final PsiIdentifier identifier = statement.getLabelIdentifier(); + final String labelText = identifier.getText(); + if (labelText == null || labelText.length() == 0) { + return; + } + final PsiStatement exitedStatement = statement.findExitedStatement(); + if (exitedStatement == null) { + return; + } + if (currentContainer == null) { + return; + } + final PsiElement containerParent = currentContainer.getParent(); + if (exitedStatement.equals(containerParent)) { + return; + } + registerStatementError(statement); + } + + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/verbose/UnnecessaryLabelOnContinueStatementInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/verbose/UnnecessaryLabelOnContinueStatementInspection.java new file mode 100644 index 000000000000..a0acd2660705 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/verbose/UnnecessaryLabelOnContinueStatementInspection.java @@ -0,0 +1,107 @@ +package com.siyeh.ig.verbose; + +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 UnnecessaryLabelOnContinueStatementInspection extends StatementInspection { + private final UnnecessaryLabelOnContinueStatementFix fix = new UnnecessaryLabelOnContinueStatementFix(); + + public String getDisplayName() { + return "Unnecessary label on 'continue' statement"; + } + + public String getGroupDisplayName() { + return GroupNames.VERBOSE_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "Unnecessary label on #ref statement #loc"; + } + + public InspectionGadgetsFix buildFix(PsiElement location) { + return fix; + } + + private static class UnnecessaryLabelOnContinueStatementFix extends InspectionGadgetsFix { + public String getName() { + return "Remove label"; + } + + public void applyFix(Project project, ProblemDescriptor descriptor) { + final PsiElement continueKeywordElement = descriptor.getPsiElement(); + final PsiContinueStatement continueStatement = + (PsiContinueStatement) continueKeywordElement.getParent(); + replaceStatement(project, continueStatement, "continue;"); + } + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new UnnecessaryLabelOnContinueStatementVisitor(this, inspectionManager, onTheFly); + } + + private static class UnnecessaryLabelOnContinueStatementVisitor extends BaseInspectionVisitor { + private PsiStatement currentContainer = null; + + private UnnecessaryLabelOnContinueStatementVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitForStatement(PsiForStatement statement) { + final PsiStatement prevContainer = currentContainer; + currentContainer = statement; + super.visitForStatement(statement); + currentContainer = prevContainer; + } + + public void visitDoWhileStatement(PsiDoWhileStatement statement) { + final PsiStatement prevContainer = currentContainer; + currentContainer = statement; + super.visitDoWhileStatement(statement); + currentContainer = prevContainer; + } + + public void visitForeachStatement(PsiForeachStatement statement) { + final PsiStatement prevContainer = currentContainer; + currentContainer = statement; + super.visitForeachStatement(statement); + currentContainer = prevContainer; + } + + public void visitWhileStatement(PsiWhileStatement statement) { + final PsiStatement prevContainer = currentContainer; + currentContainer = statement; + super.visitWhileStatement(statement); + currentContainer = prevContainer; + } + + public void visitContinueStatement(PsiContinueStatement statement) { + super.visitContinueStatement(statement); + final PsiIdentifier labelIdentifier = statement.getLabelIdentifier(); + if (labelIdentifier == null) { + return; + } + final PsiIdentifier identifier = statement.getLabelIdentifier(); + final String labelText = identifier.getText(); + if (labelText == null || labelText.length() == 0) { + return; + } + final PsiStatement continuedStatement = statement.findContinuedStatement(); + if (continuedStatement == null) { + return; + } + if (currentContainer == null) { + return; + } + final PsiElement containerParent = currentContainer.getParent(); + if (continuedStatement.equals(containerParent)) { + return; + } + registerStatementError(statement); + } + + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/verbose/UnnecessaryParenthesesInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/verbose/UnnecessaryParenthesesInspection.java new file mode 100644 index 000000000000..968b1c92c444 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/verbose/UnnecessaryParenthesesInspection.java @@ -0,0 +1,91 @@ +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.intellij.psi.tree.IElementType; +import com.siyeh.ig.*; +import com.siyeh.ig.psiutils.ParenthesesUtils; + +public class UnnecessaryParenthesesInspection extends StatementInspection { + private final UnnecessaryParenthesesFix fix = new UnnecessaryParenthesesFix(); + + public String getDisplayName() { + return "Unnecessary parentheses"; + } + + public String getGroupDisplayName() { + return GroupNames.VERBOSE_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "Parentheses around #ref are unnecessary #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new UnnecessaryParenthesesVisitor(this, inspectionManager, onTheFly); + } + + public InspectionGadgetsFix buildFix(PsiElement location) { + return fix; + } + + private static class UnnecessaryParenthesesFix extends InspectionGadgetsFix { + public String getName() { + return "Remove unnecessary parentheses"; + } + + public void applyFix(Project project, ProblemDescriptor descriptor) { + final PsiExpression exp = (PsiExpression) descriptor.getPsiElement(); + final String newExpression = ParenthesesUtils.removeParentheses(exp); + replaceExpression(project, exp, newExpression); + } + + } + + private static class UnnecessaryParenthesesVisitor extends BaseInspectionVisitor { + private UnnecessaryParenthesesVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitParenthesizedExpression(PsiParenthesizedExpression expression) { + final PsiElement parent = expression.getParent(); + final PsiExpression child = expression.getExpression(); + if (child == null) { + return; + } + if (!(parent instanceof PsiExpression)) { + registerError(expression); + return; + } + final int parentPrecedence = ParenthesesUtils.getPrecendence((PsiExpression) parent); + final int childPrecedence = ParenthesesUtils.getPrecendence(child); + if (parentPrecedence > childPrecedence) { + registerError(expression); + return; + } + if (parentPrecedence == childPrecedence) { + if (parent instanceof PsiBinaryExpression && + child instanceof PsiBinaryExpression) { + final PsiJavaToken parentSign = + ((PsiBinaryExpression) parent).getOperationSign(); + final IElementType parentOperator = parentSign.getTokenType(); + final PsiJavaToken childSign = ((PsiBinaryExpression) child).getOperationSign(); + final IElementType childOperator = childSign.getTokenType(); + + final PsiBinaryExpression binaryExpression = (PsiBinaryExpression) parent; + final PsiExpression lhs = binaryExpression.getLOperand(); + if (lhs.equals(expression) && parentOperator.equals(childOperator)) { + registerError(expression); + return; + } + } else { + registerError(expression); + return; + } + } + super.visitParenthesizedExpression(expression); + } + } +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/verbose/UnnecessaryQualifierForThisInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/verbose/UnnecessaryQualifierForThisInspection.java new file mode 100644 index 000000000000..3a66a547611d --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/verbose/UnnecessaryQualifierForThisInspection.java @@ -0,0 +1,80 @@ +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.PsiClass; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiJavaCodeReferenceElement; +import com.intellij.psi.PsiThisExpression; +import com.siyeh.ig.*; +import com.siyeh.ig.psiutils.ClassUtils; + +public class UnnecessaryQualifierForThisInspection extends StatementInspection { + private final UnnecessaryThisFix fix = new UnnecessaryThisFix(); + + public String getDisplayName() { + return "Unnecessary qualifier for 'this'"; + } + + public String getGroupDisplayName() { + return GroupNames.VERBOSE_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "Qualifier '#ref' on 'this' is unnecessary in this context #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new UnnecessaryQualifierForThisVisitor(this, inspectionManager, onTheFly); + } + + public InspectionGadgetsFix buildFix(PsiElement location) { + return fix; + } + + private static class UnnecessaryThisFix extends InspectionGadgetsFix { + public String getName() { + return "Remove unnecessary qualifier "; + } + + public void applyFix(Project project, ProblemDescriptor descriptor) { + final PsiElement qualifier = descriptor.getPsiElement(); + final PsiThisExpression thisExpression = (PsiThisExpression) qualifier.getParent(); + replaceExpression(project, thisExpression, "this"); + } + + } + + private static class UnnecessaryQualifierForThisVisitor extends BaseInspectionVisitor { + private UnnecessaryQualifierForThisVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitThisExpression(PsiThisExpression thisExpression) { + super.visitThisExpression(thisExpression); + final PsiJavaCodeReferenceElement qualifier = + thisExpression.getQualifier(); + if (qualifier == null) { + return; + } + final PsiElement referent = qualifier.resolve(); + if (referent == null) { + return; + } + if (!(referent instanceof PsiClass)) { + return; + } + final PsiClass containingClass = + ClassUtils.getContainingClass(thisExpression); + if (containingClass == null) { + return; + } + if (!containingClass.equals(referent)) { + return; + } + registerError(qualifier); + } + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/verbose/UnnecessaryReturnInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/verbose/UnnecessaryReturnInspection.java new file mode 100644 index 000000000000..fdf65d99e4a4 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/verbose/UnnecessaryReturnInspection.java @@ -0,0 +1,78 @@ +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.intellij.psi.util.PsiTreeUtil; +import com.siyeh.ig.*; + +public class UnnecessaryReturnInspection extends StatementInspection { + private final UnnecessaryReturnFix fix = new UnnecessaryReturnFix(); + + public String getDisplayName() { + return "Unnecessary 'return' statement"; + } + + public String getGroupDisplayName() { + return GroupNames.VERBOSE_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + final PsiMethod method = + (PsiMethod) PsiTreeUtil.getParentOfType(location, PsiMethod.class); + if (method.isConstructor()) { + return "#ref is unnecessary as the last statement in a constructor #loc"; + } else { + return "#ref is unnecessary as the last statement in a method returning 'void' #loc"; + } + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new UnnecessaryReturnVisitor(this, inspectionManager, onTheFly); + } + + public InspectionGadgetsFix buildFix(PsiElement location) { + return fix; + } + + private static class UnnecessaryReturnFix extends InspectionGadgetsFix { + public String getName() { + return "Remove unnecessary return"; + } + + public void applyFix(Project project, ProblemDescriptor descriptor) { + final PsiElement returnKeywordElement = descriptor.getPsiElement(); + final PsiElement returnStatement = returnKeywordElement.getParent(); + deleteElement(returnStatement); + } + + } + + private static class UnnecessaryReturnVisitor extends BaseInspectionVisitor { + private UnnecessaryReturnVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitMethod(PsiMethod method) { + // don't call super, to keep from drilling in + final PsiType returnType = method.getReturnType(); + if (!method.isConstructor() && !returnType.equals(PsiType.VOID)) { + return; + } + final PsiCodeBlock body = method.getBody(); + if (body == null) { + return; + } + final PsiStatement[] statements = body.getStatements(); + if (statements == null || statements.length == 0) { + return; + } + final PsiStatement finalStatement = statements[statements.length - 1]; + if (!(finalStatement instanceof PsiReturnStatement)) { + return; + } + registerStatementError(finalStatement); + } + } +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/verbose/UnnecessarySemicolonInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/verbose/UnnecessarySemicolonInspection.java new file mode 100644 index 000000000000..16a9c9375bae --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/verbose/UnnecessarySemicolonInspection.java @@ -0,0 +1,101 @@ +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.intellij.psi.tree.IElementType; +import com.siyeh.ig.*; + +public class UnnecessarySemicolonInspection extends ClassInspection { + private final UnnecessarySemicolonFix fix = new UnnecessarySemicolonFix(); + + public String getDisplayName() { + return "Unnecessary semicolon"; + } + + public String getGroupDisplayName() { + return GroupNames.VERBOSE_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "Unnecessary semicolon #ref #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new UnnecessarySemicolonVisitor(this, inspectionManager, onTheFly); + } + + public InspectionGadgetsFix buildFix(PsiElement location) { + return fix; + } + + private static class UnnecessarySemicolonFix extends InspectionGadgetsFix { + public String getName() { + return "Remove unnecessary semicolon"; + } + + public void applyFix(Project project, ProblemDescriptor descriptor) { + final PsiElement semicolonElement = descriptor.getPsiElement(); + deleteElement(semicolonElement); + } + + } + + private static class UnnecessarySemicolonVisitor extends BaseInspectionVisitor { + private boolean m_inClass = false; + + private UnnecessarySemicolonVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitClass(PsiClass aClass) { + final boolean wasInClass = m_inClass; + if (!m_inClass) { + m_inClass = true; + super.visitClass(aClass); + } + m_inClass = wasInClass; + PsiElement sibling = aClass.getNextSibling(); + while (sibling != null) { + if (sibling instanceof PsiJavaToken && + ((PsiJavaToken) sibling).getTokenType().equals(JavaTokenType.SEMICOLON)) { + registerError(sibling); + } + sibling = sibling.getNextSibling(); + } + } + + public void visitJavaToken(PsiJavaToken token) { + super.visitJavaToken(token); + final IElementType tokenType = token.getTokenType(); + if (!tokenType.equals(JavaTokenType.SEMICOLON)) { + return; + } + final PsiElement parent = token.getParent(); + if (!(parent instanceof PsiClass) && !(parent instanceof PsiJavaFile)) { + return; + } + if (parent instanceof PsiClass && ((PsiClass) parent).isEnum()) { + //A very hacky way of saying that semicolons after + //enum constants are not unnecessary. + PsiElement prevSibling = token.getPrevSibling(); + while (prevSibling != null && prevSibling instanceof PsiWhiteSpace) { + prevSibling = prevSibling.getPrevSibling(); + } + if (prevSibling instanceof PsiEnumConstant) { + return; + } + } + registerError(token); + } + + public void visitEmptyStatement(PsiEmptyStatement statement) { + super.visitEmptyStatement(statement); + final PsiElement parent = statement.getParent(); + if (parent instanceof PsiCodeBlock) { + registerError(statement); + } + } + } +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/verbose/UnnecessarySuperConstructorInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/verbose/UnnecessarySuperConstructorInspection.java new file mode 100644 index 000000000000..b2aa158e11fa --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/verbose/UnnecessarySuperConstructorInspection.java @@ -0,0 +1,71 @@ +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 UnnecessarySuperConstructorInspection extends ExpressionInspection { + private final UnnecessarySuperConstructorFix fix = new UnnecessarySuperConstructorFix(); + + public String getDisplayName() { + return "Unnecessary 'super()' statement"; + } + + public String getGroupDisplayName() { + return GroupNames.VERBOSE_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "#ref is unnecessary #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new UnnecessarySuperConstructorVisitor(this, inspectionManager, onTheFly); + } + + public InspectionGadgetsFix buildFix(PsiElement location) { + return fix; + } + + private static class UnnecessarySuperConstructorFix extends InspectionGadgetsFix { + public String getName() { + return "Remove unnecessary super()"; + } + + public void applyFix(Project project, ProblemDescriptor descriptor) { + final PsiElement superCall = descriptor.getPsiElement(); + final PsiElement callStatement = superCall.getParent(); + deleteElement(callStatement); + } + + } + + private static class UnnecessarySuperConstructorVisitor extends BaseInspectionVisitor { + private UnnecessarySuperConstructorVisitor(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 String methodText = methodExpression.getText(); + if (!"super".equals(methodText)) { + return; + } + final PsiExpressionList argumentList = call.getArgumentList(); + if (argumentList == null) { + return; + } + final PsiExpression[] args = argumentList.getExpressions(); + if (args.length != 0) { + return; + } + registerError(call); + } + } +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/verbose/UnnecessaryThisInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/verbose/UnnecessaryThisInspection.java new file mode 100644 index 000000000000..cbc7cc21bae1 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/verbose/UnnecessaryThisInspection.java @@ -0,0 +1,84 @@ +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.*; +import com.siyeh.ig.psiutils.VariableSearchUtils; + +public class UnnecessaryThisInspection extends StatementInspection { + private final UnnecessaryThisFix fix = new UnnecessaryThisFix(); + + public String getDisplayName() { + return "Unnecessary 'this' qualifier"; + } + + public String getGroupDisplayName() { + return GroupNames.VERBOSE_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "'#ref' is unnecessary in this context #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new UnnecessaryThisVisitor(this, inspectionManager, onTheFly); + } + + public InspectionGadgetsFix buildFix(PsiElement location) { + return fix; + } + + private static class UnnecessaryThisFix extends InspectionGadgetsFix { + public String getName() { + return "Remove unnecessary 'this.'"; + } + + public void applyFix(Project project, ProblemDescriptor descriptor) { + final PsiElement thisToken = descriptor.getPsiElement(); + final PsiReferenceExpression thisExpression = (PsiReferenceExpression) thisToken.getParent(); + final String newExpression = thisExpression.getReferenceName(); + replaceExpression(project, thisExpression, newExpression); + } + + } + + private static class UnnecessaryThisVisitor extends BaseInspectionVisitor { + private UnnecessaryThisVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitReferenceExpression(PsiReferenceExpression expression) { + super.visitReferenceExpression(expression); + PsiReferenceParameterList parameterList = expression.getParameterList(); + if (parameterList != null && parameterList.getTypeArguments().length > 0) { + return; + } + + final PsiExpression qualifierExpression = expression.getQualifierExpression(); + if (qualifierExpression == null) { + return; + } + if (!(qualifierExpression instanceof PsiThisExpression)) { + return; + } + final PsiThisExpression thisExpression = (PsiThisExpression) qualifierExpression; + if (thisExpression.getQualifier() != null) { + return; + } + if (expression.getParent() instanceof PsiCallExpression) { + registerError(qualifierExpression); // method calls are always in error + return; + } + final String varName = expression.getReferenceName(); + if (varName == null) { + return; + } + if (!VariableSearchUtils.existsLocalOrParameter(varName, expression)) { + registerError(thisExpression); + } + } + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/verbose/UnnecessaryUnboxingInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/verbose/UnnecessaryUnboxingInspection.java new file mode 100644 index 000000000000..1366ba939785 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/verbose/UnnecessaryUnboxingInspection.java @@ -0,0 +1,119 @@ +package com.siyeh.ig.verbose; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.codeInspection.ProblemDescriptor; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.roots.ProjectRootManager; +import com.intellij.psi.*; +import com.intellij.pom.java.LanguageLevel; +import com.siyeh.ig.*; +import com.siyeh.ig.psiutils.ParenthesesUtils; + +import java.util.HashMap; +import java.util.Map; + +public class UnnecessaryUnboxingInspection extends ExpressionInspection { + private static final Map s_unboxingMethods = new HashMap(8); + private final UnnecessaryUnboxingFix fix = new UnnecessaryUnboxingFix(); + + static { + s_unboxingMethods.put("java.lang.Integer", "intValue"); + s_unboxingMethods.put("java.lang.Short", "shortValue"); + s_unboxingMethods.put("java.lang.Boolean", "booleanValue"); + s_unboxingMethods.put("java.lang.Long", "longValue"); + s_unboxingMethods.put("java.lang.Byte", "byteValue"); + s_unboxingMethods.put("java.lang.Float", "floatValue"); + s_unboxingMethods.put("java.lang.Long", "longValue"); + s_unboxingMethods.put("java.lang.Double", "doubleValue"); + s_unboxingMethods.put("java.lang.Character", "charValue"); + } + + public String getDisplayName() { + return "Unnecessary unboxing (J2SDK 5.0 only)"; + } + + public String getGroupDisplayName() { + return GroupNames.VERBOSE_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "Unnecessary unboxing #ref #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new UnnecessaryUnboxingVisitor(this, inspectionManager, onTheFly); + } + + public InspectionGadgetsFix buildFix(PsiElement location) { + return fix; + } + + private static class UnnecessaryUnboxingFix extends InspectionGadgetsFix { + public String getName() { + return "Remove unboxing"; + } + + public void applyFix(Project project, ProblemDescriptor descriptor) { + final PsiMethodCallExpression methodCall = (PsiMethodCallExpression) descriptor.getPsiElement(); + final PsiReferenceExpression methodExpression = methodCall.getMethodExpression(); + final PsiExpression qualifier = methodExpression.getQualifierExpression(); + final PsiElement parent = methodCall.getParent(); + if (parent instanceof PsiExpression) { + final PsiExpression strippedQualifier = + ParenthesesUtils.stripParentheses(qualifier); + final String strippedQualifierText = strippedQualifier.getText(); + if (ParenthesesUtils.getPrecendence(strippedQualifier) > + ParenthesesUtils.getPrecendence((PsiExpression) parent)) { + replaceExpression(project, methodCall, strippedQualifierText); + } else { + replaceExpression(project, methodCall, + '(' + strippedQualifierText + ')'); + } + } else { + final PsiExpression strippedQualifier = + ParenthesesUtils.stripParentheses(qualifier); + final String strippedQualiferText = strippedQualifier.getText(); + replaceExpression(project, methodCall, strippedQualiferText); + } + } + } + + private static class UnnecessaryUnboxingVisitor extends BaseInspectionVisitor { + private UnnecessaryUnboxingVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitMethodCallExpression(PsiMethodCallExpression expression) { + super.visitMethodCallExpression(expression); + final PsiManager manager = expression.getManager(); + final LanguageLevel languageLevel = manager.getEffectiveLanguageLevel(); + if (languageLevel.equals(LanguageLevel.JDK_1_3) || + languageLevel.equals(LanguageLevel.JDK_1_4)) { + return; + } + final PsiReferenceExpression methodExpression = expression.getMethodExpression(); + if (methodExpression == null) { + return; + } + final String methodName = methodExpression.getReferenceName(); + final PsiExpression qualifier = methodExpression.getQualifierExpression(); + if (qualifier == null) { + return; + } + final PsiType qualifierType = qualifier.getType(); + if (qualifierType == null) { + return; + } + final String qualifierTypeName = qualifierType.getCanonicalText(); + if (!s_unboxingMethods.containsKey(qualifierTypeName)) { + return; + } + final Object unboxingMethod = s_unboxingMethods.get(qualifierTypeName); + if (!unboxingMethod.equals(methodName)) { + return; + } + registerError(expression); + } + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/verbose/UnusedLabelInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/verbose/UnusedLabelInspection.java new file mode 100644 index 000000000000..fb0750a55fef --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/verbose/UnusedLabelInspection.java @@ -0,0 +1,119 @@ +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 UnusedLabelInspection extends StatementInspection { + private final UnusedLabelFix fix = new UnusedLabelFix(); + + public String getDisplayName() { + return "Unused label"; + } + + public String getGroupDisplayName() { + return GroupNames.VERBOSE_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "Unused label #ref #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new UnusedLabelVisitor(this, inspectionManager, onTheFly); + } + + public InspectionGadgetsFix buildFix(PsiElement location) { + return fix; + } + + private static class UnusedLabelFix extends InspectionGadgetsFix { + public String getName() { + return "Remove unused label"; + } + + public void applyFix(Project project, ProblemDescriptor descriptor) { + final PsiElement label = descriptor.getPsiElement(); + final PsiLabeledStatement statement = (PsiLabeledStatement) label.getParent(); + final PsiStatement labeledStatement = statement.getStatement(); + final String statementText = labeledStatement.getText(); + replaceStatement(project, statement, statementText); + } + } + + private static class UnusedLabelVisitor extends BaseInspectionVisitor { + private UnusedLabelVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitLabeledStatement(PsiLabeledStatement statement) { + if (containsBreakOrContinueForLabel(statement)) { + return; + } + final PsiIdentifier labelIdentifier = statement.getLabelIdentifier(); + registerError(labelIdentifier); + } + + private static boolean containsBreakOrContinueForLabel(PsiLabeledStatement statement) { + final LabelFinder labelFinder = new LabelFinder(statement); + statement.accept(labelFinder); + return labelFinder.jumpFound(); + } + } + + private static class LabelFinder extends PsiRecursiveElementVisitor { + private boolean m_found = false; + private String m_label = null; + + private LabelFinder(PsiLabeledStatement target) { + super(); + final PsiIdentifier labelIdentifier = target.getLabelIdentifier(); + m_label = labelIdentifier.getText(); + } + + private boolean jumpFound() { + return m_found; + } + + 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 visitContinueStatement(PsiContinueStatement continueStatement) { + super.visitContinueStatement(continueStatement); + + final PsiIdentifier labelIdentifier = continueStatement.getLabelIdentifier(); + if (labelMatches(labelIdentifier)) { + m_found = true; + } + } + + public void visitBreakStatement(PsiBreakStatement breakStatement) { + super.visitBreakStatement(breakStatement); + + final PsiIdentifier labelIdentifier = breakStatement.getLabelIdentifier(); + + if (labelMatches(labelIdentifier)) { + m_found = true; + } + } + + private boolean labelMatches(PsiIdentifier labelIdentifier) { + if (labelIdentifier == null) { + return false; + } + final String labelText = labelIdentifier.getText(); + return labelText.equals(m_label); + } + + } +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/verbose/VariableUsedInInnerClassVisitor.java b/plugins/InspectionGadgets/src/com/siyeh/ig/verbose/VariableUsedInInnerClassVisitor.java new file mode 100644 index 000000000000..e527cdad943a --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/verbose/VariableUsedInInnerClassVisitor.java @@ -0,0 +1,46 @@ +package com.siyeh.ig.verbose; + +import com.intellij.psi.*; + +public class VariableUsedInInnerClassVisitor extends PsiRecursiveElementVisitor +{ + private final PsiVariable m_variable; + private boolean m_usedInInnerClass = false; + private boolean m_inInnerClass = false; + + public VariableUsedInInnerClassVisitor(PsiVariable variable) + { + super(); + m_variable = variable; + } + + public void visitAnonymousClass(PsiAnonymousClass psiAnonymousClass) + { + final boolean wasInInnerClass = m_inInnerClass; + m_inInnerClass = true; + super.visitAnonymousClass(psiAnonymousClass); + m_inInnerClass = wasInInnerClass; + } + + public void visitReferenceExpression(PsiReferenceExpression reference) + { + final PsiExpression qualifier = reference.getQualifierExpression(); + if(qualifier!=null) + { + qualifier.accept(this); + } + if(m_inInnerClass) + { + final PsiElement element = reference.resolve(); + if(m_variable.equals(element)) + { + m_usedInInnerClass = true; + } + } + } + + public boolean isUsedInInnerClass() + { + return m_usedInInnerClass; + } +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/visibility/FieldHidesSuperclassFieldInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/visibility/FieldHidesSuperclassFieldInspection.java new file mode 100644 index 000000000000..284ea975764a --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/visibility/FieldHidesSuperclassFieldInspection.java @@ -0,0 +1,78 @@ +package com.siyeh.ig.visibility; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.psi.PsiClass; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiField; +import com.siyeh.ig.*; +import com.siyeh.ig.fixes.RenameFix; +import com.siyeh.ig.psiutils.ClassUtils; +import com.siyeh.ig.ui.SingleCheckboxOptionsPanel; + +import javax.swing.*; +import java.util.HashSet; +import java.util.Set; + +public class FieldHidesSuperclassFieldInspection extends FieldInspection { + public boolean m_ignoreInvisibleFields = false; + private final RenameFix fix = new RenameFix(); + + public String getDisplayName() { + return "Field name hides field in superclass"; + } + + public String getGroupDisplayName() { + return GroupNames.VISIBILITY_GROUP_NAME; + } + + protected InspectionGadgetsFix buildFix(PsiElement location) { + return fix; + } + + public String buildErrorString(PsiElement location) { + return "Field '#ref' hides field in superclass #loc"; + } + + public JComponent createOptionsPanel() { + return new SingleCheckboxOptionsPanel("Ignore superclass fields not visible from subclass", + this, "m_ignoreInvisibleFields"); + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new FieldHidesSuperclassFieldVisitor(this, inspectionManager, onTheFly); + } + + private class FieldHidesSuperclassFieldVisitor extends BaseInspectionVisitor { + private FieldHidesSuperclassFieldVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitField(PsiField field) { + final PsiClass aClass = field.getContainingClass(); + if (aClass == null) { + return; + } + final String fieldName = field.getName(); + if ("serialVersionUID".equals(fieldName)) { + return; //special case + } + PsiClass ancestorClass = aClass.getSuperClass(); + final Set visitedClasses = new HashSet(); + while (ancestorClass != null) { + if (!visitedClasses.add(ancestorClass)) { + return; + } + final PsiField ancestorField = ancestorClass.findFieldByName(fieldName, false); + if (ancestorField != null) { + if (!m_ignoreInvisibleFields || ClassUtils.isFieldVisible(ancestorField, aClass)) { + registerFieldError(field); + return; + } + } + ancestorClass = ancestorClass.getSuperClass(); + } + } + + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/visibility/InnerClassVariableHidesOuterClassVariableInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/visibility/InnerClassVariableHidesOuterClassVariableInspection.java new file mode 100644 index 000000000000..5abfc0313ba9 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/visibility/InnerClassVariableHidesOuterClassVariableInspection.java @@ -0,0 +1,66 @@ +package com.siyeh.ig.visibility; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.psi.PsiClass; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiField; +import com.siyeh.ig.*; +import com.siyeh.ig.fixes.RenameFix; +import com.siyeh.ig.psiutils.ClassUtils; + +public class InnerClassVariableHidesOuterClassVariableInspection extends FieldInspection { + private final RenameFix fix = new RenameFix(); + + public String getDisplayName() { + return "Inner class field hides outer class field"; + } + + public String getGroupDisplayName() { + return GroupNames.VISIBILITY_GROUP_NAME; + } + + protected InspectionGadgetsFix buildFix(PsiElement location) { + return fix; + } + + protected boolean buildQuickFixesOnlyForOnTheFlyErrors() { + return true; + } + + public String buildErrorString(PsiElement location) { + return "Inner class field '#ref' hides outer class field #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new InnerClassVariableHidesOuterClassVariableVisitor(this, inspectionManager, onTheFly); + } + + private static class InnerClassVariableHidesOuterClassVariableVisitor extends BaseInspectionVisitor { + private InnerClassVariableHidesOuterClassVariableVisitor(BaseInspection inspection, + InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitField(PsiField field) { + final PsiClass aClass = field.getContainingClass(); + if (aClass == null) { + return; + } + final String fieldName = field.getName(); + if ("serialVersionUID".equals(fieldName)) { + return; //special case + } + PsiClass ancestorClass = + ClassUtils.getContainingClass(aClass); + while (ancestorClass != null) { + if (ancestorClass.findFieldByName(fieldName, false) != null) { + registerFieldError(field); + } + ancestorClass = + ClassUtils.getContainingClass(ancestorClass); + } + } + + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/visibility/LocalVariableHidingMemberVariableInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/visibility/LocalVariableHidingMemberVariableInspection.java new file mode 100644 index 000000000000..940017f15d57 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/visibility/LocalVariableHidingMemberVariableInspection.java @@ -0,0 +1,148 @@ +package com.siyeh.ig.visibility; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.psi.*; +import com.intellij.psi.util.PsiTreeUtil; +import com.siyeh.ig.*; +import com.siyeh.ig.fixes.RenameFix; +import com.siyeh.ig.psiutils.ClassUtils; + +import javax.swing.*; +import javax.swing.event.ChangeEvent; +import javax.swing.event.ChangeListener; +import java.awt.*; + +public class LocalVariableHidingMemberVariableInspection extends MethodInspection { + public boolean m_ignoreInvisibleFields = true; + public boolean m_ignoreStaticMethods = true; + private final RenameFix fix = new RenameFix(); + + public String getDisplayName() { + return "Local variable hides member variable"; + } + + public String getGroupDisplayName() { + return GroupNames.VISIBILITY_GROUP_NAME; + } + + protected InspectionGadgetsFix buildFix(PsiElement location) { + return fix; + } + + protected boolean buildQuickFixesOnlyForOnTheFlyErrors() { + return true; + } + + public String buildErrorString(PsiElement location) { + return "Local variable '#ref' hides member variable #loc"; + } + + public JComponent createOptionsPanel() { + final JPanel panel = new JPanel(new GridBagLayout()); + final JCheckBox ignoreInvisibleCheckBox = new JCheckBox("Ignore superclass fields not visible from subclass", + m_ignoreInvisibleFields); + final JCheckBox ignoreStaticCheckBox = new JCheckBox("Ignore local variables in static methods", + m_ignoreStaticMethods); + + final ButtonModel ignoreInvisibleModel = ignoreInvisibleCheckBox.getModel(); + ignoreInvisibleModel.addChangeListener(new ChangeListener() { + + public void stateChanged(ChangeEvent e) { + m_ignoreInvisibleFields = ignoreInvisibleModel.isSelected(); + } + }); + final ButtonModel ignoreStaticModel = ignoreStaticCheckBox.getModel(); + ignoreStaticModel.addChangeListener(new ChangeListener() { + public void stateChanged(ChangeEvent e) { + m_ignoreStaticMethods = ignoreStaticModel.isSelected(); + } + }); + final GridBagConstraints constraints = new GridBagConstraints(); + constraints.gridx = 0; + constraints.gridy = 0; + constraints.weightx = 1.0; + constraints.anchor = GridBagConstraints.CENTER; + constraints.fill = GridBagConstraints.HORIZONTAL; + panel.add(ignoreInvisibleCheckBox, constraints); + constraints.gridy = 1; + panel.add(ignoreStaticCheckBox, constraints); + return panel; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new LocalVariableHidingMemberVariableVisitor(this, inspectionManager, onTheFly); + } + + private class LocalVariableHidingMemberVariableVisitor extends BaseInspectionVisitor { + private LocalVariableHidingMemberVariableVisitor(BaseInspection inspection, + InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitLocalVariable(PsiLocalVariable variable) { + super.visitLocalVariable(variable); + if (m_ignoreStaticMethods) { + final PsiMethod aMethod = + (PsiMethod) PsiTreeUtil.getParentOfType(variable, PsiMethod.class); + if (aMethod == null) { + return; + } + if (aMethod.hasModifierProperty(PsiModifier.STATIC)) { + return; + } + } + final PsiClass aClass = + ClassUtils.getContainingClass(variable); + if (aClass == null) { + return; + } + final String variableName = variable.getName(); + final PsiField[] fields = aClass.getAllFields(); + for (int i = 0; i < fields.length; i++) { + final PsiField field = fields[i]; + if (checkFieldName(field, variableName, aClass)) { + registerVariableError(variable); + } + } + } + + public void visitParameter(PsiParameter variable) { + super.visitParameter(variable); + if (!(variable.getParent() instanceof PsiTryStatement)) { + return; + } + final PsiClass aClass = + ClassUtils.getContainingClass(variable); + if (aClass == null) { + return; + } + final String variableName = variable.getName(); + final PsiField[] fields = aClass.getAllFields(); + for (int i = 0; i < fields.length; i++) { + final PsiField field = fields[i]; + if (checkFieldName(field, variableName, aClass)) { + registerVariableError(variable); + } + } + } + + private boolean checkFieldName(PsiField field, String variableName, PsiClass aClass) { + if (field == null) { + return false; + } + final String fieldName = field.getName(); + if (fieldName == null) { + return false; + } + if (!fieldName.equals(variableName)) { + return false; + } + if (m_ignoreInvisibleFields && !ClassUtils.isFieldVisible(field, aClass)) { + return false; + } + return true; + } + + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/visibility/MethodOverloadsParentMethodInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/visibility/MethodOverloadsParentMethodInspection.java new file mode 100644 index 000000000000..329aa21aafd6 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/visibility/MethodOverloadsParentMethodInspection.java @@ -0,0 +1,121 @@ +package com.siyeh.ig.visibility; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.psi.*; +import com.intellij.psi.util.PsiSuperMethodUtil; +import com.siyeh.ig.*; +import com.siyeh.ig.fixes.RenameFix; + +import java.util.Set; +import java.util.HashSet; + +public class MethodOverloadsParentMethodInspection extends MethodInspection { + private final RenameFix fix = new RenameFix(); + + public String getDisplayName() { + return "Method overloads method of superclass"; + } + + public String getGroupDisplayName() { + return GroupNames.VISIBILITY_GROUP_NAME; + } + + protected InspectionGadgetsFix buildFix(PsiElement location) { + return fix; + } + + protected boolean buildQuickFixesOnlyForOnTheFlyErrors() { + return true; + } + + public String buildErrorString(PsiElement location) { + return "Method '#ref' overloads a compatible method of a superclass, when overriding might have been intended #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new MethodOverloadsParentMethodVisitor(this, inspectionManager, onTheFly); + } + + private static class MethodOverloadsParentMethodVisitor extends BaseInspectionVisitor { + private MethodOverloadsParentMethodVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitMethod(PsiMethod method) { + final PsiClass aClass = method.getContainingClass(); + if (aClass == null) { + return; + } + if (method.hasModifierProperty(PsiModifier.PRIVATE) + || method.hasModifierProperty(PsiModifier.STATIC)) { + return; + } + + PsiClass ancestorClass = aClass.getSuperClass(); + final Set visitedClasses = new HashSet(); + while (ancestorClass != null) { + if (!visitedClasses.add(ancestorClass)) { + return; + } + if (methodOverloads(method, ancestorClass)) { + registerMethodError(method); + return; + } + ancestorClass = ancestorClass.getSuperClass(); + } + } + + + private static boolean methodOverloads(PsiMethod meth, PsiClass ancestorClass) { + if (methodOverrides(meth, ancestorClass)) { + return false; + } + final String methName = meth.getName(); + final PsiParameterList parameterList = meth.getParameterList(); + final PsiParameter[] parameters = parameterList.getParameters(); + final PsiMethod[] methods = ancestorClass.findMethodsByName(methName, false); + if (methods != null) { + for (int i = 0; i < methods.length; i++) { + final PsiMethod testMethod = methods[i]; + + if (!testMethod.hasModifierProperty(PsiModifier.PRIVATE) + && !testMethod.hasModifierProperty(PsiModifier.STATIC)) { + final PsiParameterList testParameterList = testMethod.getParameterList(); + final PsiParameter[] testParameters = testParameterList.getParameters(); + if (testParameters.length == parameters.length && + !parametersAreCompatible(parameters, testParameters)) { + return true; + } + } + } + } + return false; + } + + private static boolean parametersAreCompatible(PsiParameter[] parameters, PsiParameter[] testParameters) { + for (int i = 0; i < parameters.length; i++) { + final PsiParameter parameter = parameters[i]; + final PsiType parameterType = parameter.getType(); + final PsiParameter testParameter = testParameters[i]; + final PsiType testParameterType = testParameter.getType(); + + if (!parameterType.isAssignableFrom(testParameterType)) { + return false; + } + } + return true; + } + + private static boolean methodOverrides(PsiMethod meth, PsiClass ancestorClass) { + // This code is generics aware. + final PsiMethod[] superMethods = PsiSuperMethodUtil.findSuperMethods(meth, true); + for (int i = 0; i < superMethods.length; i++) { + final PsiMethod superMethod = superMethods[i]; + if (ancestorClass.equals(superMethod.getContainingClass())) { + return true; + } + } + return false; + } + } +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/visibility/MethodOverridesPrivateMethodInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/visibility/MethodOverridesPrivateMethodInspection.java new file mode 100644 index 000000000000..41ae6cae5c90 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/visibility/MethodOverridesPrivateMethodInspection.java @@ -0,0 +1,94 @@ +package com.siyeh.ig.visibility; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.psi.*; +import com.siyeh.ig.*; +import com.siyeh.ig.fixes.RenameFix; + +import java.util.Set; +import java.util.HashSet; + +public class MethodOverridesPrivateMethodInspection extends MethodInspection { + private final RenameFix fix = new RenameFix(); + + public String getDisplayName() { + return "Method overrides private method of superclass"; + } + + public String getGroupDisplayName() { + return GroupNames.VISIBILITY_GROUP_NAME; + } + + protected InspectionGadgetsFix buildFix(PsiElement location) { + return fix; + } + + protected boolean buildQuickFixesOnlyForOnTheFlyErrors() { + return true; + } + + public String buildErrorString(PsiElement location) { + return "Method '#ref' overrides a private method of a superclass #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new MethodOverridesPrivateMethodVisitor(this, inspectionManager, + onTheFly); + } + + private static class MethodOverridesPrivateMethodVisitor + extends BaseInspectionVisitor { + private MethodOverridesPrivateMethodVisitor(BaseInspection inspection, + InspectionManager inspectionManager, + boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitMethod(PsiMethod method) { + final PsiClass aClass = method.getContainingClass(); + if (aClass == null) { + return; + } + final String methodName = method.getName(); + final PsiParameterList parameterList = method.getParameterList(); + if (parameterList == null) { + return; + } + final PsiParameter[] parameters = parameterList.getParameters(); + if (parameters == null) { + return; + } + final int numParameters = parameters.length; + PsiClass ancestorClass = aClass.getSuperClass(); + final Set visitedClasses = new HashSet(); + while (ancestorClass != null) { + if (!visitedClasses.add(ancestorClass)) { + return; + } + final PsiMethod[] methods = ancestorClass.findMethodsByName(methodName, false); + if (methods != null) { + for (int i = 0; i < methods.length; i++) { + final PsiMethod testMethod = methods[i]; + + final PsiParameterList testParametersList = testMethod.getParameterList(); + if (testParametersList == null) { + continue; + } + final int numTestParameters = + testParametersList.getParameters().length; + if (numParameters != numTestParameters) { + continue; + } + if (testMethod.hasModifierProperty(PsiModifier.PRIVATE)) { + registerMethodError(method); + return; + } + } + } + ancestorClass = ancestorClass.getSuperClass(); + } + } + + } + +} \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/visibility/MethodOverridesStaticMethodInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/visibility/MethodOverridesStaticMethodInspection.java new file mode 100644 index 000000000000..1bf63cc95d3a --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/visibility/MethodOverridesStaticMethodInspection.java @@ -0,0 +1,94 @@ +package com.siyeh.ig.visibility; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.psi.*; +import com.siyeh.ig.*; +import com.siyeh.ig.fixes.RenameFix; + +import java.util.Set; +import java.util.HashSet; + +public class MethodOverridesStaticMethodInspection extends MethodInspection { + private final RenameFix fix = new RenameFix(); + + public String getDisplayName() { + return "Method overrides static method of superclass"; + } + + public String getGroupDisplayName() { + return GroupNames.VISIBILITY_GROUP_NAME; + } + + protected InspectionGadgetsFix buildFix(PsiElement location) { + return fix; + } + + protected boolean buildQuickFixesOnlyForOnTheFlyErrors() { + return true; + } + + public String buildErrorString(PsiElement location) { + return "Method '#ref' overrides a static method of a superclass #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new MethodOverridesStaticMethodVisitor(this, inspectionManager, + onTheFly); + } + + private static class MethodOverridesStaticMethodVisitor + extends BaseInspectionVisitor { + private MethodOverridesStaticMethodVisitor(BaseInspection inspection, + InspectionManager inspectionManager, + boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitMethod(PsiMethod method) { + final PsiClass aClass = method.getContainingClass(); + if (aClass == null) { + return; + } + final String methName = method.getName(); + final PsiParameterList parameterList = method.getParameterList(); + if (parameterList == null) { + return; + } + final PsiParameter[] parameters = parameterList.getParameters(); + if (parameters == null) { + return; + } + final int numParameters = parameters.length; + PsiClass ancestorClass = aClass.getSuperClass(); + final Set visitedClasses = new HashSet(); + while (ancestorClass != null) { + if (!visitedClasses.add(ancestorClass)) { + return; + } + final PsiMethod[] methods = ancestorClass.findMethodsByName(methName, false); + if (methods != null) { + for (int i = 0; i < methods.length; i++) { + final PsiMethod testMethod = methods[i]; + final PsiParameterList testParametersList = testMethod.getParameterList(); + if (testParametersList == null) { + continue; + } + final int numTestParameters = testParametersList.getParameters() + .length; + if (numParameters != numTestParameters) { + continue; + } + if (testMethod.hasModifierProperty(PsiModifier.STATIC) && + !testMethod.hasModifierProperty(PsiModifier.PRIVATE)) { + registerMethodError(method); + return; + } + } + } + ancestorClass = ancestorClass.getSuperClass(); + } + } + + } + +} \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/visibility/ParameterHidingMemberVariableInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/visibility/ParameterHidingMemberVariableInspection.java new file mode 100644 index 000000000000..0fea136bfd51 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/visibility/ParameterHidingMemberVariableInspection.java @@ -0,0 +1,170 @@ +package com.siyeh.ig.visibility; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.psi.*; +import com.intellij.psi.util.PsiTreeUtil; +import com.siyeh.ig.*; +import com.siyeh.ig.fixes.RenameFix; +import com.siyeh.ig.psiutils.ClassUtils; + +import javax.swing.*; +import javax.swing.event.ChangeEvent; +import javax.swing.event.ChangeListener; +import java.awt.*; + +public class ParameterHidingMemberVariableInspection extends MethodInspection { + public boolean m_ignoreInvisibleFields = false; + public boolean m_ignoreStaticMethodParametersHidingInstanceFields = false; + public boolean m_ignoreForConstructors = false; + public boolean m_ignoreForPropertySetters = false; + private final RenameFix fix = new RenameFix(); + + public String getDisplayName() { + return "Parameter hides member variable"; + } + + public String getGroupDisplayName() { + return GroupNames.VISIBILITY_GROUP_NAME; + } + + protected InspectionGadgetsFix buildFix(PsiElement location) { + return fix; + } + + protected boolean buildQuickFixesOnlyForOnTheFlyErrors() { + return true; + } + + public String buildErrorString(PsiElement location) { + return "Parameter '#ref' hides member variable #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new ParameterHidingMemberVariableVisitor(this, inspectionManager, onTheFly); + } + + private class ParameterHidingMemberVariableVisitor extends BaseInspectionVisitor { + private ParameterHidingMemberVariableVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitParameter(PsiParameter variable) { + super.visitParameter(variable); + if (variable.getParent() instanceof PsiTryStatement) { + return; + } + final PsiMethod method = + (PsiMethod) PsiTreeUtil.getParentOfType(variable, PsiMethod.class); + if (method == null) { + return; + } + if (m_ignoreForConstructors && method.isConstructor()) { + return; + } + if (m_ignoreForPropertySetters) { + final String methodName = method.getName(); + final PsiType returnType = method.getReturnType(); + if (methodName.startsWith("set") && returnType.equals(PsiType.VOID)) { + return; + } + } + + final PsiClass aClass = + ClassUtils.getContainingClass(variable); + if (aClass == null) { + return; + } + final String variableName = variable.getName(); + final PsiField[] fields = aClass.getAllFields(); + for (int i = 0; i < fields.length; i++) { + final PsiField field = fields[i]; + if (checkFieldName(field, variableName, aClass)) { + if (m_ignoreStaticMethodParametersHidingInstanceFields && + !field.hasModifierProperty(PsiModifier.STATIC) && + method.hasModifierProperty(PsiModifier.STATIC)) { + continue; + } + registerVariableError(variable); + } + } + } + + private boolean checkFieldName(PsiField field, String variableName, PsiClass aClass) { + if (field == null) { + return false; + } + final String fieldName = field.getName(); + if (fieldName == null) { + return false; + } + if (!fieldName.equals(variableName)) { + return false; + } + if (m_ignoreInvisibleFields && !ClassUtils.isFieldVisible(field, aClass)) { + return false; + } + return true; + } + + } + + public JComponent createOptionsPanel() { + final GridBagLayout layout = new GridBagLayout(); + final JPanel panel = new JPanel(layout); + final JCheckBox settersCheckBox = new JCheckBox("Ignore for property setters", m_ignoreForPropertySetters); + final ButtonModel settersModel = settersCheckBox.getModel(); + settersModel.addChangeListener(new ChangeListener() { + + public void stateChanged(ChangeEvent e) { + m_ignoreForPropertySetters = settersModel.isSelected(); + } + }); + final JCheckBox ignoreInvisibleFieldsCheck = new JCheckBox("Ignore superclass fields not visible from subclass", + m_ignoreInvisibleFields); + + final ButtonModel invisibleFieldsModel = ignoreInvisibleFieldsCheck.getModel(); + invisibleFieldsModel.addChangeListener(new ChangeListener() { + + public void stateChanged(ChangeEvent e) { + m_ignoreInvisibleFields = invisibleFieldsModel.isSelected(); + } + }); + + final JCheckBox constructorCheckBox = new JCheckBox("Ignore for constructors", m_ignoreForConstructors); + final ButtonModel constructorModel = constructorCheckBox.getModel(); + constructorModel.addChangeListener(new ChangeListener() { + + public void stateChanged(ChangeEvent e) { + m_ignoreForConstructors = constructorModel.isSelected(); + } + }); + final JCheckBox staticMethodsCheckbox = new JCheckBox("Ignore for static method parameters hiding instance fields", m_ignoreStaticMethodParametersHidingInstanceFields); + final ButtonModel staticMethodsModel = staticMethodsCheckbox.getModel(); + staticMethodsModel.addChangeListener(new ChangeListener() { + + public void stateChanged(ChangeEvent e) { + m_ignoreStaticMethodParametersHidingInstanceFields = staticMethodsModel.isSelected(); + } + }); + + final GridBagConstraints constraints = new GridBagConstraints(); + constraints.fill = GridBagConstraints.HORIZONTAL; + + constraints.gridx = 0; + constraints.gridy = 0; + panel.add(settersCheckBox, constraints); + + constraints.gridx = 0; + constraints.gridy = 1; + panel.add(constructorCheckBox, constraints); + + constraints.gridx = 0; + constraints.gridy = 2; + panel.add(ignoreInvisibleFieldsCheck, constraints); + + constraints.gridx = 0; + constraints.gridy = 3; + panel.add(staticMethodsCheckbox, constraints); + return panel; + } +} diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/AbstractClassExtendsConcreteClass.html b/plugins/InspectionGadgets/src/inspectionDescriptions/AbstractClassExtendsConcreteClass.html new file mode 100644 index 000000000000..c507ff9c3f39 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/AbstractClassExtendsConcreteClass.html @@ -0,0 +1,6 @@ + +
+ +This inspection reports any instances of abstract classes which extend concrete classes. +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/AbstractClassWithoutAbstractMethods.html b/plugins/InspectionGadgets/src/inspectionDescriptions/AbstractClassWithoutAbstractMethods.html new file mode 100644 index 000000000000..0710ae4273c3 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/AbstractClassWithoutAbstractMethods.html @@ -0,0 +1,6 @@ + +
+ +This inspection reports any instances of abstract classes without abstract methods. +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/AbstractMethodCallInConstructor.html b/plugins/InspectionGadgets/src/inspectionDescriptions/AbstractMethodCallInConstructor.html new file mode 100644 index 000000000000..d8331988c6dc --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/AbstractMethodCallInConstructor.html @@ -0,0 +1,8 @@ + +
+ +This inspection reports any calls of abstract methods within a constructor of an +abstract class. Such calls may result in subtle bugs, as the object is not guaranteed to be initialized +before the method call occurs. +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/AbstractMethodOverridesAbstractMethod.html b/plugins/InspectionGadgets/src/inspectionDescriptions/AbstractMethodOverridesAbstractMethod.html new file mode 100644 index 000000000000..16b58abb5690 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/AbstractMethodOverridesAbstractMethod.html @@ -0,0 +1,6 @@ + +
+ +This inspection reports any instances of abstract methods which override abstract methods. +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/AbstractMethodOverridesConcreteMethod.html b/plugins/InspectionGadgets/src/inspectionDescriptions/AbstractMethodOverridesConcreteMethod.html new file mode 100644 index 000000000000..0337d5b88651 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/AbstractMethodOverridesConcreteMethod.html @@ -0,0 +1,6 @@ + +
+ +This inspection reports any instances of abstract methods which override concrete methods. +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/Annotation.html b/plugins/InspectionGadgets/src/inspectionDescriptions/Annotation.html new file mode 100644 index 000000000000..a591929d0324 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/Annotation.html @@ -0,0 +1,7 @@ + +
+ +This inspection reports any uses of annotations. +Annotations are not supported under Java 1.4 or earlier JVMs. +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/AnnotationClass.html b/plugins/InspectionGadgets/src/inspectionDescriptions/AnnotationClass.html new file mode 100644 index 000000000000..811689892c4c --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/AnnotationClass.html @@ -0,0 +1,7 @@ + +
+ +This inspection reports any instances of annotation interfaces. +Such interfaces are not supported under Java 1.4 or earlier JVMs. +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/AnonymousClassComplexity.html b/plugins/InspectionGadgets/src/inspectionDescriptions/AnonymousClassComplexity.html new file mode 100644 index 000000000000..27a9bc5a485c --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/AnonymousClassComplexity.html @@ -0,0 +1,11 @@ + +
+ +This inspection reports any instances of anonymous inner classes with too high of a total complexity. The +total complexity of a class is the sum of the cyclomatic complexities of all the methods +and initializers the class declares. Inherited methods and initializers are not counted +toward the total complexity. Anonymous classes with more than very low complexities may be +difficult to understand, and should probably be promoted to become named inner classes. +

+Use the field provided below to specify the maximum acceptable complexity a class might have.

Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/AnonymousClassMethodCount.html b/plugins/InspectionGadgets/src/inspectionDescriptions/AnonymousClassMethodCount.html new file mode 100644 index 000000000000..e3a4f112ab59 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/AnonymousClassMethodCount.html @@ -0,0 +1,10 @@ + +
+ +This inspection reports any instances of anonymous inner class with too many methods. +Anonymous classes with more than a very low number of methods may be +difficult to understand, and should probably be promoted to become named inner classes. +

+Use the field provided below to specify the maximum acceptable number of methods +an anonymous inner class might have.

Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/AnonymousInnerClass.html b/plugins/InspectionGadgets/src/inspectionDescriptions/AnonymousInnerClass.html new file mode 100644 index 000000000000..55b6ffe8f1fe --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/AnonymousInnerClass.html @@ -0,0 +1,8 @@ + +
+ +This inspection reports any anonymous inner classes. Some code standards discourage +the use of anonymous inner classes. + +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/AssertAsName.html b/plugins/InspectionGadgets/src/inspectionDescriptions/AssertAsName.html new file mode 100644 index 000000000000..096ff639eab9 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/AssertAsName.html @@ -0,0 +1,8 @@ + +
+ +This inspection reports any instances of variables, methods, or classes named +assert. Such names are legal under Java 1.3 or +earlier JVMs, but will cause problems under Java 1.4 or later. +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/AssertStatement.html b/plugins/InspectionGadgets/src/inspectionDescriptions/AssertStatement.html new file mode 100644 index 000000000000..5e6881e9a1b9 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/AssertStatement.html @@ -0,0 +1,7 @@ + +
+ +This inspection reports any instances of assert statements. +Such statements are not supported under Java 1.3 or earlier JVMs. +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/AssertsWithoutMessages.html b/plugins/InspectionGadgets/src/inspectionDescriptions/AssertsWithoutMessages.html new file mode 100644 index 000000000000..cf2cd4b05178 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/AssertsWithoutMessages.html @@ -0,0 +1,9 @@ + +
+ +This inspection reports any instances of calls to JUnit assertXXX() methods that don't +report an error message on assertion failure. Error messages may help clarify the test case's +intent. + +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/AssignmentToCatchBlockParameter.html b/plugins/InspectionGadgets/src/inspectionDescriptions/AssignmentToCatchBlockParameter.html new file mode 100644 index 000000000000..6e515543cd25 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/AssignmentToCatchBlockParameter.html @@ -0,0 +1,8 @@ + +
+ +This inspection reports any instances of assignment to variable declared as a catch block parameter. +While occasionally intended, this construct can be confusing. + +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/AssignmentToCollectionFieldFromParameter.html b/plugins/InspectionGadgets/src/inspectionDescriptions/AssignmentToCollectionFieldFromParameter.html new file mode 100644 index 000000000000..ad1fae3eb832 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/AssignmentToCollectionFieldFromParameter.html @@ -0,0 +1,10 @@ + +
+ +This inspection reports any attempt to assign an array or Collection field from a method parameter. +Since the array or Collection may have it's contents modified by the calling method, this construct may +result in an object having it's state modified unexpectedly. While occasionally useful for performance +reasons, this construct is inherently bug-prone. + +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/AssignmentToDateFieldFromParameter.html b/plugins/InspectionGadgets/src/inspectionDescriptions/AssignmentToDateFieldFromParameter.html new file mode 100644 index 000000000000..b2afc51a7bf7 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/AssignmentToDateFieldFromParameter.html @@ -0,0 +1,12 @@ + +
+ +This inspection reports any attempt to assign a java.lang.Date or +java.lang.Calendar field from a method parameter. +Since Date or Calendar are often +treated as immutable values but are actually mutable, assigning to such a field from a method parameter may +result in an object having it's state modified unexpectedly. While occasionally useful for performance +reasons, this construct is inherently bug-prone. + +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/AssignmentToForLoopParameter.html b/plugins/InspectionGadgets/src/inspectionDescriptions/AssignmentToForLoopParameter.html new file mode 100644 index 000000000000..8b9d98af1e4d --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/AssignmentToForLoopParameter.html @@ -0,0 +1,9 @@ + +
+ +This inspection reports any instances of assignment a variable declared in a for statement +in the body of that statement. It also reports any attempt to increment or decrement the variable. +While occasionally intended, this construct can be extremely confusing, and is often the result of a typo. + +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/AssignmentToMethodParameter.html b/plugins/InspectionGadgets/src/inspectionDescriptions/AssignmentToMethodParameter.html new file mode 100644 index 000000000000..08214f7454f6 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/AssignmentToMethodParameter.html @@ -0,0 +1,9 @@ + +
+ +This inspection reports any instances of assignment to a +variable declared as a method parameter. It also reports any attempt to increment or decrement the variable. +While occasionally intended, this construct can be extremely confusing, and is often the result of a typo. + +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/AssignmentToNull.html b/plugins/InspectionGadgets/src/inspectionDescriptions/AssignmentToNull.html new file mode 100644 index 000000000000..eb3545a7ea71 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/AssignmentToNull.html @@ -0,0 +1,10 @@ + +
+ +This inspection reports any instances of the assignment of a variable to null, outside of declarations. +While occasionally useful for triggering garbage collection, this construct may make the code more prone +to NullPointerExceptions, and often indicates that the developer doesn't really understand the classes +intended semantics. + +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/AssignmentUsedAsCondition.html b/plugins/InspectionGadgets/src/inspectionDescriptions/AssignmentUsedAsCondition.html new file mode 100644 index 000000000000..8447bf7987d9 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/AssignmentUsedAsCondition.html @@ -0,0 +1,11 @@ + +
+ +This inspection reports any instances of an assignment being +used as the condition of an if, while, for or +do statement. While occasionally intended, +this usage is confusing, and often indicates a typo +(= instead of ==). + +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/AutoBoxing.html b/plugins/InspectionGadgets/src/inspectionDescriptions/AutoBoxing.html new file mode 100644 index 000000000000..a1df37d071d0 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/AutoBoxing.html @@ -0,0 +1,7 @@ + +
+ +This inspection reports any instances of "auto-boxing", e.g. the automatic wrapping of primitive values as objects, where needed. +Code which relies on auto-boxing will not work in pre-Java 5.0 environments. +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/AutoUnboxing.html b/plugins/InspectionGadgets/src/inspectionDescriptions/AutoUnboxing.html new file mode 100644 index 000000000000..c029d2e29204 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/AutoUnboxing.html @@ -0,0 +1,7 @@ + +
+ +This inspection reports any instances of "auto-unboxing", e.g. the automatic unwrapping of objects into primitive values, where needed. +Code which relies on auto-boxing will not work in pre-Java 5.0 environments. +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/BigDecimalEquals.html b/plugins/InspectionGadgets/src/inspectionDescriptions/BigDecimalEquals.html new file mode 100644 index 000000000000..cdacda45be4e --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/BigDecimalEquals.html @@ -0,0 +1,12 @@ + +
+ +This inspection reports any instances of .equals() being called +to compare two java.math.BigDecimal numbers. This is normaly +a mistake, as two java.math.BigDecimals are only equal if +they are equal in both value and scale, so that 2.0 is not equal to 2.00 +To compare java.math.BigDecimals for mathematical equality, +use .compareTo() instead. + +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/BooleanConstructor.html b/plugins/InspectionGadgets/src/inspectionDescriptions/BooleanConstructor.html new file mode 100644 index 000000000000..5fcdd95bfc28 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/BooleanConstructor.html @@ -0,0 +1,9 @@ + +
+ +This inspection reports any attempt to instantiate a new Boolean object. Constructing +new Boolean objects is rarely necessary, and may cause + performance problems if done often enough. + +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/BreakStatement.html b/plugins/InspectionGadgets/src/inspectionDescriptions/BreakStatement.html new file mode 100644 index 000000000000..d2ec29e05b4d --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/BreakStatement.html @@ -0,0 +1,9 @@ + +
+ +This inspection reports any instances of break statements, +other than at the end of a switch statement branch. +break statements complicate refactoring, and can be confusing. + +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/BreakStatementWithLabel.html b/plugins/InspectionGadgets/src/inspectionDescriptions/BreakStatementWithLabel.html new file mode 100644 index 000000000000..8c6df1044d2c --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/BreakStatementWithLabel.html @@ -0,0 +1,8 @@ + +
+ +This inspection reports any instances of break statements with labels. +Labeled break statements complicate refactoring, and can be confusing. + +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/BusyWait.html b/plugins/InspectionGadgets/src/inspectionDescriptions/BusyWait.html new file mode 100644 index 000000000000..ef2d09c3e482 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/BusyWait.html @@ -0,0 +1,9 @@ + +
+ +This inspection reports instances of calls to java.lang.Thread.sleep() that occur inside loops. Such calls +are indicative of "busy-waiting". Busy-waiting is often inefficient, and may result in unexpected deadlocks +as busy-waiting threads do not release locked resources. + +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/CStyleArrayDeclaration.html b/plugins/InspectionGadgets/src/inspectionDescriptions/CStyleArrayDeclaration.html new file mode 100644 index 000000000000..b1e263aa2ff0 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/CStyleArrayDeclaration.html @@ -0,0 +1,8 @@ + +
+ +This inspection reports array declarations made using C-style syntax, with the array indicator attached to the variable, +rather than Java-style syntax, with the array indicator attached to the type. + +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/CastThatLosesPrecision.html b/plugins/InspectionGadgets/src/inspectionDescriptions/CastThatLosesPrecision.html new file mode 100644 index 000000000000..695a1ccc750f --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/CastThatLosesPrecision.html @@ -0,0 +1,9 @@ + +
+ +This inspection reports any instances of cast operations between built-in numeric types which may +result in loss of precision. Such casts are not necessarily a problem, but may result in difficult to +trace bugs if the loss of precision is unexpected. + +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/CastToConcreteClass.html b/plugins/InspectionGadgets/src/inspectionDescriptions/CastToConcreteClass.html new file mode 100644 index 000000000000..b0e15c8f59cb --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/CastToConcreteClass.html @@ -0,0 +1,8 @@ + +
+ +This inspection reports any instances of casting a value to a concrete class, rather than an interface. +Such declarations may represent a failure of abstraction, and may make testing more difficult. +Declarations whose classes come from system or third-party libraries will not be reported by this inspection. +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/CatchGenericClass.html b/plugins/InspectionGadgets/src/inspectionDescriptions/CatchGenericClass.html new file mode 100644 index 000000000000..8805f432fe0b --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/CatchGenericClass.html @@ -0,0 +1,14 @@ + +
+ +This inspection reports instances where a generic exception class is caught. For clarity and +precision, it is recommended that specific exception classes be caught instead of generic ones. +This inspection reports catch blocks with arguments of the following types: +
    +
  • java.lang.Throwable
  • +
  • java.lang.Exception
  • +
  • java.lang.RuntimeException
  • +
+
+
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/ChainedEquality.html b/plugins/InspectionGadgets/src/inspectionDescriptions/ChainedEquality.html new file mode 100644 index 000000000000..603da3840025 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/ChainedEquality.html @@ -0,0 +1,8 @@ + +
+ +This inspection reports any instances of chained equality comparisons (i.e. a==b==c). +Such comparisons are confusing. + +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/ChainedMethodCall.html b/plugins/InspectionGadgets/src/inspectionDescriptions/ChainedMethodCall.html new file mode 100644 index 000000000000..12d587c14d32 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/ChainedMethodCall.html @@ -0,0 +1,8 @@ + +
+ +This inspection reports any instances of method calls whose target is another +method call. + +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/CharacterComparison.html b/plugins/InspectionGadgets/src/inspectionDescriptions/CharacterComparison.html new file mode 100644 index 000000000000..1b8d60d226de --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/CharacterComparison.html @@ -0,0 +1,8 @@ + +
+ +This inspection reports any ordinal comparison of char values. In an internationalized +environment, such comparisons are rarely correct. + +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/CheckedExceptionClass.html b/plugins/InspectionGadgets/src/inspectionDescriptions/CheckedExceptionClass.html new file mode 100644 index 000000000000..4afddb86b36f --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/CheckedExceptionClass.html @@ -0,0 +1,9 @@ + +
+ +This inspection reports any instances of checked exception classes (i.e. subclasses of Exception which are +not also subclasses of RuntimeException). Certain coding standards require that all user-defined exception +classes be unchecked. + +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/ClassComplexity.html b/plugins/InspectionGadgets/src/inspectionDescriptions/ClassComplexity.html new file mode 100644 index 000000000000..abcb8c29d0e7 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/ClassComplexity.html @@ -0,0 +1,10 @@ + +
+ +This inspection reports any instances of class with too high of a total complexity. The +total complexity of a class is the sum of the cyclomatic complexities of all the methods +and initializers the class declares. Inherited methods and initializers are not counted +toward the total complexity. +

+Use the field provided below to specify the maximum acceptable complexity a class might have.

Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/ClassCoupling.html b/plugins/InspectionGadgets/src/inspectionDescriptions/ClassCoupling.html new file mode 100644 index 000000000000..a68ff529f6bb --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/ClassCoupling.html @@ -0,0 +1,12 @@ + +
+ +This inspection reports any instances of classes which are highly coupled, i.e. that reference too many other classes. +Classes with too high a coupling can be very fragile, and should probably be broken up. References to system classes +(those in the java.or javax. packages), are not +counted for purposes of this inspection. +

+Use the field provided below to specify the maximum acceptable coupling a class might have. + +

Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/ClassEscapesItsScope.html b/plugins/InspectionGadgets/src/inspectionDescriptions/ClassEscapesItsScope.html new file mode 100644 index 000000000000..7e3cbac1f980 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/ClassEscapesItsScope.html @@ -0,0 +1,10 @@ + +
+ +This inspection reports any references to classes which allow the class name to +be used outside the class's stated scope. For instance, this inspection would report +a public method which returns a private inner class, or a protected field whose +type is a package-visible class. While legal Java, such references can be very +confusing, and make reuse difficult. +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/ClassInTopLevelPackage.html b/plugins/InspectionGadgets/src/inspectionDescriptions/ClassInTopLevelPackage.html new file mode 100644 index 000000000000..30fb270610ba --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/ClassInTopLevelPackage.html @@ -0,0 +1,6 @@ + +
+This inspection reports any classes +which do not contain package declarations. +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/ClassInheritanceDepth.html b/plugins/InspectionGadgets/src/inspectionDescriptions/ClassInheritanceDepth.html new file mode 100644 index 000000000000..e390fdd7101c --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/ClassInheritanceDepth.html @@ -0,0 +1,8 @@ + +
+ +This inspection reports any instances of class too deep in the inheritance hierarchy. Classes too deeply inherited +may be confusing, and are a good sign that refactoring may be necessary. +

+Use the field provided below to specify the maximum acceptable inheritance depth a class might have.

Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/ClassInitializer.html b/plugins/InspectionGadgets/src/inspectionDescriptions/ClassInitializer.html new file mode 100644 index 000000000000..371218884b5a --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/ClassInitializer.html @@ -0,0 +1,10 @@ + +
+ +This inspection reports any of non-static initializers +in classes. Some coding standards prohibit such initializers, prefering initialization to be done +in constructors or field initializers. Non-static initializers +may also be inadvertantly created by deleting the static keyword, +resulting in obscure bugs. +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/ClassMayBeInterface.html b/plugins/InspectionGadgets/src/inspectionDescriptions/ClassMayBeInterface.html new file mode 100644 index 000000000000..8b340574bafb --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/ClassMayBeInterface.html @@ -0,0 +1,9 @@ + +
+This inspection reports any concrete or abstract classes +which may be simplified to be interfaces. This occurs if the class has no superclass (other +than Object), has no fields declared that are not static, final, and public, and has no +methods declared that are not public and abstract, and no inner classes +that cannot themselves be interfaces. +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/ClassNameDiffersFromFileName.html b/plugins/InspectionGadgets/src/inspectionDescriptions/ClassNameDiffersFromFileName.html new file mode 100644 index 000000000000..e4244de64a6f --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/ClassNameDiffersFromFileName.html @@ -0,0 +1,9 @@ + +
+ +This inspection reports any instances of top-level class names which do not match the name of +their containing file. While the Java specification allows such naming for non-public classes, +such misnamed files can be confusing, and may degrade the usefulness of various +software tools. +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/ClassNamePrefixedWithPackageName.html b/plugins/InspectionGadgets/src/inspectionDescriptions/ClassNamePrefixedWithPackageName.html new file mode 100644 index 000000000000..65ccd49a6f7e --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/ClassNamePrefixedWithPackageName.html @@ -0,0 +1,9 @@ + +
+ +This inspection reports any instances of classes whose names are prefixed with their package names, irrespective of +capitalization. While occasionally reasonable, this is often due to a poor naming scheme, and may be redundant and +annoying. + +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/ClassNameSameAsAncestorName.html b/plugins/InspectionGadgets/src/inspectionDescriptions/ClassNameSameAsAncestorName.html new file mode 100644 index 000000000000..7604eb9d3d96 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/ClassNameSameAsAncestorName.html @@ -0,0 +1,8 @@ + +
+ +This inspection reports any instances of class being named identically to one of their +super classes (but in different packages). Such class name may be very confusing. + +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/ClassNamingConvention.html b/plugins/InspectionGadgets/src/inspectionDescriptions/ClassNamingConvention.html new file mode 100644 index 000000000000..b24a7af0b638 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/ClassNamingConvention.html @@ -0,0 +1,11 @@ + +
+ +This inspection reports instances of classes whose names are either too short, too long, or do not follow +the specified regular expression pattern. +

+Use the fields provided below to specify mininum length, maximum length and regular expression expected for class names. +(Regular expressions are in standard java.util.regex format.) + +

Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/ClassNestingDepth.html b/plugins/InspectionGadgets/src/inspectionDescriptions/ClassNestingDepth.html new file mode 100644 index 000000000000..f7a860acd106 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/ClassNestingDepth.html @@ -0,0 +1,8 @@ + +
+ +This inspection reports any instances of inner classes too deeply nested. Nesting inner classes inside +inner classes is almost certain to be confusing, and is a good sign that refactoring may be necessary. +

+Use the field provided below to specify the maximum acceptable nesting depth a class might have.

Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/ClassReferencesSubclass.html b/plugins/InspectionGadgets/src/inspectionDescriptions/ClassReferencesSubclass.html new file mode 100644 index 000000000000..05fce675a405 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/ClassReferencesSubclass.html @@ -0,0 +1,7 @@ + +
+ +This inspection reports any instances of classes which contain references to one of their subclasses. +Such references may be confusing, and violate several rules of object-oriented design. +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/ClassWithMultipleLoggers.html b/plugins/InspectionGadgets/src/inspectionDescriptions/ClassWithMultipleLoggers.html new file mode 100644 index 000000000000..d03996a3e4b9 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/ClassWithMultipleLoggers.html @@ -0,0 +1,12 @@ + +
+ +This inspection reports any instances of classes which have multiple loggers declared. +Ensuring that every class has a single dedicated logger is an important step in providing a unified logging +implementation for an application. Interfaces, +enumerations, annotations, inner classes, and abstract classes are not reported by this inspection. +

+Use the field below to specify the name of the class which will be used for logging in this project. +Classes which do declare multiple fields of that class will be reported by this inspection. +

Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/ClassWithoutConstructor.html b/plugins/InspectionGadgets/src/inspectionDescriptions/ClassWithoutConstructor.html new file mode 100644 index 000000000000..272bb4089132 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/ClassWithoutConstructor.html @@ -0,0 +1,7 @@ + +
+ +This inspection reports any instances of a classes without constructors. Some coding standards prohibit such classes. + +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/ClassWithoutLogger.html b/plugins/InspectionGadgets/src/inspectionDescriptions/ClassWithoutLogger.html new file mode 100644 index 000000000000..492eefa542bf --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/ClassWithoutLogger.html @@ -0,0 +1,11 @@ + +
+ +This inspection reports any instances of classes which do not have a logger declared. +Ensuring that every class has a dedicated logger is an important step in providing a unified logging +implementation for an application. Interfaces, enumerations, annotations, inner classes, and abstract classes are not reported by this inspection. +

+Use the field below to specify the name of the class which will be used for logging in this project. +Classes which do not declare a field of that class will be reported by this inspection. +

Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/ClassWithoutNoArgConstructor.html b/plugins/InspectionGadgets/src/inspectionDescriptions/ClassWithoutNoArgConstructor.html new file mode 100644 index 000000000000..882af062dec7 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/ClassWithoutNoArgConstructor.html @@ -0,0 +1,8 @@ + +
+ +This inspection reports any instances of a classes without a no-argument constructor. +Such constructors are necessary in some contexts if a class is to be created reflexively. + +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/ClassWithoutToString.html b/plugins/InspectionGadgets/src/inspectionDescriptions/ClassWithoutToString.html new file mode 100644 index 000000000000..d074862fb4a1 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/ClassWithoutToString.html @@ -0,0 +1,8 @@ + +
+ +This inspection reports instances classes which do not implement the toString() method. +It is handy to have all classes implement toString() for debugging purposes. + +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/CloneCallsConstructors.html b/plugins/InspectionGadgets/src/inspectionDescriptions/CloneCallsConstructors.html new file mode 100644 index 000000000000..3b19a7d61b07 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/CloneCallsConstructors.html @@ -0,0 +1,10 @@ + +
+ +This inspection reports instances of calls to object constructors inside clone() methods. +Instantiation of objects inside of clone() should be done by calling clone(), +instead of creating the object directly, to support later subclassing. + + +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/CloneCallsSuperClone.html b/plugins/InspectionGadgets/src/inspectionDescriptions/CloneCallsSuperClone.html new file mode 100644 index 000000000000..980619f6c785 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/CloneCallsSuperClone.html @@ -0,0 +1,8 @@ + +
+ +This inspection reports instances of clone() methods which do not call super.clone(). +Cloning an object without calling super.clone() may result in objects being improperly initialized. + +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/CloneDeclaresCloneNotSupported.html b/plugins/InspectionGadgets/src/inspectionDescriptions/CloneDeclaresCloneNotSupported.html new file mode 100644 index 000000000000..513c5756a6a9 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/CloneDeclaresCloneNotSupported.html @@ -0,0 +1,13 @@ + +
+ +This inspection reports instances of clone() methods which are not declared as throwing the +CloneNotSupportedException. If clone() is not declared +to possibly throw CloneNotSupportedException, then subclasses which need to +prohibit cloning will not be able to do so in the standard way. This inspection will not report +clone() methods declared final, +or clone() methods on final classes. + + +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/CloneableClassInSecureContext.html b/plugins/InspectionGadgets/src/inspectionDescriptions/CloneableClassInSecureContext.html new file mode 100644 index 000000000000..29e29301de82 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/CloneableClassInSecureContext.html @@ -0,0 +1,10 @@ + +
+ +This inspection reports any instances of classes which may be cloned. A class +may be cloned if it supports the Cloneable interface, +and its clone() method is not defined to immediately +throw an error. Cloneable classes may be dangerous in code intended for secure use. + +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/CloneableImplementsClone.html b/plugins/InspectionGadgets/src/inspectionDescriptions/CloneableImplementsClone.html new file mode 100644 index 000000000000..497ea9e2a674 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/CloneableImplementsClone.html @@ -0,0 +1,9 @@ + +
+ +This inspection reports classes which implement the Cloneable interfaces, but which do not override the +clone() method. Such classes use the default implementation of clone(), which is often not the desired +behaviour. + +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/CollectionsMustHaveInitialCapacity.html b/plugins/InspectionGadgets/src/inspectionDescriptions/CollectionsMustHaveInitialCapacity.html new file mode 100644 index 000000000000..0277f4f179a7 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/CollectionsMustHaveInitialCapacity.html @@ -0,0 +1,19 @@ + +
+ +This inspection reports any attempt to instantiate a new Collection object without specifying +an initial capacity. If no initial capacity is specified, a default capacity is used, which will rarely be optimal. Failing +to specify initial capacities for collections may result in performance issues, if space needs to be reallocated and +memory copied when capacity is exceeded. This inspection checks allocations of the following classes: +
    +
  • java.util.ArrayList +
  • java.util.BitSet +
  • java.util.HashMap +
  • java.util.HashSet +
  • java.util.Hashtable +
  • java.util.Vector +
  • java.util.WeakHashMap +
+
+
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/CompareToUsesNonFinalVariable.html b/plugins/InspectionGadgets/src/inspectionDescriptions/CompareToUsesNonFinalVariable.html new file mode 100644 index 000000000000..0fb936266444 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/CompareToUsesNonFinalVariable.html @@ -0,0 +1,9 @@ + +
+ +This inspection reports any implementations of compareTo() which access +non-final variables. Such access may result in compareTo() +returning different results at different points in an object's lifecycle, which may in turn cause problems when +using the standard Collections classes. +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/ComparisonOfShortAndChar.html b/plugins/InspectionGadgets/src/inspectionDescriptions/ComparisonOfShortAndChar.html new file mode 100644 index 000000000000..78bdd46c89bd --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/ComparisonOfShortAndChar.html @@ -0,0 +1,9 @@ + +
+ +This inspection reports any instances of equality comparisons between +short and char values. +Such comparisons may cause subtle bugs, as short values are +signed and char values unsigned. +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/ConditionalExpression.html b/plugins/InspectionGadgets/src/inspectionDescriptions/ConditionalExpression.html new file mode 100644 index 000000000000..194d4f6c0406 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/ConditionalExpression.html @@ -0,0 +1,8 @@ + +
+ +This inspection reports any instances of the ternary condition operator. Some coding standards prohibit the use of +the condition operator, in favor of if-else statements. + +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/ConfusingElse.html b/plugins/InspectionGadgets/src/inspectionDescriptions/ConfusingElse.html new file mode 100644 index 000000000000..eaa648df9a8f --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/ConfusingElse.html @@ -0,0 +1,11 @@ + +
+ +This inspection reports any instances of confusing else branches. Confusing else +branches are branches of if statements whose if branch cannot complete normally and +which are followed by other statements. In these cases, the statements following the +if statement may be moved into the else branch, for increased clarity. + + +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/ConfusingFloatingPointLiteral.html b/plugins/InspectionGadgets/src/inspectionDescriptions/ConfusingFloatingPointLiteral.html new file mode 100644 index 000000000000..33dcbcec3ad7 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/ConfusingFloatingPointLiteral.html @@ -0,0 +1,7 @@ + +
+ +This inspection reports any floating point numbers which do not have a decimal point, numbers before the decimal point, +and numbers after the decimal point. Such literals may be confusing, and violate several coding standards. +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/ConfusingMainMethod.html b/plugins/InspectionGadgets/src/inspectionDescriptions/ConfusingMainMethod.html new file mode 100644 index 000000000000..3756c3cb2894 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/ConfusingMainMethod.html @@ -0,0 +1,9 @@ + +
+ +This inspection reports any instances of methods named "main" which do not have signature +public static void main(String[]). Such methods may be confusing, as methods named "main" +are expected to be application entry points. + +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/ConfusingOctalEscape.html b/plugins/InspectionGadgets/src/inspectionDescriptions/ConfusingOctalEscape.html new file mode 100644 index 000000000000..0e69534335e6 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/ConfusingOctalEscape.html @@ -0,0 +1,7 @@ + +
+ +This inspection reports any string literals which contain an octal escape sequence immediately followed by +a digit. Such strings may be confusing, and are often the result of errors in escape code creation. +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/ConstantDeclaredInAbstractClass.html b/plugins/InspectionGadgets/src/inspectionDescriptions/ConstantDeclaredInAbstractClass.html new file mode 100644 index 000000000000..6dea457e9b86 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/ConstantDeclaredInAbstractClass.html @@ -0,0 +1,8 @@ + +
+ +This inspection reports on any constants (i.e. public static final fields) declared in abstract classes. Some coding +standards require that constants be declared in interfaces instead. + +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/ConstantDeclaredInInterface.html b/plugins/InspectionGadgets/src/inspectionDescriptions/ConstantDeclaredInInterface.html new file mode 100644 index 000000000000..0daa1743e280 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/ConstantDeclaredInInterface.html @@ -0,0 +1,8 @@ + +
+ +This inspection reports on any constants (i.e. public static final fields) declared in interfaces. Some coding +standards require that constants be declared in abstract classes instead. + +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/ConstantNamingConvention.html b/plugins/InspectionGadgets/src/inspectionDescriptions/ConstantNamingConvention.html new file mode 100644 index 000000000000..16ba202eea42 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/ConstantNamingConvention.html @@ -0,0 +1,11 @@ + +
+ +This inspection reports instances of constants whose names are either too short, too long, or do not follow +the specified regular expression pattern. Constants are variables of immutable type declared static final. +

+Use the fields provided below to specify mininum length, maximum length and regular expression expected for constant names. +(Regular expressions are in standard java.util.regex format.) + +

Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/ConstantOnLHSOfComparison.html b/plugins/InspectionGadgets/src/inspectionDescriptions/ConstantOnLHSOfComparison.html new file mode 100644 index 000000000000..dae8949619d8 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/ConstantOnLHSOfComparison.html @@ -0,0 +1,8 @@ + +
+ +This inspection reports on comparison operations with constant values on their left-hand side. Some coding conventions +specify that constants should be on the right-hand side of comparisons. + +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/ConstantOnRHSOfComparison.html b/plugins/InspectionGadgets/src/inspectionDescriptions/ConstantOnRHSOfComparison.html new file mode 100644 index 000000000000..5a5ad40e387b --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/ConstantOnRHSOfComparison.html @@ -0,0 +1,8 @@ + +
+ +This inspection reports on comparison operations with constant values on their right-hand side. Some coding conventions +specify that constants should be on the left-hand side of comparisons. + +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/ConstructorCount.html b/plugins/InspectionGadgets/src/inspectionDescriptions/ConstructorCount.html new file mode 100644 index 000000000000..bed65a16bacf --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/ConstructorCount.html @@ -0,0 +1,9 @@ + +
+ +This inspection reports any instances of class with too many constructors. Classes with +too many constructors are prone to initialization errors, and may often be better modeled as +multiple subclasses. +

+Use the field provided below to specify the maximum acceptable number of constructors class might have.

Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/ContinueOrBreakFromFinallyBlock.html b/plugins/InspectionGadgets/src/inspectionDescriptions/ContinueOrBreakFromFinallyBlock.html new file mode 100644 index 000000000000..757dc630fe64 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/ContinueOrBreakFromFinallyBlock.html @@ -0,0 +1,10 @@ + +
+ +This inspection reports any instances of break or continue statements +inside of finally +blocks. While occasionally intended, such statements are very confusing, may mask exceptions thrown, and +tremendously complicate debugging. + +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/ContinueStatement.html b/plugins/InspectionGadgets/src/inspectionDescriptions/ContinueStatement.html new file mode 100644 index 000000000000..287798ae92a9 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/ContinueStatement.html @@ -0,0 +1,6 @@ + +
+This inspection reports any instances of continue statements. +continue statements complicate refactoring, and can be confusing. +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/ContinueStatementWithLabel.html b/plugins/InspectionGadgets/src/inspectionDescriptions/ContinueStatementWithLabel.html new file mode 100644 index 000000000000..58f42b2f0a1d --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/ContinueStatementWithLabel.html @@ -0,0 +1,6 @@ + +
+This inspection reports any instances of continue statements with labels. +Labeled continue statements complicate refactoring, and can be confusing. +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/CovariantCompareTo.html b/plugins/InspectionGadgets/src/inspectionDescriptions/CovariantCompareTo.html new file mode 100644 index 000000000000..78b29e1c9847 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/CovariantCompareTo.html @@ -0,0 +1,7 @@ + +
+This inspection reports any instances of a class having a compareTo() +method taking an argument other than java.lang.Object, if the class does not have a compareTo() method +which does take java.lang.Object as its argument. Normally, this is a mistake. +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/CovariantEquals.html b/plugins/InspectionGadgets/src/inspectionDescriptions/CovariantEquals.html new file mode 100644 index 000000000000..6ae17dbc4503 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/CovariantEquals.html @@ -0,0 +1,7 @@ + +
+This inspection reports any instances of a class having a equals() +method taking an argument other than java.lang.Object, if the class does not have a equals() method +which does take java.lang.Object as it's argument. Normally, this is a mistake. +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/CyclomaticComplexity.html b/plugins/InspectionGadgets/src/inspectionDescriptions/CyclomaticComplexity.html new file mode 100644 index 000000000000..9b48badf166a --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/CyclomaticComplexity.html @@ -0,0 +1,11 @@ + +
+ +This inspection reports any instances of methods that have too high a cyclomatic complexity. Cyclomatic +complexity is basically a measurement of the number of branching points in a method. Methods with too high +a cyclomatic complexity may be confusing and difficult to test. +

+Use the field provided below to specify the maximum acceptable cyclomatic complexity a method might have. + +

Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/DateToString.html b/plugins/InspectionGadgets/src/inspectionDescriptions/DateToString.html new file mode 100644 index 000000000000..c5aed69ddb35 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/DateToString.html @@ -0,0 +1,8 @@ + +
+ +This inspection reports any call of toString() on java.util.Date objects. 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/DeclareCollectionAsInterface.html b/plugins/InspectionGadgets/src/inspectionDescriptions/DeclareCollectionAsInterface.html new file mode 100644 index 000000000000..e31eb9913745 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/DeclareCollectionAsInterface.html @@ -0,0 +1,8 @@ + +
+ +This inspection reports on declarations of Collection variables made by using the collection class as the type, +rather than an appropriate interface. + +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/DefaultNotLastCaseInSwitch.html b/plugins/InspectionGadgets/src/inspectionDescriptions/DefaultNotLastCaseInSwitch.html new file mode 100644 index 000000000000..1cef12285ae5 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/DefaultNotLastCaseInSwitch.html @@ -0,0 +1,6 @@ + +
+This inspection reports any instances of switch statements where the default case +comes before some other case. This construct is unnecessarily confusing. +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/DeserializableClassInSecureContext.html b/plugins/InspectionGadgets/src/inspectionDescriptions/DeserializableClassInSecureContext.html new file mode 100644 index 000000000000..2a8363465a18 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/DeserializableClassInSecureContext.html @@ -0,0 +1,10 @@ + +
+ +This inspection reports any instances of classes which may be deserialized. A class +may be deserialized if it supports the Serializable interface, +and its readObject() method is not defined to immediately +throw an error. Deserializable classes may be dangerous in code intended for secure use. + +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/DollarSignInName.html b/plugins/InspectionGadgets/src/inspectionDescriptions/DollarSignInName.html new file mode 100644 index 000000000000..9e53cf25c177 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/DollarSignInName.html @@ -0,0 +1,8 @@ + +
+ +This inspection reports any instances of identifers containing dollar signs ('$'). While +such identifiers are legal Java, their use outside of generated java code is strongly discouraged. + +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/DoubleCheckedLocking.html b/plugins/InspectionGadgets/src/inspectionDescriptions/DoubleCheckedLocking.html new file mode 100644 index 000000000000..f2c429fd15d5 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/DoubleCheckedLocking.html @@ -0,0 +1,11 @@ + +
+ +This inspection reports any instances of the double-checked locking construct. For a +discussion of double-checked locking and why it is unsafe, see +http://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html + + +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/EmptyCatchBlock.html b/plugins/InspectionGadgets/src/inspectionDescriptions/EmptyCatchBlock.html new file mode 100644 index 000000000000..6253ce60b219 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/EmptyCatchBlock.html @@ -0,0 +1,11 @@ + +
+ +This inspection reports instances of empty catch blocks. While occasionally intended, this +empty catch blocks can make debugging extremely difficult. +

+Use the controls below to indicate whether catch blocks containing only comments should be reported, +and whether empty catch blocks in JUnit tests should be reported. + +

Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/EmptyClass.html b/plugins/InspectionGadgets/src/inspectionDescriptions/EmptyClass.html new file mode 100644 index 000000000000..2cac8a242f5d --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/EmptyClass.html @@ -0,0 +1,9 @@ + +
+ +This inspection reports any empty classes. A class is empty if it +doesn't have any fields, methods or constructors. Empty classes are often left over +after large changes or refactorings. + +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/EmptyFinallyBlock.html b/plugins/InspectionGadgets/src/inspectionDescriptions/EmptyFinallyBlock.html new file mode 100644 index 000000000000..435d40756eb0 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/EmptyFinallyBlock.html @@ -0,0 +1,8 @@ + +
+ +This inspection reports instances of empty finally blocks. Empty finally blocks +usually indicate coding errors. + +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/EmptyInitializer.html b/plugins/InspectionGadgets/src/inspectionDescriptions/EmptyInitializer.html new file mode 100644 index 000000000000..e1840db9e7e9 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/EmptyInitializer.html @@ -0,0 +1,7 @@ + +
+ +This inspection reports instances of empty class initializer blocks. + +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/EmptyStatementBody.html b/plugins/InspectionGadgets/src/inspectionDescriptions/EmptyStatementBody.html new file mode 100644 index 000000000000..a98a4c0f72db --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/EmptyStatementBody.html @@ -0,0 +1,11 @@ + +
+This inspection reports any instances of if, +while, do or for statements +having empty bodies. While occasionally intended, this construction is confusing, and often the result of a typo. +

+Use the checkbox below to indicate whether this inspection should report statements whose body is an +empty code block, rather than just empty statements. + +

Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/EmptySynchronizedStatement.html b/plugins/InspectionGadgets/src/inspectionDescriptions/EmptySynchronizedStatement.html new file mode 100644 index 000000000000..d7eff13e86ec --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/EmptySynchronizedStatement.html @@ -0,0 +1,7 @@ + +
+This inspection reports any instances of synchronized statements +having empty bodies. While theoretically this may be the semantics intended, this construction is +confusing, and often the result of a typo. +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/EmptyTryBlock.html b/plugins/InspectionGadgets/src/inspectionDescriptions/EmptyTryBlock.html new file mode 100644 index 000000000000..14881d4e4260 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/EmptyTryBlock.html @@ -0,0 +1,7 @@ + +
+ +This inspection reports any instances of empty try blocks. + +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/EnumAsName.html b/plugins/InspectionGadgets/src/inspectionDescriptions/EnumAsName.html new file mode 100644 index 000000000000..7f195b09f0f7 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/EnumAsName.html @@ -0,0 +1,8 @@ + +
+ +This inspection reports any instances of variables, methods, or classes named +enum. Such names are legal under Java 1.4 or +earlier JVMs, but will cause problems under Java 5.0 or later. +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/EnumClass.html b/plugins/InspectionGadgets/src/inspectionDescriptions/EnumClass.html new file mode 100644 index 000000000000..37023214143c --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/EnumClass.html @@ -0,0 +1,7 @@ + +
+ +This inspection reports any instances of enum classes. +Such statements are not supported under Java 1.4 or earlier JVMs. +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/EqualsBetweenInconvertibleTypes.html b/plugins/InspectionGadgets/src/inspectionDescriptions/EqualsBetweenInconvertibleTypes.html new file mode 100644 index 000000000000..46e333f75234 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/EqualsBetweenInconvertibleTypes.html @@ -0,0 +1,9 @@ + +
+ +This inspection reports instances of calls to .equals() where the target and argument are +of incompatible types. While such a call might theoretically be useful, most likely it represents +a bug. + +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/EqualsUsesNonFinalVariable.html b/plugins/InspectionGadgets/src/inspectionDescriptions/EqualsUsesNonFinalVariable.html new file mode 100644 index 000000000000..b82437476dc2 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/EqualsUsesNonFinalVariable.html @@ -0,0 +1,9 @@ + +
+ +This inspection reports any implementations of equals() which access +non-final variables. Such access may result in equals() +returning different results at different points in an object's lifecycle, which may in turn cause problems when +using the standard Collections classes. +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/ErrorRethrown.html b/plugins/InspectionGadgets/src/inspectionDescriptions/ErrorRethrown.html new file mode 100644 index 000000000000..26da973ef919 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/ErrorRethrown.html @@ -0,0 +1,8 @@ + +
+This inspection reports any instances of try statements which catch +java.lang.Error or any subclass and which do not rethrow the error. +Statements which catch java.lang.ThreadDeath are not +reported by this inspection. +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/ExceptionFromCatchWhichDoesntWrap.html b/plugins/InspectionGadgets/src/inspectionDescriptions/ExceptionFromCatchWhichDoesntWrap.html new file mode 100644 index 000000000000..37edbb36f2ec --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/ExceptionFromCatchWhichDoesntWrap.html @@ -0,0 +1,11 @@ + +
+ +This inspection reports on instances of exceptions constructed and thrown +from inside catch blocks, which do not "wrap" the caught +exception. It is considered good practice when throwing an exception in response to an exception +to wrap the initial exception, so that valuable context information +such as stack frames and line numbers are not lost. + +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/ExceptionNameDoesntEndWithException.html b/plugins/InspectionGadgets/src/inspectionDescriptions/ExceptionNameDoesntEndWithException.html new file mode 100644 index 000000000000..5f9a8980ca07 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/ExceptionNameDoesntEndWithException.html @@ -0,0 +1,7 @@ + +
+ +This inspection reports any instances of exception classes whose names don't end with 'Exception'. + +
Powered by InspectionGadgets
+ diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/ExtendsObject.html b/plugins/InspectionGadgets/src/inspectionDescriptions/ExtendsObject.html new file mode 100644 index 000000000000..c6b068169d34 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/ExtendsObject.html @@ -0,0 +1,7 @@ + +
+ +This inspection reports any classes explicitly declared to extend java.lang.Object. + +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/ExternalizableWithSerializationMethods.html b/plugins/InspectionGadgets/src/inspectionDescriptions/ExternalizableWithSerializationMethods.html new file mode 100644 index 000000000000..56896bb363d3 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/ExternalizableWithSerializationMethods.html @@ -0,0 +1,9 @@ + +
+ +This inspection reports on instances of Externalizable classes which define readObject() +or writeObject() methods. These methods are not called for serialization of +Externalizable objects. + +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/FallthruInSwitchStatement.html b/plugins/InspectionGadgets/src/inspectionDescriptions/FallthruInSwitchStatement.html new file mode 100644 index 000000000000..1e3286641236 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/FallthruInSwitchStatement.html @@ -0,0 +1,11 @@ + +
+ +This inspection reports any instances of 'fallthrough' in a switch statement. +'Fallthrough' is defined to occur when a series of executable statements after a switch label is not guaranteed. +to transfer control before the next switch label. In that case, control 'falls through' to the statements after +that switch label, even though the switch expression does not equal the value of the fallen-through label. +While occasionally intended, this construction is confusing, and often the result of a typo. + +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/FeatureEnvy.html b/plugins/InspectionGadgets/src/inspectionDescriptions/FeatureEnvy.html new file mode 100644 index 000000000000..d7a67cb4d5cd --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/FeatureEnvy.html @@ -0,0 +1,12 @@ + +
+ +This inspection reports instances of the "Feature Envy" code smell. Feature +envy is defined as occuring when a method calls methods on another class three +or more times. Calls to library classes, parent classes, contained or containing +classes are not counted for purposes of this inspection. Feature +envy is often an indication that functionality is in the wrong class, and may +profitably be moved. + +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/FieldAccessedSynchronizedAndUnsynchronized.html b/plugins/InspectionGadgets/src/inspectionDescriptions/FieldAccessedSynchronizedAndUnsynchronized.html new file mode 100644 index 000000000000..a88c135e0e71 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/FieldAccessedSynchronizedAndUnsynchronized.html @@ -0,0 +1,9 @@ + +
+ +This inspection reports any instances of non-final fields which are accessed in both synchronized and unsynchronized contexts. +Accesses in constructors an initializers are ignored for purposes of this inspection. Such "partially synchronized" access +is often the result of a coding oversight, and may result in unexpectedly inconsistent data structures. + +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/FieldCount.html b/plugins/InspectionGadgets/src/inspectionDescriptions/FieldCount.html new file mode 100644 index 000000000000..14d407fbd825 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/FieldCount.html @@ -0,0 +1,10 @@ + +
+ +This inspection reports any instances of class with too many fields. Classes with +a large number of fields are often trying to 'do too much', and may need to be +refactored into multiple smaller classes. +

+Use the controls provided below to specify the maximum acceptable number of fields class might have, and +to indicate whether constant fields count toward this number.

Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/FieldHidesSuperclassField.html b/plugins/InspectionGadgets/src/inspectionDescriptions/FieldHidesSuperclassField.html new file mode 100644 index 000000000000..2d1ae8ded8e5 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/FieldHidesSuperclassField.html @@ -0,0 +1,8 @@ + +
+ +This inspection reports any instances of fields with the same name as a field in an ancestor class. Such field +names may be confusing, and can be bug-prone. + +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/FieldMayBeStatic.html b/plugins/InspectionGadgets/src/inspectionDescriptions/FieldMayBeStatic.html new file mode 100644 index 000000000000..56f26c00fedf --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/FieldMayBeStatic.html @@ -0,0 +1,7 @@ + +
+ +This inspection reports any instance variables which may safely be made static. A field +may be static if it is declared final, and is initialized with a constant. +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/FieldRepeatedlyAccessed.html b/plugins/InspectionGadgets/src/inspectionDescriptions/FieldRepeatedlyAccessed.html new file mode 100644 index 000000000000..52ceb3320805 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/FieldRepeatedlyAccessed.html @@ -0,0 +1,12 @@ + +
+ +This inspection reports any instances of fields which are accessed three or more times by a given method, +or which are accessed in a loop. While such field access may be logically correct, it is often more performant +to replace such accesses with local variables, copying the fields to a temporary local and copying back if necessary. +

+Use the checkbox below to ignore instances of final fields being repeatedly accessed, as many compilers and JVMs +can optimize that case without explicit creation of a temporary local variable. + +

Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/FinalClass.html b/plugins/InspectionGadgets/src/inspectionDescriptions/FinalClass.html new file mode 100644 index 000000000000..a3bbbef6dad3 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/FinalClass.html @@ -0,0 +1,8 @@ + +
+ +This inspection reports any instances of classes being declared final. Some coding +standards discourage final classes. + +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/FinalMethod.html b/plugins/InspectionGadgets/src/inspectionDescriptions/FinalMethod.html new file mode 100644 index 000000000000..1c69f3df34d1 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/FinalMethod.html @@ -0,0 +1,8 @@ + +
+ +This inspection reports any instances of methods being declared final. Some coding +standards discourage final methods + +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/FinalMethodInFinalClass.html b/plugins/InspectionGadgets/src/inspectionDescriptions/FinalMethodInFinalClass.html new file mode 100644 index 000000000000..1bd658b71f49 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/FinalMethodInFinalClass.html @@ -0,0 +1,8 @@ + +
+ +This inspection reports any instances of methods being declared final in +classes that are declared final. This is unnecessary, and may be confusing. + +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/FinalPrivateMethod.html b/plugins/InspectionGadgets/src/inspectionDescriptions/FinalPrivateMethod.html new file mode 100644 index 000000000000..0227234a48b8 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/FinalPrivateMethod.html @@ -0,0 +1,8 @@ + +
+This inspection reports any instances of methods +declared final and private. +As private methods cannot be meaningfully overriden, declaring them +final is redundant. +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/FinalStaticMethod.html b/plugins/InspectionGadgets/src/inspectionDescriptions/FinalStaticMethod.html new file mode 100644 index 000000000000..14af520a4372 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/FinalStaticMethod.html @@ -0,0 +1,8 @@ + +
+This inspection reports any instances of methods +declared final and static. +As static methods cannot be meaningfully overriden, declaring them +final is redundant. +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/Finalize.html b/plugins/InspectionGadgets/src/inspectionDescriptions/Finalize.html new file mode 100644 index 000000000000..f2e18915b5ba --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/Finalize.html @@ -0,0 +1,8 @@ + +
+This inspection reports any implementations of +a finalize() method. Due to inability to +gaurantee that finalize() will ever be called, +some coding standards prohibit it's use. +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/FinalizeCallsSuperFinalize.html b/plugins/InspectionGadgets/src/inspectionDescriptions/FinalizeCallsSuperFinalize.html new file mode 100644 index 000000000000..6ee62d533f58 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/FinalizeCallsSuperFinalize.html @@ -0,0 +1,7 @@ + +
+This inspection reports any implementations of the Object.finalize() method +which do not call super.finalize(). Failing to call super.finalize() may result in objects failing to properly +free any resources held or do other cleanup activities. +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/FinalizeNotProtected.html b/plugins/InspectionGadgets/src/inspectionDescriptions/FinalizeNotProtected.html new file mode 100644 index 000000000000..2d1b63214745 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/FinalizeNotProtected.html @@ -0,0 +1,7 @@ + +
+This inspection reports any implementations of the Object.finalize() method +which are not declared protected. finalize() should be declare protected, +to prevent it from being explicitly invoked by other classes. +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/FloatingPointEquality.html b/plugins/InspectionGadgets/src/inspectionDescriptions/FloatingPointEquality.html new file mode 100644 index 000000000000..3bbb560e1268 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/FloatingPointEquality.html @@ -0,0 +1,8 @@ + +
+This inspection reports any instances of floating-point values +being compared with == or !=. + Floating point values are inherently inaccurate, and comparing them +for exact equality is almost never the desired semantics. +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/ForCanBeForeach.html b/plugins/InspectionGadgets/src/inspectionDescriptions/ForCanBeForeach.html new file mode 100644 index 000000000000..8bc188cb2f5b --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/ForCanBeForeach.html @@ -0,0 +1,9 @@ + +
+ +This inspection reports any instances of for loops which iterator +over collections or arrays, and can be replaced with the J2SDK 5.0 "for each" iteration syntax. +

+For safety, this inspection is disabled unless the project uses J2SDK 5.0. +

Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/ForLoopReplaceableByWhile.html b/plugins/InspectionGadgets/src/inspectionDescriptions/ForLoopReplaceableByWhile.html new file mode 100644 index 000000000000..3280af86d391 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/ForLoopReplaceableByWhile.html @@ -0,0 +1,9 @@ + +
+ +This inspection reports any instances of for loops +which contain neither initialization or update components, and can thus be replaced by +simpler while statements. + +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/ForLoopThatDoesntUseLoopVariable.html b/plugins/InspectionGadgets/src/inspectionDescriptions/ForLoopThatDoesntUseLoopVariable.html new file mode 100644 index 000000000000..458bd4f571a7 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/ForLoopThatDoesntUseLoopVariable.html @@ -0,0 +1,8 @@ + +
+ +This inspection reports any instances of for loops where the condition or +update does not use the for loop variable. + +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/ForLoopWithMissingComponent.html b/plugins/InspectionGadgets/src/inspectionDescriptions/ForLoopWithMissingComponent.html new file mode 100644 index 000000000000..51ed49515cb7 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/ForLoopWithMissingComponent.html @@ -0,0 +1,8 @@ + +
+ +This inspection reports any instances for loops that lack initialization, condition, or update clauses. +Some coding styles prohibit such loops. + +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/ForeachStatement.html b/plugins/InspectionGadgets/src/inspectionDescriptions/ForeachStatement.html new file mode 100644 index 000000000000..063593131f19 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/ForeachStatement.html @@ -0,0 +1,7 @@ + +
+ +This inspection reports any instances of the Java 5.0 for statement syntax. +Such for statements are not supported under Java 1.4 or earlier JVMs. +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/HardcodedFileSeparators.html b/plugins/InspectionGadgets/src/inspectionDescriptions/HardcodedFileSeparators.html new file mode 100644 index 000000000000..e516d8ccaf52 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/HardcodedFileSeparators.html @@ -0,0 +1,8 @@ + +
+This inspection reports any instances of the forward (/) or backward (\) slash in a string or +character literal. These characters are commonly used as file separators, and portability may suffer if their use is hardcoded. +This will not report instances of the forward slash immediately following a '<' character, +or immediately preceeding a '>' character, as those often indicate XML or HTML tags, rather than file names. +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/HardcodedLineSeparators.html b/plugins/InspectionGadgets/src/inspectionDescriptions/HardcodedLineSeparators.html new file mode 100644 index 000000000000..72afa1824d05 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/HardcodedLineSeparators.html @@ -0,0 +1,6 @@ + +
+This inspection reports any instances of the newline (\n) or return (\r) characters in a string or +character literal. These characters are commonly used as line separators, and portability may suffer they are hardcoded. +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/HashCodeUsesNonFinalVariable.html b/plugins/InspectionGadgets/src/inspectionDescriptions/HashCodeUsesNonFinalVariable.html new file mode 100644 index 000000000000..e642d6a3b7c9 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/HashCodeUsesNonFinalVariable.html @@ -0,0 +1,9 @@ + +
+ +This inspection reports any implementations of hashcode() which access +non-final variables. Such access may result in hashcode() +returning different values at different points in an object's lifecycle, which may in turn cause problems when +using the standard Collections classes. +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/IfStatementWithTooManyBranches.html b/plugins/InspectionGadgets/src/inspectionDescriptions/IfStatementWithTooManyBranches.html new file mode 100644 index 000000000000..c3508474ee23 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/IfStatementWithTooManyBranches.html @@ -0,0 +1,11 @@ + +
+ +This inspection reports instances of if statements with too many branches. +Such statements may be confusing, and are often the sign of inadequate levels of design +abstraction. +

+Use the field provided below to specify the maximum number of branches expected. + +

Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/IgnoreResultOfCall.html b/plugins/InspectionGadgets/src/inspectionDescriptions/IgnoreResultOfCall.html new file mode 100644 index 000000000000..1ed3b0a24306 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/IgnoreResultOfCall.html @@ -0,0 +1,17 @@ + +
+This inspection reports any instances of calls to a specified list of +methods where the result of that call is ignored. For many method, ignoring the result is perfectly +legitimate, but for some method it is almost certainly an error. Examples of methods where ignoring +the result ofa call is likely to be an error inclued java.io.inputStream.read(), +which returns the number of bytes actually read, any method on +java.lang.String or java.math.BigInteger, +as all of those methods are side-effect free and thus pointless if ignored + +

+Use the panel below to enter the class names and method names of the methods you wish to check for +ignored returns. Class names must be specified as a simple string, while method names may be +specified using a standard Java regular expression. Specifying a class names implicitly specifies +that class and all of it's subclasses. +

Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/ImplicitCallToSuper.html b/plugins/InspectionGadgets/src/inspectionDescriptions/ImplicitCallToSuper.html new file mode 100644 index 000000000000..34b94c3fb7e1 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/ImplicitCallToSuper.html @@ -0,0 +1,10 @@ + +
+ +This inspection reports any instances of constructors which do not begin with calls to "super" constructor, or +other constructors of the same class. Such constructors can be thought of as implicitly beginning with a +call to super(). Some coding standards prefer that such calls to +super() be made explicitly. + +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/ImplicitNumericConversion.html b/plugins/InspectionGadgets/src/inspectionDescriptions/ImplicitNumericConversion.html new file mode 100644 index 000000000000..1c70019d4e77 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/ImplicitNumericConversion.html @@ -0,0 +1,9 @@ + +
+ +This inspection reports any instances of implicit conversion between numeric types. +Implicit numeric conversion is not a problem in itself, but if unexpected may be a source +of difficult to trace bugs. + +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/IncompatibleMask.html b/plugins/InspectionGadgets/src/inspectionDescriptions/IncompatibleMask.html new file mode 100644 index 000000000000..72a01b866331 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/IncompatibleMask.html @@ -0,0 +1,9 @@ + +
+ +This inspection reports any instances of bitwise mask expressions which are gauranteed to +evaluate to true or false. Expressions checked are of the form "var & constant1 == constant2" or +"var | constant1 == constant2", where constant1 and constant2 are incompatible bitmask constants. + +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/IncrementDecrementUsedAsExpression.html b/plugins/InspectionGadgets/src/inspectionDescriptions/IncrementDecrementUsedAsExpression.html new file mode 100644 index 000000000000..f51c4d0cf9bc --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/IncrementDecrementUsedAsExpression.html @@ -0,0 +1,9 @@ + +
+ +This inspection reports any instances of increment or decrement expressions nested inside other expressions. +While admirably terse, such expressions may be confusing, and violate the general design principle that a +given construct should do precisely one thing. + +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/InfiniteLoopStatement.html b/plugins/InspectionGadgets/src/inspectionDescriptions/InfiniteLoopStatement.html new file mode 100644 index 000000000000..9cf867021caf --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/InfiniteLoopStatement.html @@ -0,0 +1,10 @@ + +
+ +This inspection reports any instances of for, while, + or do statements which +can only exit by throwing an exception. While such statements may be correct, they +are often a symptom of coding errors. + +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/InfiniteRecursion.html b/plugins/InspectionGadgets/src/inspectionDescriptions/InfiniteRecursion.html new file mode 100644 index 000000000000..ccb4e56d5e37 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/InfiniteRecursion.html @@ -0,0 +1,9 @@ + +
+ +This inspection reports any instances of methods which must either recurse +infinitely or throw an exception. Methods reported by this inspection can not +return normally. + +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/InnerClassMayBeStatic.html b/plugins/InspectionGadgets/src/inspectionDescriptions/InnerClassMayBeStatic.html new file mode 100644 index 000000000000..0dd993288896 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/InnerClassMayBeStatic.html @@ -0,0 +1,9 @@ + +
+ +This inspection reports any inner classes which may safely be made +static. An inner class may be static if it doesn't reference +it's enclosing class instance. A static inner class uses slightly less memory. +
Powered by InspectionGadgets
+ + \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/InnerClassOnInterface.html b/plugins/InspectionGadgets/src/inspectionDescriptions/InnerClassOnInterface.html new file mode 100644 index 000000000000..afea7573b846 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/InnerClassOnInterface.html @@ -0,0 +1,7 @@ + +
+This inspection reports any instances of inner classes +of interface classes. Some coding standards +discourage such classes. +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/InnerClassVariableHidesOuterClassVariable.html b/plugins/InspectionGadgets/src/inspectionDescriptions/InnerClassVariableHidesOuterClassVariable.html new file mode 100644 index 000000000000..440fc63adc0e --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/InnerClassVariableHidesOuterClassVariable.html @@ -0,0 +1,8 @@ + +
+ +This inspection reports any instances of inner class variables being named identically to member variables of a containing class. +Such a variable name may be confusing. + +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/InstanceMethodNamingConvention.html b/plugins/InspectionGadgets/src/inspectionDescriptions/InstanceMethodNamingConvention.html new file mode 100644 index 000000000000..74ced86b7f1a --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/InstanceMethodNamingConvention.html @@ -0,0 +1,12 @@ + +
+ +This inspection reports instances of instance methods whose names are either too short, too long, or do not follow +the specified regular expression pattern. Instance methods that override library +methods are ignored for purposes of this inspection. +

+Use the fields provided below to specify mininum length, maximum length and regular expression expected for instance method names. +(Regular expressions are in standard java.util.regex format.) + +

Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/InstanceVariableInitialization.html b/plugins/InspectionGadgets/src/inspectionDescriptions/InstanceVariableInitialization.html new file mode 100644 index 000000000000..1788e8874cc7 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/InstanceVariableInitialization.html @@ -0,0 +1,12 @@ + +
+ +This inspection reports instances of instance variables which are not guaranteed to be initialized upon object initialization. +

+Use the checkbox below to indicate whether you want uninitialized primitive fields to be reported. +

+Note: This inspection uses a very conservative dataflow algorithm, and may report instance variables +as uninitialized incorrectly. Variables reported as initialized will always be initialized. + +

Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/InstanceVariableNamingConvention.html b/plugins/InspectionGadgets/src/inspectionDescriptions/InstanceVariableNamingConvention.html new file mode 100644 index 000000000000..19552604f180 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/InstanceVariableNamingConvention.html @@ -0,0 +1,12 @@ + +
+ +This inspection reports instances of instance variables whose names are either too short, too long, or do not follow +the specified regular expression pattern. +

+Use the fields provided below to specify mininum length, maximum length and regular expression expected for +instance variable names. +(Regular expressions are in standard java.util.regex format.) + +

Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/InstanceVariableOfConcreteClass.html b/plugins/InspectionGadgets/src/inspectionDescriptions/InstanceVariableOfConcreteClass.html new file mode 100644 index 000000000000..8c80b1d5491a --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/InstanceVariableOfConcreteClass.html @@ -0,0 +1,8 @@ + +
+ +This inspection reports any instance variables whose type is declared to be a concrete class, rather than an interface. +Such declarations may represent a failure of abstraction, and may make testing more difficult. +Declarations whose classes come from system or third-party libraries will not be reported by this inspection. +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/InstanceVariableUninitializedUse.html b/plugins/InspectionGadgets/src/inspectionDescriptions/InstanceVariableUninitializedUse.html new file mode 100644 index 000000000000..6b26f00f206a --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/InstanceVariableUninitializedUse.html @@ -0,0 +1,12 @@ + +
+ +This inspection reports reads of instance variables which are not yet initialized. +

+Use the checkbox below to indicate whether you want uninitialized primitive fields to be reported. +

+Note: This inspection uses a very conservative dataflow algorithm, and may report instance variables +as uninitialized incorrectly. Variables reported as initialized will always be initialized. + +

Powered by InspectionGadgets
+ diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/InstanceofCatchParameter.html b/plugins/InspectionGadgets/src/inspectionDescriptions/InstanceofCatchParameter.html new file mode 100644 index 000000000000..73910efbef18 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/InstanceofCatchParameter.html @@ -0,0 +1,9 @@ + +
+ +This inspection reports any instanceof expressions on catch block parameters. +Testing the type of catch parameters is usually better done by having separate +catch blocks, rather than instanceof. + +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/InstanceofInterfaces.html b/plugins/InspectionGadgets/src/inspectionDescriptions/InstanceofInterfaces.html new file mode 100644 index 000000000000..f879448ac1c7 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/InstanceofInterfaces.html @@ -0,0 +1,9 @@ + +
+ +This inspection reports on uses of instanceof where the type checked for is a concrete class, +rather than an interface. Such uses often indicate excessive coupling to concrete implementations, rather +than abstractions. instanceof expressions whose classes come from system or third-party libraries will not be reported by this inspection. + +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/InstanceofThis.html b/plugins/InspectionGadgets/src/inspectionDescriptions/InstanceofThis.html new file mode 100644 index 000000000000..a38a7cce681a --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/InstanceofThis.html @@ -0,0 +1,10 @@ + +
+ +This inspection reports on uses of instanceof where the +expression checked is this. Such expressions +are indicative of a failure of object-oriented design, and should be replaced by +polymorphic constructions. + +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/IntegerDivisionInFloatingPointContext.html b/plugins/InspectionGadgets/src/inspectionDescriptions/IntegerDivisionInFloatingPointContext.html new file mode 100644 index 000000000000..2f4aa082c1f8 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/IntegerDivisionInFloatingPointContext.html @@ -0,0 +1,9 @@ + +
+ +This inspection reports any instances of integer division where the +result is either directly or indirectly used as a floating point number. +Such division is often an error, and may result in unexpected results +due to truncation in integer division. +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/InterfaceNamingConvention.html b/plugins/InspectionGadgets/src/inspectionDescriptions/InterfaceNamingConvention.html new file mode 100644 index 000000000000..5b03cb568b32 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/InterfaceNamingConvention.html @@ -0,0 +1,11 @@ + +
+ +This inspection reports instances of interfaces whose names are either too short, too long, or do not follow +the specified regular expression pattern. +

+Use the fields provided below to specify mininum length, maximum length and regular expression expected for interface names. +(Regular expressions are in standard java.util.regex format.) + +

Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/JavaLangImport.html b/plugins/InspectionGadgets/src/inspectionDescriptions/JavaLangImport.html new file mode 100644 index 000000000000..4eb5d56769e9 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/JavaLangImport.html @@ -0,0 +1,10 @@ + +
+ +This inspection reports any import statements which refer to the java.lang package. +Such import statements are unnecessary. Since IDEA can automatically +detect and fix such statements with it's "Optimize Imports" command, this inspection is mostly useful +for off-line reporting on code bases that you don't intend to change. + +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/JavaLangReflect.html b/plugins/InspectionGadgets/src/inspectionDescriptions/JavaLangReflect.html new file mode 100644 index 000000000000..4fcab9ea26eb --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/JavaLangReflect.html @@ -0,0 +1,9 @@ + +
+ +This inspection reports any uses of classes in the java.lang.reflect package. While powerful, +reflection in Java is often slow, and may possibly be unsafe is it prevents compile-time type and +exception checking. + +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/LengthOneStringsInConcatenation.html b/plugins/InspectionGadgets/src/inspectionDescriptions/LengthOneStringsInConcatenation.html new file mode 100644 index 000000000000..4fbdf1b648a9 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/LengthOneStringsInConcatenation.html @@ -0,0 +1,8 @@ + +
+ +This inspection reports any instances of String literals of length one being used in concatenation. +These literals may be replaced by equivalent character literals, gaining some performance enhancement. + +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/LimitedScopeInnerClass.html b/plugins/InspectionGadgets/src/inspectionDescriptions/LimitedScopeInnerClass.html new file mode 100644 index 000000000000..ed0aa38ea8ff --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/LimitedScopeInnerClass.html @@ -0,0 +1,9 @@ + +
+ +This inspection reports any limited-scope inner classes. Some code standards discourage +the use of limited-scope inner classes, and they are unusual enough as to possibly be +confusing. + +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/LiteralAsArgToStringEquals.html b/plugins/InspectionGadgets/src/inspectionDescriptions/LiteralAsArgToStringEquals.html new file mode 100644 index 000000000000..11a97dd552d9 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/LiteralAsArgToStringEquals.html @@ -0,0 +1,9 @@ + +
+ +This inspection reports any instances of calls to .equals() whose arguments are String literals. Some coding +standards specify that String literals should be the target of .equals(), rather than +argument, thus minimizing NullPointerExceptions. + +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/LocalVariableHidingMemberVariable.html b/plugins/InspectionGadgets/src/inspectionDescriptions/LocalVariableHidingMemberVariable.html new file mode 100644 index 000000000000..9017c35221da --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/LocalVariableHidingMemberVariable.html @@ -0,0 +1,8 @@ + +
+ +This inspection reports any instances of local variables being named identically to visible member variables of their +class. Such a variable name may be confusing. + +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/LocalVariableNamingConvention.html b/plugins/InspectionGadgets/src/inspectionDescriptions/LocalVariableNamingConvention.html new file mode 100644 index 000000000000..c72d074d7015 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/LocalVariableNamingConvention.html @@ -0,0 +1,11 @@ + +
+ +This inspection reports instances of local variables whose names are either too short, too long, or do not follow +the specified regular expression pattern. +

+Use the fields provided below to specify mininum length, maximum length and regular expression expected for local variables names. +(Regular expressions are in standard java.util.regex format.) + +

Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/LocalVariableOfConcreteClass.html b/plugins/InspectionGadgets/src/inspectionDescriptions/LocalVariableOfConcreteClass.html new file mode 100644 index 000000000000..897c09981e5c --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/LocalVariableOfConcreteClass.html @@ -0,0 +1,9 @@ + +
+ +This inspection reports any local variables whose type is declared to be a concrete class. +Such declarations may represent a failure of abstraction, and may make testing more difficult. +Declarations whose classes come from system or third-party libraries will not be reported by this inspection. +Catch-block parameters of concrete exception type will also not be reported by this inspection. +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/LongLiteralsEndingWithLowercaseL.html b/plugins/InspectionGadgets/src/inspectionDescriptions/LongLiteralsEndingWithLowercaseL.html new file mode 100644 index 000000000000..9d9a5570de1f --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/LongLiteralsEndingWithLowercaseL.html @@ -0,0 +1,6 @@ + +
+This inspection reports any instances of long literals ending with lowercase 'l'. These +literals may be confusing, as lowercase 'l' looks very similar to '1'. +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/LoopStatementsThatDontLoop.html b/plugins/InspectionGadgets/src/inspectionDescriptions/LoopStatementsThatDontLoop.html new file mode 100644 index 000000000000..47743e60ede9 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/LoopStatementsThatDontLoop.html @@ -0,0 +1,7 @@ + +
+This inspection reports any instance of for, +while and do statements whose +bodies are guaranteed to execute at most once. Normally, this is an indication of a bug. +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/MagicCharacter.html b/plugins/InspectionGadgets/src/inspectionDescriptions/MagicCharacter.html new file mode 100644 index 000000000000..f0c4fa323873 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/MagicCharacter.html @@ -0,0 +1,10 @@ + +
+ +This inspection reports all instances of "magic characters", character constants used without declaration. +"Magic character" can result in code whose intention is extremely unclear, and may result in errors if a "magic +character" is changed in one code location but not another. Such use may also complicates internationalization +efforts. + +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/MagicNumber.html b/plugins/InspectionGadgets/src/inspectionDescriptions/MagicNumber.html new file mode 100644 index 000000000000..774fc955dc01 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/MagicNumber.html @@ -0,0 +1,10 @@ + +
+ +This inspection reports all instances of "magic numbers", literal numeric constants used without declaration. +"Magic numbers" can result in code whose intention is extremely unclear, and may result in errors if a "magic +number" is changed in one code location but not another. The numbers 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 0L, 1L, +0.0, 1.0, 0.0F and 1.0F are not reported by this inspection. + +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/ManualArrayCopy.html b/plugins/InspectionGadgets/src/inspectionDescriptions/ManualArrayCopy.html new file mode 100644 index 000000000000..84ce5e0e2a06 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/ManualArrayCopy.html @@ -0,0 +1,9 @@ + +
+ +This inspection reports any instances of the manual copying of array contents which may be replaced by +calls to System.arraycopy(). This inspection may return false positives on complicated array +copying constructs, and so should be used with care. + +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/MarkerInterface.html b/plugins/InspectionGadgets/src/inspectionDescriptions/MarkerInterface.html new file mode 100644 index 000000000000..9e64a4e43ce6 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/MarkerInterface.html @@ -0,0 +1,10 @@ + +
+ +This inspection reports "marker" interfaces which have no methods or fields. +Such interfaces may be confusing, and normally indicate a design failure. +Interfaces which extend two or more other interfaces will not be reported by +this inspection. + +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/MethodCount.html b/plugins/InspectionGadgets/src/inspectionDescriptions/MethodCount.html new file mode 100644 index 000000000000..060101227a3e --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/MethodCount.html @@ -0,0 +1,10 @@ + +
+ +This inspection reports any instances of class with too many methods. Classes with +a large number of methods are often trying to 'do too much', and may need to be +refactored into multiple smaller classes. +

+Use the field provided below to specify the maximum acceptable number of methods +a class might have.

Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/MethodCoupling.html b/plugins/InspectionGadgets/src/inspectionDescriptions/MethodCoupling.html new file mode 100644 index 000000000000..d0648b1787f5 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/MethodCoupling.html @@ -0,0 +1,12 @@ + +
+ +This inspection reports any instances of methods which are highly coupled, i.e. that reference too many other classes. +Methods with too high a coupling can be very fragile, and should probably be broken up. References to system classes +(those in the java.or javax. packages), are not +counted for purposes of this inspection. +

+Use the field provided below to specify the maximum acceptable coupling a method might have. + +

Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/MethodMayBeStatic.html b/plugins/InspectionGadgets/src/inspectionDescriptions/MethodMayBeStatic.html new file mode 100644 index 000000000000..565286dcf829 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/MethodMayBeStatic.html @@ -0,0 +1,9 @@ + +
+ +This inspection reports any methods which may safely be made static. +A method may be static if it doesn't reference any of its class' non static methods and non static +fields and isn't overridden in a sub class. +
Powered by InspectionGadgets
+ + \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/MethodNameSameAsClassName.html b/plugins/InspectionGadgets/src/inspectionDescriptions/MethodNameSameAsClassName.html new file mode 100644 index 000000000000..f5e169d33789 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/MethodNameSameAsClassName.html @@ -0,0 +1,8 @@ + +
+ +This inspection reports any instances of methods being named identically to their class. +Such a method name may be confusing. + +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/MethodNameSameAsParentName.html b/plugins/InspectionGadgets/src/inspectionDescriptions/MethodNameSameAsParentName.html new file mode 100644 index 000000000000..0f8f908625c5 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/MethodNameSameAsParentName.html @@ -0,0 +1,8 @@ + +
+ +This inspection reports any instances of methods being named identically to the superclass of the method's class. +Such a method name may be confusing. + +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/MethodNamesDifferOnlyByCase.html b/plugins/InspectionGadgets/src/inspectionDescriptions/MethodNamesDifferOnlyByCase.html new file mode 100644 index 000000000000..6c3f9774d60c --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/MethodNamesDifferOnlyByCase.html @@ -0,0 +1,8 @@ + +
+ +This inspection reports on cases where multiple methods of a class have names which differ only by +case. Such method names may be very confusing. + +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/MethodOverloadsParentMethod.html b/plugins/InspectionGadgets/src/inspectionDescriptions/MethodOverloadsParentMethod.html new file mode 100644 index 000000000000..40bbcc8ad15e --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/MethodOverloadsParentMethod.html @@ -0,0 +1,9 @@ + +
+ +This inspection reports instance methods having the same name and different but compatible arguments as +a method in a superclass. In this case, the child method overloads the parent method, instead of overriding it. +While that may be intended, if unintended it may result in latent bugs. + +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/MethodOverridesPrivateMethod.html b/plugins/InspectionGadgets/src/inspectionDescriptions/MethodOverridesPrivateMethod.html new file mode 100644 index 000000000000..5946095f8c82 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/MethodOverridesPrivateMethod.html @@ -0,0 +1,8 @@ + +
+ +This inspection reports instances methods having the same name as a private method of a superclass. Such +methods may result in confusing semantics, particularly if the private method is ever made publicly visible. + +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/MethodOverridesStaticMethod.html b/plugins/InspectionGadgets/src/inspectionDescriptions/MethodOverridesStaticMethod.html new file mode 100644 index 000000000000..d01f4bc7e13a --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/MethodOverridesStaticMethod.html @@ -0,0 +1,8 @@ + +
+ +This inspection reports instances methods having the same name as a static method of a superclass. Such +methods may result in confusing semantics. + +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/MethodReturnOfConcreteClass.html b/plugins/InspectionGadgets/src/inspectionDescriptions/MethodReturnOfConcreteClass.html new file mode 100644 index 000000000000..74f3bbcab640 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/MethodReturnOfConcreteClass.html @@ -0,0 +1,8 @@ + +
+ +This inspection reports any methods whose return type is declared to be a concrete class, rather than an interface. +Such declarations may represent a failure of abstraction, and may make testing more difficult. +Declarations whose classes come from system or third-party libraries will not be reported by this inspection. +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/MethodWithMultipleLoops.html b/plugins/InspectionGadgets/src/inspectionDescriptions/MethodWithMultipleLoops.html new file mode 100644 index 000000000000..084271acae38 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/MethodWithMultipleLoops.html @@ -0,0 +1,7 @@ + +
+ +This inspection reports any instances of methods containing multiple loop statements. + +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/MismatchedArrayReadWrite.html b/plugins/InspectionGadgets/src/inspectionDescriptions/MismatchedArrayReadWrite.html new file mode 100644 index 000000000000..391c05f4fcf0 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/MismatchedArrayReadWrite.html @@ -0,0 +1,9 @@ + +
+ +This inspection reports instances of array fields or variables whose contents are not both +read from and written to. Such mismatched reads and writes are pointless, and may indicate +either dead code or a typographical error. + +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/MismatchedCollectionQueryUpdate.html b/plugins/InspectionGadgets/src/inspectionDescriptions/MismatchedCollectionQueryUpdate.html new file mode 100644 index 000000000000..9ee209bd937b --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/MismatchedCollectionQueryUpdate.html @@ -0,0 +1,9 @@ + +
+ +This inspection reports instances of collection fields or variables whose contents are not both +queried and updated. Such mismatched queries and updates are pointless, and may indicate +either dead code or a typographical error. + +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/MissortedModifiers.html b/plugins/InspectionGadgets/src/inspectionDescriptions/MissortedModifiers.html new file mode 100644 index 000000000000..fd8c4f419334 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/MissortedModifiers.html @@ -0,0 +1,7 @@ + +
+ +This inspection reports on declarations whose modifiers are not in the canonical preferred order. + +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/MisspelledCompareTo.html b/plugins/InspectionGadgets/src/inspectionDescriptions/MisspelledCompareTo.html new file mode 100644 index 000000000000..5fc136063e91 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/MisspelledCompareTo.html @@ -0,0 +1,6 @@ + +
+This inspection reports any declaration of a compareto() method, taking one argument. +Normally, this is a typo of compareTo(). +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/MisspelledEquals.html b/plugins/InspectionGadgets/src/inspectionDescriptions/MisspelledEquals.html new file mode 100644 index 000000000000..4b9a7da8e68c --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/MisspelledEquals.html @@ -0,0 +1,6 @@ + +
+This inspection reports any declaration of a equal() method, taking one argument. +Normally, this is a typo of equals(). +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/MisspelledHashcode.html b/plugins/InspectionGadgets/src/inspectionDescriptions/MisspelledHashcode.html new file mode 100644 index 000000000000..eb25b8c78aa8 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/MisspelledHashcode.html @@ -0,0 +1,6 @@ + +
+This inspection reports any declaration of a hashcode() method, taking no arguments. +Normally, this is a typo of hashCode(). +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/MisspelledSetUp.html b/plugins/InspectionGadgets/src/inspectionDescriptions/MisspelledSetUp.html new file mode 100644 index 000000000000..7eab0e3a71e2 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/MisspelledSetUp.html @@ -0,0 +1,8 @@ + +
+ +This inspection reports any instances of a setup() method on a JUnit test case. This is +normally a misspelling of setUp(), and is entirely too easy to make. + +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/MisspelledTearDown.html b/plugins/InspectionGadgets/src/inspectionDescriptions/MisspelledTearDown.html new file mode 100644 index 000000000000..dfb40f367c99 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/MisspelledTearDown.html @@ -0,0 +1,8 @@ + +
+ +This inspection reports any instances of a teardown() method on a JUnit test case. This is +normally a misspelling of tearDown(), and is entirely too easy to make. + +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/MisspelledToString.html b/plugins/InspectionGadgets/src/inspectionDescriptions/MisspelledToString.html new file mode 100644 index 000000000000..31591901aabd --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/MisspelledToString.html @@ -0,0 +1,6 @@ + +
+This inspection reports any declaration of a tostring() method, taking one argument. +Normally, this is a typo of toString(). +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/MultipleDeclaration.html b/plugins/InspectionGadgets/src/inspectionDescriptions/MultipleDeclaration.html new file mode 100644 index 000000000000..549e619f25d4 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/MultipleDeclaration.html @@ -0,0 +1,8 @@ + +
+ +This inspection reports instances of multiple variables being declared in a single declaration. +Some coding standards prohibit such declarations. + +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/MultipleReturnPointsPerMethod.html b/plugins/InspectionGadgets/src/inspectionDescriptions/MultipleReturnPointsPerMethod.html new file mode 100644 index 000000000000..b01a1d81dfb8 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/MultipleReturnPointsPerMethod.html @@ -0,0 +1,10 @@ + +
+ +This inspection reports any instances of methods with too many return points. Methods with too many return points +may be confusing, and hard to refactor. +

+Use the field provided below to specify the maximum acceptable number of return points a method might have. + +

Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/MultipleTopLevelClassesInFile.html b/plugins/InspectionGadgets/src/inspectionDescriptions/MultipleTopLevelClassesInFile.html new file mode 100644 index 000000000000..8fa09d1fbc3f --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/MultipleTopLevelClassesInFile.html @@ -0,0 +1,8 @@ + +
+ +This inspection reports any instances of multiple top-level classes in a single java file. Putting multiple +top-level classes in a file can be confusing, and may degrade the usefulness of various +software tools. +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/MultipleTypedDeclaration.html b/plugins/InspectionGadgets/src/inspectionDescriptions/MultipleTypedDeclaration.html new file mode 100644 index 000000000000..12c93a58fb2e --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/MultipleTypedDeclaration.html @@ -0,0 +1,8 @@ + +
+ +This inspection reports instances of multiple different types of variables being declared in a single declaration. +Such declarations may be confusing. + +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/MultiplyOrDivideByPowerOfTwo.html b/plugins/InspectionGadgets/src/inspectionDescriptions/MultiplyOrDivideByPowerOfTwo.html new file mode 100644 index 000000000000..304a40fbc0d3 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/MultiplyOrDivideByPowerOfTwo.html @@ -0,0 +1,8 @@ + +
+ +This inspection reports all instances of multiplication or divison of an integer value by a constant power of 2. These +expressions may be replaced by right or left shift operations, to some possible performance improvement + +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/NakedNotify.html b/plugins/InspectionGadgets/src/inspectionDescriptions/NakedNotify.html new file mode 100644 index 000000000000..683d516bd84b --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/NakedNotify.html @@ -0,0 +1,13 @@ + +
+ +This inspection reports any instances of .notify() or +.notifyAll() being called without any detectable state change occuring. +Normally, .notify() and .notifyAll() are +used to inform other threads that a state change has occured. That state change should occur in a synchronized +context that contains the .notify() or + .notifyAll() call, and prior to the call. While not having such a state change + isn't necessarily incorrect, it is certainly worth examining. + +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/NativeMethods.html b/plugins/InspectionGadgets/src/inspectionDescriptions/NativeMethods.html new file mode 100644 index 000000000000..4b4f31be7827 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/NativeMethods.html @@ -0,0 +1,6 @@ + +
+ +This inspection reports any instances of the methods declared native. Native methods are inherently unportable. +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/NegatedConditional.html b/plugins/InspectionGadgets/src/inspectionDescriptions/NegatedConditional.html new file mode 100644 index 000000000000..69187c4c3785 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/NegatedConditional.html @@ -0,0 +1,11 @@ + +
+ +This inspection reports any instances of conditional expressions whose conditions are negated. +Flipping the order of the conditional expression branches will usually increase the clarity of such statements. +

+Use the check box below to have comparisons of the form != null +ignored by this inspection + +

Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/NegatedIfElse.html b/plugins/InspectionGadgets/src/inspectionDescriptions/NegatedIfElse.html new file mode 100644 index 000000000000..ef38686e1ef9 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/NegatedIfElse.html @@ -0,0 +1,13 @@ + +
+ +This inspection reports any instances of if statements +which contain else branches and whose conditions are negated. +Flipping the order of the if and else +branches will usually increase the clarity of such statements. +

+Use the check box below to have comparisons of the form != null +ignored by this inspection + +

Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/NestedAssignment.html b/plugins/InspectionGadgets/src/inspectionDescriptions/NestedAssignment.html new file mode 100644 index 000000000000..3911f27f823f --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/NestedAssignment.html @@ -0,0 +1,8 @@ + +
+ +This inspection reports any instances of assignment expressions nested inside other expressions. While admirably terse, +such expressions may be confusing, and violate the general design priniciple that a given construct should do precisely one thing. + +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/NestedConditionalExpression.html b/plugins/InspectionGadgets/src/inspectionDescriptions/NestedConditionalExpression.html new file mode 100644 index 000000000000..8f66bb07085f --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/NestedConditionalExpression.html @@ -0,0 +1,8 @@ + +
+ +This inspection reports all instances of nested conditional expressions. Nested conditional expressions +may result in extremely confusing code. + +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/NestedMethodCall.html b/plugins/InspectionGadgets/src/inspectionDescriptions/NestedMethodCall.html new file mode 100644 index 000000000000..ebc29dc2dd69 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/NestedMethodCall.html @@ -0,0 +1,8 @@ + +
+ +This inspection reports any instances of method calls used as a parameter of another +method call. + +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/NestedSwitchStatement.html b/plugins/InspectionGadgets/src/inspectionDescriptions/NestedSwitchStatement.html new file mode 100644 index 000000000000..8827219673d9 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/NestedSwitchStatement.html @@ -0,0 +1,8 @@ + +
+ +This inspection reports all instances of nested switch statements. Nested switch statements +may result in extremely confusing code. + +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/NestedSynchronizedStatement.html b/plugins/InspectionGadgets/src/inspectionDescriptions/NestedSynchronizedStatement.html new file mode 100644 index 000000000000..f784ffeb3305 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/NestedSynchronizedStatement.html @@ -0,0 +1,8 @@ + +
+ +This inspection reports all instances of nested synchronized statements. Nested synchronized statements +are either useless (if the lock objects are identical) or prone to deadlock. + +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/NestedTryStatement.html b/plugins/InspectionGadgets/src/inspectionDescriptions/NestedTryStatement.html new file mode 100644 index 000000000000..82bad25530a7 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/NestedTryStatement.html @@ -0,0 +1,9 @@ + +
+ +This inspection reports all instances of nested try statements. Nested try statements +may result in confusing code, and should probably have their catch and finally sections +merged. + +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/NestingDepth.html b/plugins/InspectionGadgets/src/inspectionDescriptions/NestingDepth.html new file mode 100644 index 000000000000..8606e35480db --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/NestingDepth.html @@ -0,0 +1,10 @@ + +
+ +This inspection reports any instances of methods whose bodies are too deeply nested. Methods with too much statement +nesting may be confusing, and are a good sign that refactoring may be necessary. +

+Use the field provided below to specify the maximum acceptable nesting depth a method might have. + +

Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/NoExplicitFinalizeCalls.html b/plugins/InspectionGadgets/src/inspectionDescriptions/NoExplicitFinalizeCalls.html new file mode 100644 index 000000000000..14e2a1b01732 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/NoExplicitFinalizeCalls.html @@ -0,0 +1,8 @@ + +
+This inspection reports any call of Object.finalize(). Calling +Object.finalize() explicitly is a very bad idea, as it can result in objects being placed in an +inconsistent state. Calls to super.finalize() from within implementations of finalize() +are benign, and are not reported by this inspection. +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/NonCommentSourceStatements.html b/plugins/InspectionGadgets/src/inspectionDescriptions/NonCommentSourceStatements.html new file mode 100644 index 000000000000..d046cca38a5c --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/NonCommentSourceStatements.html @@ -0,0 +1,10 @@ + +
+ +This inspection reports any instances of methods that are too long. Methods that are too long +may be confusing, and are a good sign that refactoring is necessary. +

+Use the field provided below to specify the maximum acceptable number of non-comment source statements a method might have. + +

Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/NonExceptionNameEndsWithException.html b/plugins/InspectionGadgets/src/inspectionDescriptions/NonExceptionNameEndsWithException.html new file mode 100644 index 000000000000..875f77024165 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/NonExceptionNameEndsWithException.html @@ -0,0 +1,7 @@ + +
+ +This inspection reports any instances of non-exception classes whose names end with 'Exception'. + +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/NonProtectedConstructorInAbstractClass.html b/plugins/InspectionGadgets/src/inspectionDescriptions/NonProtectedConstructorInAbstractClass.html new file mode 100644 index 000000000000..28b568d0ab84 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/NonProtectedConstructorInAbstractClass.html @@ -0,0 +1,8 @@ + +
+ +This inspection reports all instances of constructors in abstract classes that are not +declared protected or private. + +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/NonSerializableWithSerialVersionUIDField.html b/plugins/InspectionGadgets/src/inspectionDescriptions/NonSerializableWithSerialVersionUIDField.html new file mode 100644 index 000000000000..bf7c9fbd2feb --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/NonSerializableWithSerialVersionUIDField.html @@ -0,0 +1,8 @@ + +
+ +This inspection reports on instances of non-Serializable classes which define a serialVersionUID +field. This is usually an indication of a programmer error. + +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/NonSerializableWithSerializationMethods.html b/plugins/InspectionGadgets/src/inspectionDescriptions/NonSerializableWithSerializationMethods.html new file mode 100644 index 000000000000..c8168b43a76d --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/NonSerializableWithSerializationMethods.html @@ -0,0 +1,8 @@ + +
+ +This inspection reports on instances of non-Serializable classes which define readObject() +or writeObject() methods. Such methods normally indicate programmer error. + +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/NonShortCircuitBoolean.html b/plugins/InspectionGadgets/src/inspectionDescriptions/NonShortCircuitBoolean.html new file mode 100644 index 000000000000..0bc5401e1637 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/NonShortCircuitBoolean.html @@ -0,0 +1,9 @@ + +
+ +This inspection reports on any uses of the non-short-circuit forms of boolean 'and' and 'or' ( & +and | ). The non-short-circuit versions are occasionally useful, but +their presence is often due to typos of the short-circuit forms ( && +and || ), and may lead to subtle bugs. +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/NonStaticFinalLogger.html b/plugins/InspectionGadgets/src/inspectionDescriptions/NonStaticFinalLogger.html new file mode 100644 index 000000000000..e0105080ea7e --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/NonStaticFinalLogger.html @@ -0,0 +1,14 @@ + +
+ +This inspection reports any instances of logger fields on classes which are not declared static. +and final. +Ensuring that every classes logger is effectively constant and bound to that class +simplifies the task of providing a unified logging implementation for an application. Interfaces, +enumerations, annotations, inner classes, and abstract classes are not reported by this inspection. +

+Use the field below to specify the name of the class which will be used for logging in this project. +Fields of that type which are not static. +and final will be reported by this inspection. +

Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/NonStaticInnerClassInSecureContext.html b/plugins/InspectionGadgets/src/inspectionDescriptions/NonStaticInnerClassInSecureContext.html new file mode 100644 index 000000000000..2370f249d8e5 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/NonStaticInnerClassInSecureContext.html @@ -0,0 +1,9 @@ + +
+ +This inspection reports any instances of non-static inner classes. +Compilation of such classes causes the creation of hidden, package-visible methods on the parent class, which may +compromise security. + +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/NonSynchronizedMethodOverridesSynchronizedMethod.html b/plugins/InspectionGadgets/src/inspectionDescriptions/NonSynchronizedMethodOverridesSynchronizedMethod.html new file mode 100644 index 000000000000..6338b33db211 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/NonSynchronizedMethodOverridesSynchronizedMethod.html @@ -0,0 +1,7 @@ + +
+ +This inspection reports any instances of non-synchronized +methods overriding synchronized methods. +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/NoopMethodInAbstractClass.html b/plugins/InspectionGadgets/src/inspectionDescriptions/NoopMethodInAbstractClass.html new file mode 100644 index 000000000000..80e830b9e4cf --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/NoopMethodInAbstractClass.html @@ -0,0 +1,8 @@ + +
+ +This inspection reports any instances of "no-op" methods in abstract classes. It is usually a better +design to make such methods abstract themselves, so that classes which inherit the methods will not forget to provide +their own implementations. +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/NotifyNotInSynchronizedContext.html b/plugins/InspectionGadgets/src/inspectionDescriptions/NotifyNotInSynchronizedContext.html new file mode 100644 index 000000000000..51e3f6504ddd --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/NotifyNotInSynchronizedContext.html @@ -0,0 +1,10 @@ + +
+ +This inspection reports on any call to notify() not made inside a corresponding synchronized +statement or synchronized method. Calling notify() on an object +without holding a lock on that object will result in an IllegalMonitorStateException being thrown. +Such a construct is not necessarily an error, as the necessary lock may be acquired before +the containing method is called, but it's worth looking at. +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/NumericToString.html b/plugins/InspectionGadgets/src/inspectionDescriptions/NumericToString.html new file mode 100644 index 000000000000..bde1e0b390d9 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/NumericToString.html @@ -0,0 +1,8 @@ + +
+ +This inspection reports any call of toString() on numeric objects. 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/ObjectAllocationInLoop.html b/plugins/InspectionGadgets/src/inspectionDescriptions/ObjectAllocationInLoop.html new file mode 100644 index 000000000000..f93a3f8b0991 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/ObjectAllocationInLoop.html @@ -0,0 +1,9 @@ + +
+ +This inspection reports on instances of object or array allocation inside loops. While not +necessarily a problem, object allocation inside loop is a great place to look for memory leaks +and performance issues. + +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/ObjectEquality.html b/plugins/InspectionGadgets/src/inspectionDescriptions/ObjectEquality.html new file mode 100644 index 000000000000..57ee63f1d835 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/ObjectEquality.html @@ -0,0 +1,10 @@ + +
+This inspection reports any use of == to test for Object equality, +rather than the ".equals()" method. Note that comparison of Strings using == is not +reported by this inspection, nor is the comparison of an object to null using ==. +

+Use checkbox below to indicate whether uses of == between objects of enumerated type +should be reported by this inspection. +

Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/ObjectEqualsNull.html b/plugins/InspectionGadgets/src/inspectionDescriptions/ObjectEqualsNull.html new file mode 100644 index 000000000000..d9fccda85a10 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/ObjectEqualsNull.html @@ -0,0 +1,8 @@ + +
+ +This inspection reports on instances of .equals() calls which have null +as an argument. The semantics of such calls are almost certainly not what was intended. + +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/ObjectNotify.html b/plugins/InspectionGadgets/src/inspectionDescriptions/ObjectNotify.html new file mode 100644 index 000000000000..d3c4ff7cc3df --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/ObjectNotify.html @@ -0,0 +1,8 @@ + +
+ +This inspection reports any calls to notify(). While occasionally useful, in almost all cases +notifyAll() is a better choice. See Doug Lea's Concurrent Programming in Java for a discussion. + +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/ObsoleteCollection.html b/plugins/InspectionGadgets/src/inspectionDescriptions/ObsoleteCollection.html new file mode 100644 index 000000000000..ccf888500e1e --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/ObsoleteCollection.html @@ -0,0 +1,9 @@ + +
+ +This inspection reports any uses of java.util.Vector or +java.util.Hashtable. While still supported, these +classes were made obsolete by the JDK1.2 collection classes, and should probably not be used in new development. + +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/OctalAndDecimalIntegersMixed.html b/plugins/InspectionGadgets/src/inspectionDescriptions/OctalAndDecimalIntegersMixed.html new file mode 100644 index 000000000000..2ae8cf6e7294 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/OctalAndDecimalIntegersMixed.html @@ -0,0 +1,7 @@ + +
+This inspection reports any use of both octal and decimal integers in an array +initialization. This is often due to creating an array by copying a list of numbers into an array without noticing +that some of them are zero-padded, and will thus be interpretted by the Java compiler as octal. +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/OctalLiteral.html b/plugins/InspectionGadgets/src/inspectionDescriptions/OctalLiteral.html new file mode 100644 index 000000000000..301550525b2e --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/OctalLiteral.html @@ -0,0 +1,8 @@ + +
+ +This inspection reports any instances of octal integer literals. Some coding standards prohibit the +use of octal literals, as they may be easily confused with decimal literals. + +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/OnDemandImport.html b/plugins/InspectionGadgets/src/inspectionDescriptions/OnDemandImport.html new file mode 100644 index 000000000000..dc3ec9d3645f --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/OnDemandImport.html @@ -0,0 +1,10 @@ + +
+ +This inspection reports any import statements which cover entire packages ('* imports'). +Some coding standards prohibit such import statements. Since IDEA can automatically +detect and fix such statements with it's "Optimize Imports" command, this inspection is mostly useful +for off-line reporting on code bases that you don't intend to change. + +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/OverloadedMethodsWithSameNumberOfParameters.html b/plugins/InspectionGadgets/src/inspectionDescriptions/OverloadedMethodsWithSameNumberOfParameters.html new file mode 100644 index 000000000000..10e8cc273420 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/OverloadedMethodsWithSameNumberOfParameters.html @@ -0,0 +1,8 @@ + +
+ +This inspection reports on cases where multiple methods of the same class are declared +with the identical name and same number of parameters. + +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/OverlyComplexArithmeticExpression.html b/plugins/InspectionGadgets/src/inspectionDescriptions/OverlyComplexArithmeticExpression.html new file mode 100644 index 000000000000..75525589ebf9 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/OverlyComplexArithmeticExpression.html @@ -0,0 +1,9 @@ + +
+ +This inspection reports any instances of arithmetic expressions with too many terms. Such +expressions may be confusing and bug-prone. +

+Use the field provided below to specify the maximum number of terms allowed in an arithmetic expression. +

Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/OverlyComplexBooleanExpression.html b/plugins/InspectionGadgets/src/inspectionDescriptions/OverlyComplexBooleanExpression.html new file mode 100644 index 000000000000..7b191b2c2d8f --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/OverlyComplexBooleanExpression.html @@ -0,0 +1,10 @@ + +
+ +This inspection reports any instances of boolean expressions with too many terms. Such +expressions may be confusing and bug-prone. +

+Use the field provided below to specify the maximum number of terms allowed in a boolean expression. + +

Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/OverlyStrongTypeCast.html b/plugins/InspectionGadgets/src/inspectionDescriptions/OverlyStrongTypeCast.html new file mode 100644 index 000000000000..2f849e0702b8 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/OverlyStrongTypeCast.html @@ -0,0 +1,11 @@ + +
+ +This inspection reports any instances of type casts which are overly strong. For instance, +casting an object to ArrayList when casting it to +List would do just as well. Note: much like the "Redundant type cast" +inspection, applying the fix for this inspection may change the semantics of your program, if you are +intentionally using an overly strong cast to cause a ClassCastException to be generated. Use caution. + +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/OverridableMethodCallInConstructor.html b/plugins/InspectionGadgets/src/inspectionDescriptions/OverridableMethodCallInConstructor.html new file mode 100644 index 000000000000..d4bb21343c65 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/OverridableMethodCallInConstructor.html @@ -0,0 +1,10 @@ + +
+ +This inspection reports any calls of overridable methods within a constructor. +Methods are overridable if they are not declared final, +static or private. +Such calls may result in subtle bugs, as the object is not guaranteed to be initialized +before the method call occurs. +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/PackageVisibleField.html b/plugins/InspectionGadgets/src/inspectionDescriptions/PackageVisibleField.html new file mode 100644 index 000000000000..88ad7d585245 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/PackageVisibleField.html @@ -0,0 +1,6 @@ + +
+This inspection reports any instances of package-visible instance variables. +Constants (i.e. variables marked static and final) are not reported. +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/PackageVisibleInnerClass.html b/plugins/InspectionGadgets/src/inspectionDescriptions/PackageVisibleInnerClass.html new file mode 100644 index 000000000000..81fa5d09b7cd --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/PackageVisibleInnerClass.html @@ -0,0 +1,5 @@ + +
+This inspection reports any instances of package-visible inner classes. +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/ParameterHidingMemberVariable.html b/plugins/InspectionGadgets/src/inspectionDescriptions/ParameterHidingMemberVariable.html new file mode 100644 index 000000000000..146f4a38fc68 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/ParameterHidingMemberVariable.html @@ -0,0 +1,8 @@ + +
+ +This inspection reports any instances of method parameters being named identically to visible member variables of their +class. Such a parameter name may be confusing. + +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/ParameterNamingConvention.html b/plugins/InspectionGadgets/src/inspectionDescriptions/ParameterNamingConvention.html new file mode 100644 index 000000000000..689863d3d678 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/ParameterNamingConvention.html @@ -0,0 +1,11 @@ + +
+ +This inspection reports instances of method parameters whose names are either too short, too long, or do not follow +the specified regular expression pattern. +

+Use the fields provided below to specify mininum length, maximum length and regular expression expected for method parameter names. +(Regular expressions are in standard java.util.regex format.) + +

Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/ParameterOfConcreteClass.html b/plugins/InspectionGadgets/src/inspectionDescriptions/ParameterOfConcreteClass.html new file mode 100644 index 000000000000..5d7aad85e12e --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/ParameterOfConcreteClass.html @@ -0,0 +1,8 @@ + +
+ +This inspection reports any method parameters whose type is declared to be a concrete class, rather than an interface. +Such declarations may represent a failure of abstraction, and may make testing more difficult. +Declarations whose classes come from system or third-party libraries will not be reported by this inspection. +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/ParametersPerMethod.html b/plugins/InspectionGadgets/src/inspectionDescriptions/ParametersPerMethod.html new file mode 100644 index 000000000000..3a3c0ee658dd --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/ParametersPerMethod.html @@ -0,0 +1,11 @@ + +
+ +This inspection reports any instances of methods with too many parameters. Methods with too many parameters +are a good sign that refactoring is necessary. Methods whose signatures are inherited from +library classes are ignored by this inspection. +

+Use the field provided below to specify the maximum acceptable number of parameters a method might have. + +

Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/PointlessArithmeticExpression.html b/plugins/InspectionGadgets/src/inspectionDescriptions/PointlessArithmeticExpression.html new file mode 100644 index 000000000000..61f181055de3 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/PointlessArithmeticExpression.html @@ -0,0 +1,10 @@ + +
+This inspection reports any instances of pointless arithmetic +expressions. Such expressions include adding or subtracting zero, multiplying by zero or one, +division by one, and shift by zero. Such expressions may be the result of automated refactorings +not completely followed through to completion, and in any case are unlikely to be what the developer +intended to do. + +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/PointlessBitwiseExpression.html b/plugins/InspectionGadgets/src/inspectionDescriptions/PointlessBitwiseExpression.html new file mode 100644 index 000000000000..8adb7c50c990 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/PointlessBitwiseExpression.html @@ -0,0 +1,10 @@ + +
+This inspection reports any instances of pointless bitwise +expressions. Such expressions include 'anding' with zero, 'oring' by zero, +and shift by zero. Such expressions may be the result of automated refactorings +not completely followed through to completion, and in any case are unlikely to be what the developer +intended to do. + +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/PointlessBooleanExpression.html b/plugins/InspectionGadgets/src/inspectionDescriptions/PointlessBooleanExpression.html new file mode 100644 index 000000000000..8f6b1ce282c0 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/PointlessBooleanExpression.html @@ -0,0 +1,10 @@ + +
+This inspection reports any instances of pointless or pointlessly +complicated boolean expressions. Such expressions include anding with true, oring with false, +equality comparison with a boolean literal, or negation of a boolean literal. Such expressions may be the result of automated refactorings +not completely followed through to completion, and in any case are unlikely to be what the developer +intended to do. + +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/ProtectedField.html b/plugins/InspectionGadgets/src/inspectionDescriptions/ProtectedField.html new file mode 100644 index 000000000000..75ab10503b9e --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/ProtectedField.html @@ -0,0 +1,6 @@ + +
+This inspection reports any instances of protected instance variables. +Constants (i.e. variables marked static and final) are not reported. +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/ProtectedInnerClass.html b/plugins/InspectionGadgets/src/inspectionDescriptions/ProtectedInnerClass.html new file mode 100644 index 000000000000..b4038ed1d301 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/ProtectedInnerClass.html @@ -0,0 +1,5 @@ + +
+This inspection reports any instances of protected inner classes. +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/ProtectedMemberInFinalClass.html b/plugins/InspectionGadgets/src/inspectionDescriptions/ProtectedMemberInFinalClass.html new file mode 100644 index 000000000000..58817d85564c --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/ProtectedMemberInFinalClass.html @@ -0,0 +1,9 @@ + +
+ +This inspection reports any instances of members being declared protected in +classes that are declared final. Such members may be declared private +or package-visible instead. + +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/PublicConstructorInNonPublicClass.html b/plugins/InspectionGadgets/src/inspectionDescriptions/PublicConstructorInNonPublicClass.html new file mode 100644 index 000000000000..66f12d1ae8ff --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/PublicConstructorInNonPublicClass.html @@ -0,0 +1,8 @@ + +
+ +This inspection reports all instances constructors in non-public +classes that are declared public. + +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/PublicField.html b/plugins/InspectionGadgets/src/inspectionDescriptions/PublicField.html new file mode 100644 index 000000000000..8b142ff571a7 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/PublicField.html @@ -0,0 +1,6 @@ + +
+This inspection reports any instances of public instance variables. +Constants (i.e. variables marked static and final) are not reported. +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/PublicFieldAccessedInSynchronizedContext.html b/plugins/InspectionGadgets/src/inspectionDescriptions/PublicFieldAccessedInSynchronizedContext.html new file mode 100644 index 000000000000..cc3a3b88df4d --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/PublicFieldAccessedInSynchronizedContext.html @@ -0,0 +1,10 @@ + +
+ +This inspection reports any instances of non-final, non-private fields which are accessed in a synchronized context. +A non-private field cannot be gauranteed to always be accessed in a synchronized manner, and such "partially synchronized" +access may result in unexpectedly inconsistent data structures. Accesses in constructors an initializers are ignored +for purposes of this inspection. + +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/PublicInnerClass.html b/plugins/InspectionGadgets/src/inspectionDescriptions/PublicInnerClass.html new file mode 100644 index 000000000000..3d1136ad51d8 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/PublicInnerClass.html @@ -0,0 +1,5 @@ + +
+This inspection reports any instances of public inner classes. +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/PublicMethodNotExposedInInterface.html b/plugins/InspectionGadgets/src/inspectionDescriptions/PublicMethodNotExposedInInterface.html new file mode 100644 index 000000000000..51b44f813c71 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/PublicMethodNotExposedInInterface.html @@ -0,0 +1,9 @@ + +
+ +This inspection reports instances of public methods on classes +which are not exposed as in interface. Exposing all public methods via interface is important for +maintaining loose coupling, and may be necessary for certain component-based programming styles. + +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/RawUseOfParameterizedType.html b/plugins/InspectionGadgets/src/inspectionDescriptions/RawUseOfParameterizedType.html new file mode 100644 index 000000000000..7932a84326db --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/RawUseOfParameterizedType.html @@ -0,0 +1,9 @@ + +
+ +This inspection reports any uses of parameterized classes where the type parameters are omitted. +Such "raw" uses of parameterized types are valid in Java, but defeat the purpose of using +type parameters, and may mask bugs. + +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/ReadObjectAndWriteObjectPrivate.html b/plugins/InspectionGadgets/src/inspectionDescriptions/ReadObjectAndWriteObjectPrivate.html new file mode 100644 index 000000000000..6daaaf431387 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/ReadObjectAndWriteObjectPrivate.html @@ -0,0 +1,9 @@ + +
+ +This inspection reports on instances of Serializable classes where the readObject +and writeObject() methods are not declared private. There is no reason these methods should ever +have greater visibility than that. + +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/ReadObjectInitialization.html b/plugins/InspectionGadgets/src/inspectionDescriptions/ReadObjectInitialization.html new file mode 100644 index 000000000000..73f33f5f162e --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/ReadObjectInitialization.html @@ -0,0 +1,11 @@ + +
+ +This inspection reports instances of instance variables which are not guaranteed to be initialized after the object is +deserialized by the readObject() method. +

+Note: This inspection uses a very conservative dataflow algorithm, and may report instance variables +as uninitialized incorrectly. Variables reported as initialized will always be initialized. + +

Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/ReadResolveAndWriteReplaceProtected.html b/plugins/InspectionGadgets/src/inspectionDescriptions/ReadResolveAndWriteReplaceProtected.html new file mode 100644 index 000000000000..65e05406b8bf --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/ReadResolveAndWriteReplaceProtected.html @@ -0,0 +1,8 @@ + +
+ +This inspection reports on instances of Serializable classes where the readResolve() +and writeReplace() methods are not declared protected. + +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/RedundantFieldInitialization.html b/plugins/InspectionGadgets/src/inspectionDescriptions/RedundantFieldInitialization.html new file mode 100644 index 000000000000..00e9c8e92bf4 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/RedundantFieldInitialization.html @@ -0,0 +1,7 @@ + +
+ +This inspection reports any instances of fields explicitly initialized to +the same values that the JVM would initialize it to by default. +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/RedundantImplements.html b/plugins/InspectionGadgets/src/inspectionDescriptions/RedundantImplements.html new file mode 100644 index 000000000000..072bcf850954 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/RedundantImplements.html @@ -0,0 +1,8 @@ + +
+ +This inspection reports any cases of classes declaring that they implement or extend an interface, when +that interface is already declared as implemented by a superclass or extended by another interface +of that class. Such declarations are unnecessary, and may be safely removed. +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/RedundantImport.html b/plugins/InspectionGadgets/src/inspectionDescriptions/RedundantImport.html new file mode 100644 index 000000000000..8fcf6f32a2cd --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/RedundantImport.html @@ -0,0 +1,11 @@ + +
+ +This inspection reports any import +statements that are covered by previous import +statements in the same file. Since IDEA can automatically +detect and fix such statements with it's "Optimize Imports" command, this inspection is mostly useful +for off-line reporting on code bases that you don't intend to change. + +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/RefusedBequest.html b/plugins/InspectionGadgets/src/inspectionDescriptions/RefusedBequest.html new file mode 100644 index 000000000000..67ffd0cce58d --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/RefusedBequest.html @@ -0,0 +1,8 @@ + +
+This inspection reports any methods which override concrete methods, +but which do not call that method as super. Such methods +may represent a failure of abstraction, and can lead to hard-to-trace bugs. Methods overridden +from java.lang.Object are not reported by this inspection. +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/ReplaceAssignmentWithOperatorAssignment.html b/plugins/InspectionGadgets/src/inspectionDescriptions/ReplaceAssignmentWithOperatorAssignment.html new file mode 100644 index 000000000000..ab30b7e85936 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/ReplaceAssignmentWithOperatorAssignment.html @@ -0,0 +1,8 @@ + +
+ +This inspection reports instances of assignment operations which can be replaced by operator-assignment. Code +using operator assignment may be clearer, and theoretically more performant. + +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/ResultOfObjectAllocationIgnored.html b/plugins/InspectionGadgets/src/inspectionDescriptions/ResultOfObjectAllocationIgnored.html new file mode 100644 index 000000000000..8ebe6e1f03a4 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/ResultOfObjectAllocationIgnored.html @@ -0,0 +1,8 @@ + +
+ +This inspection reports any instances of object allocation where the object allocated ignored. +Such allocation expressions are legal Java, but are usually either inadvertant, or +evidence of a very odd object initialization strategy. +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/ResultSetIndexZero.html b/plugins/InspectionGadgets/src/inspectionDescriptions/ResultSetIndexZero.html new file mode 100644 index 000000000000..0ab0ef485058 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/ResultSetIndexZero.html @@ -0,0 +1,8 @@ + +
+ +This inspection reports any attempts to access column 0 of a java.sql.ResultSet. For historical +reasons, columns of java.sql.ResultSets are numbered beginning with 1, rather than +0, and accessing column 0 is a common error in JDBC programming. +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/ReturnFromFinallyBlock.html b/plugins/InspectionGadgets/src/inspectionDescriptions/ReturnFromFinallyBlock.html new file mode 100644 index 000000000000..0cd1f6c3b3b1 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/ReturnFromFinallyBlock.html @@ -0,0 +1,9 @@ + +
+ +This inspection reports any instances of return statements inside of finally +blocks. While occasionally intended, such return statements may mask exceptions thrown, and +tremendously complicate debugging. + +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/ReturnNull.html b/plugins/InspectionGadgets/src/inspectionDescriptions/ReturnNull.html new file mode 100644 index 000000000000..9256446f58ab --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/ReturnNull.html @@ -0,0 +1,13 @@ + +
+ +This inspection reports any instances of return statements with null values. +While occasionally useful, this construct may make the code more prone +to failing with a NullPointerException, and often indicates that the developer doesn't really understand the classes +intended semantics. +

+Use the controls below to specify whether this inspections should return null object returns, null array returns, +or both. + +

Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/ReturnOfCollectionField.html b/plugins/InspectionGadgets/src/inspectionDescriptions/ReturnOfCollectionField.html new file mode 100644 index 000000000000..52a977b0959f --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/ReturnOfCollectionField.html @@ -0,0 +1,10 @@ + +
+ +This inspection reports any attempt to return an array or Collection field from a method. Since +the array or Collection may have it's contents modified by the calling method, this construct may +result in an object having it's state modified unexpectedly. While occasionally useful for performance +reasons, this construct is inherently bug-prone. + +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/ReturnOfDateField.html b/plugins/InspectionGadgets/src/inspectionDescriptions/ReturnOfDateField.html new file mode 100644 index 000000000000..918afe8f384a --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/ReturnOfDateField.html @@ -0,0 +1,12 @@ + +
+ +This inspection reports any attempt to return a java.lang.Date or +java.lang.Calendar field from a method. Since +Date or Calendar are often +treated as immutable values but are actually mutable, this construct may +result in an object having it's state modified unexpectedly. While occasionally useful for performance +reasons, this construct is inherently bug-prone. + +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/ReturnThis.html b/plugins/InspectionGadgets/src/inspectionDescriptions/ReturnThis.html new file mode 100644 index 000000000000..c23e4e1f6298 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/ReturnThis.html @@ -0,0 +1,10 @@ + +
+ +This inspection reports on instances of methods returning this. +While such a return is valid, it is rarely necessary, and usually indicates that the developer intends the method to be used +as part of a chain of similar method calls (e.g. buffer.append("foo").append("bar").append("baz")). +Such chains are frowned upon by many coding standards. + +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/RuntimeExec.html b/plugins/InspectionGadgets/src/inspectionDescriptions/RuntimeExec.html new file mode 100644 index 000000000000..de74562887eb --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/RuntimeExec.html @@ -0,0 +1,7 @@ + +
+ +This inspection reports any instances of the calls to Runtime.exec() or any +of it's variants. Calls to Runtime.exec() are inherently unportable. +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/SamePackageImport.html b/plugins/InspectionGadgets/src/inspectionDescriptions/SamePackageImport.html new file mode 100644 index 000000000000..e9e02ddaae47 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/SamePackageImport.html @@ -0,0 +1,11 @@ + +
+ +This inspection reports any import statements which refer to the same package as the +containing file. Such imports are unnecessary, and probably the result of incomplete +refactorings. Since IDEA can automatically detect and fix such statements with it's +"Optimize Imports" command, this inspection is mostly useful for off-line reporting on +code bases that you don't intend to change. + +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/SerialVersionUIDNotStaticFinal.html b/plugins/InspectionGadgets/src/inspectionDescriptions/SerialVersionUIDNotStaticFinal.html new file mode 100644 index 000000000000..6effc5beaab4 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/SerialVersionUIDNotStaticFinal.html @@ -0,0 +1,8 @@ + +
+ +This inspection reports any instances of Serializable classes whose serialVersionUID field. +is not declared static and final. + +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/SerializableClassInSecureContext.html b/plugins/InspectionGadgets/src/inspectionDescriptions/SerializableClassInSecureContext.html new file mode 100644 index 000000000000..7ead3b4749b5 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/SerializableClassInSecureContext.html @@ -0,0 +1,10 @@ + +
+ +This inspection reports any instances of classes which may be serialized. A class +may be serialized if it supports the Serializable interface, +and its writeObject() method is not defined to immediately +throw an error. Serializable classes may be dangerous in code intended for secure use. + +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/SerializableHasSerialVersionUIDField.html b/plugins/InspectionGadgets/src/inspectionDescriptions/SerializableHasSerialVersionUIDField.html new file mode 100644 index 000000000000..049aade808ca --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/SerializableHasSerialVersionUIDField.html @@ -0,0 +1,12 @@ + +
+ +This inspection reports any instances of Serializable classes which do not provide a serialVersionUID field. +Without a serialVersionUID field, any change to a class will make previously serialized versions unreadable. +

+Use the checkbox below to specify whether this inspection should report classes which are only serializable +due to inheriting from serializable classes. Such classes are often not intended for serialization, and so +this inspection would report unnecessarily + +

Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/SerializableHasSerializationMethods.html b/plugins/InspectionGadgets/src/inspectionDescriptions/SerializableHasSerializationMethods.html new file mode 100644 index 000000000000..19700c868e6c --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/SerializableHasSerializationMethods.html @@ -0,0 +1,14 @@ + +
+ +This inspection reports any instances of Serializable classes which do not provide readObject and +writeObject methods. If readObject and writeObject methods are not +provided, the default serialization algorithms are used, which may be sub-optimal in many environments for performance +and compatibility purposes. +

+Use the checkbox below to specify whether this inspection should report classes which are only serializable +due to inheriting from serializable classes. Such classes are often not intended for serialization, and so +this inspection would report unnecessarily. + +

Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/SerializableInnerClassHasSerialVersionUIDField.html b/plugins/InspectionGadgets/src/inspectionDescriptions/SerializableInnerClassHasSerialVersionUIDField.html new file mode 100644 index 000000000000..a0275640b99b --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/SerializableInnerClassHasSerialVersionUIDField.html @@ -0,0 +1,17 @@ + +
+ +This inspection reports any instances of Serializable non-static +inner classes which do not provide a serialVersionUID field. +Without a serialVersionUID field, any change to a class will make previously serialized versions unreadable. +It is strongly recommended that Serializable non-static inner classes have +a serialVersionUID field, otherwise the default serialization algorithm +may result in serialized versions being incompatible between compilers, due to differences in synthetic +accessor methods. +

+Use the checkbox below to specify whether this inspection should report classes which are only serializable +due to inheriting from serializable classes. Such classes are often not intended for serialization, and so +this inspection would report unnecessarily. + +

Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/SerializableInnerClassWithNonSerializableOuterClass.html b/plugins/InspectionGadgets/src/inspectionDescriptions/SerializableInnerClassWithNonSerializableOuterClass.html new file mode 100644 index 000000000000..03614c5e6725 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/SerializableInnerClassWithNonSerializableOuterClass.html @@ -0,0 +1,13 @@ + +
+ +This inspection reports any instances of Serializable non-static +inner classes whose outer classes are non-Serializable. Such classes +are unlikely to serialize correctly, due to implicit references from the inner to outer class. +

+Use the checkbox below to specify whether this inspection should report classes which are only serializable +due to inheriting from serializable classes. Such classes are often not intended for serialization, and so +this inspection would report unnecessarily. + +

Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/SerializableWithUnconstructableAncestor.html b/plugins/InspectionGadgets/src/inspectionDescriptions/SerializableWithUnconstructableAncestor.html new file mode 100644 index 000000000000..3c6153a10e75 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/SerializableWithUnconstructableAncestor.html @@ -0,0 +1,8 @@ + +
+ +This inspection reports any instances of Serializable classes whose closest non-serializable ancestor lacks +a no-argument constructor. Such classes can not be deserialized. + +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/SetupCallsSuperSetup.html b/plugins/InspectionGadgets/src/inspectionDescriptions/SetupCallsSuperSetup.html new file mode 100644 index 000000000000..78fc6a655cba --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/SetupCallsSuperSetup.html @@ -0,0 +1,7 @@ + +
+ +This inspection reports any instances of JUnit classes whose setUp() method +does not call super.setUp(). +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/SetupIsPublicVoidNoArg.html b/plugins/InspectionGadgets/src/inspectionDescriptions/SetupIsPublicVoidNoArg.html new file mode 100644 index 000000000000..b58ca9278da8 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/SetupIsPublicVoidNoArg.html @@ -0,0 +1,10 @@ + +
+ +This inspection reports any instances of JUnit classes whose setUp() method +is not declared +public, does not return void, or takes arguments. +Such setUp() methods are easy to create inadvertantly, +and will not be executed by JUnit tests runners. +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/SingleCharacterStartsWith.html b/plugins/InspectionGadgets/src/inspectionDescriptions/SingleCharacterStartsWith.html new file mode 100644 index 000000000000..1358465d0f95 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/SingleCharacterStartsWith.html @@ -0,0 +1,8 @@ + +
+ +This inspection reports instances calls to String.startsWith() or String.endsWith() which are called +with single character string literals. Such calls may be more efficiently implemented with String.charAt() . + +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/SingleClassImport.html b/plugins/InspectionGadgets/src/inspectionDescriptions/SingleClassImport.html new file mode 100644 index 000000000000..1ce9ab52f73a --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/SingleClassImport.html @@ -0,0 +1,10 @@ + +
+ +This inspection reports any import statements which cover single classes (as opposed to entire packages). +Some coding standards prohibit such import statements. Since IDEA can automatically +detect and fix such statements with it's "Optimize Imports" command, this inspection is mostly useful +for off-line reporting on code bases that you don't intend to change. + +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/Singleton.html b/plugins/InspectionGadgets/src/inspectionDescriptions/Singleton.html new file mode 100644 index 000000000000..3a3f1b376f05 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/Singleton.html @@ -0,0 +1,9 @@ + +
+ +This inspection reports any instances of singleton classes. +Singleton classes are declared so that only one instance of the +class may ever be instantiated. Singleton classes complicate testing, +and their presence may indicate a lack of object-oriented design. +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/StandardVariableNames.html b/plugins/InspectionGadgets/src/inspectionDescriptions/StandardVariableNames.html new file mode 100644 index 000000000000..5aabc9e926a5 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/StandardVariableNames.html @@ -0,0 +1,17 @@ + +
+ +This inspection reports on any variables with 'standard' names which are of unexpected types. +Such names may be confusing. Standard names and types are as follows: +
    +
  • i, j, k, m, n - int
  • +
  • f - float
  • +
  • d - double
  • +
  • b - byte
  • +
  • c, ch - char
  • +
  • l - long
  • +
  • s, str - String
  • +
. +
+
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/StaticCollection.html b/plugins/InspectionGadgets/src/inspectionDescriptions/StaticCollection.html new file mode 100644 index 000000000000..cb00a2931825 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/StaticCollection.html @@ -0,0 +1,9 @@ + +
+ +This inspection reports instances of Collection variables declared as static . While +not necessarily a problem, static collections are often causes of memory leaks, and are +therefore prohibited by some coding standards. + +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/StaticImport.html b/plugins/InspectionGadgets/src/inspectionDescriptions/StaticImport.html new file mode 100644 index 000000000000..a132d1d41362 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/StaticImport.html @@ -0,0 +1,7 @@ + +
+ +This inspection reports any instances of static import statements. +Such import statements are not supported under Java 1.4 or earlier JVMs. +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/StaticInheritance.html b/plugins/InspectionGadgets/src/inspectionDescriptions/StaticInheritance.html new file mode 100644 index 000000000000..5859a1fbda00 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/StaticInheritance.html @@ -0,0 +1,9 @@ + +
+ +This inspection reports instances of interfaces which are implemented for no reason other than +access to constants. Such inheritance is often confusing, and may hide important dependency +information. + +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/StaticMethodNamingConvention.html b/plugins/InspectionGadgets/src/inspectionDescriptions/StaticMethodNamingConvention.html new file mode 100644 index 000000000000..b33c1831187d --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/StaticMethodNamingConvention.html @@ -0,0 +1,11 @@ + +
+ +This inspection reports instances of static methods whose names are either too short, too long, or do not follow +the specified regular expression pattern. +

+Use the fields provided below to specify mininum length, maximum length and regular expression expected for static method names. +(Regular expressions are in standard java.util.regex format.) + +

Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/StaticNonFinalField.html b/plugins/InspectionGadgets/src/inspectionDescriptions/StaticNonFinalField.html new file mode 100644 index 000000000000..e6e4d1cda160 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/StaticNonFinalField.html @@ -0,0 +1,6 @@ + +
+ +This inspection reports any instances of non-final static fields. +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/StaticSuite.html b/plugins/InspectionGadgets/src/inspectionDescriptions/StaticSuite.html new file mode 100644 index 000000000000..9344ad9bbae0 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/StaticSuite.html @@ -0,0 +1,8 @@ + +
+ +This inspection reports instances of JUnit test case classes which contain suite() methods which +are not declared static . + +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/StaticVariableInitialization.html b/plugins/InspectionGadgets/src/inspectionDescriptions/StaticVariableInitialization.html new file mode 100644 index 000000000000..a0a1a74a7262 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/StaticVariableInitialization.html @@ -0,0 +1,12 @@ + +
+ +This inspection reports instances of static variables which are not guaranteed to be initialized upon class initialization. +

+Use the checkbox below to indicate whether you want uninitialized primitive fields to be reported. +

+Note: This inspection uses a very conservative dataflow algorithm, and may report static variables +as uninitialized incorrectly. Variables reported as initialized will always be initialized. + +

Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/StaticVariableNamingConvention.html b/plugins/InspectionGadgets/src/inspectionDescriptions/StaticVariableNamingConvention.html new file mode 100644 index 000000000000..9806d0df269c --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/StaticVariableNamingConvention.html @@ -0,0 +1,12 @@ + +
+ +This inspection reports instances of static variables whose names are either too short, too long, or do not follow +the specified regular expression pattern. Constants, i.e. variables of immutable type declared static final, +are not checked by this inspection +

+Use the fields provided below to specify mininum length, maximum length and regular expression expected for static variable names. +(Regular expressions are in standard java.util.regex format.) + +

Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/StaticVariableOfConcreteClass.html b/plugins/InspectionGadgets/src/inspectionDescriptions/StaticVariableOfConcreteClass.html new file mode 100644 index 000000000000..0094629fff5d --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/StaticVariableOfConcreteClass.html @@ -0,0 +1,8 @@ + +
+ +This inspection reports any static variables whose type is declared to be a concrete class, rather than an interface. +Such declarations may represent a failure of abstraction, and may make testing more difficult. +Declarations whose classes come from system or third-party libraries will not be reported by this inspection. +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/StaticVariableUninitializedUse.html b/plugins/InspectionGadgets/src/inspectionDescriptions/StaticVariableUninitializedUse.html new file mode 100644 index 000000000000..64c951102d51 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/StaticVariableUninitializedUse.html @@ -0,0 +1,12 @@ + +
+ + This inspection reports instances of static variables which are read prior to initialization. +

+Use the checkbox below to indicate whether you want uninitialized primitive fields to be reported. +

+Note: This inspection uses a very conservative dataflow algorithm, and may report static variables +used uninitialized incorrectly. Variables reported as initialized will always be initialized. + +

Powered by InspectionGadgets
+ diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/StringBufferMustHaveInitialCapacity.html b/plugins/InspectionGadgets/src/inspectionDescriptions/StringBufferMustHaveInitialCapacity.html new file mode 100644 index 000000000000..816d03115764 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/StringBufferMustHaveInitialCapacity.html @@ -0,0 +1,9 @@ + +
+This inspection reports any attempt to instantiate a new StringBuffer orStringBuilder object without specifying +an initial capacity. If no initial capacity is specified, a default capacity is used, which will rarely be optimal. Failing +to specify initial capacities for StringBuffers may result in performance issues, if space needs to be reallocated and +memory copied when capacity is exceeded. + +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/StringBufferReplaceableByString.html b/plugins/InspectionGadgets/src/inspectionDescriptions/StringBufferReplaceableByString.html new file mode 100644 index 000000000000..c437cdd90da3 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/StringBufferReplaceableByString.html @@ -0,0 +1,8 @@ + +
+ +This inspection reports any variables declared as java.lang.StringBuffer which are +effectively constant, and may thus be declared more efficiently declared as java.lang.String. + +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/StringBufferReplaceableByStringBuilder.html b/plugins/InspectionGadgets/src/inspectionDescriptions/StringBufferReplaceableByStringBuilder.html new file mode 100644 index 000000000000..a51bf7468d15 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/StringBufferReplaceableByStringBuilder.html @@ -0,0 +1,12 @@ + +
+ +This inspection reports any variables declared as java.lang.StringBuffer which may be +more efficiently declared as java.lang.StringBuilder. +java.lang.StringBuilder is a non-thread-safe replacement for +java.lang.StringBuffer, added in J2SDK 5.0. +

+For safety, this inspection is disabled unless the project uses J2SDK 5.0. + +

Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/StringBufferToStringInConcatenation.html b/plugins/InspectionGadgets/src/inspectionDescriptions/StringBufferToStringInConcatenation.html new file mode 100644 index 000000000000..5b2145fd803b --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/StringBufferToStringInConcatenation.html @@ -0,0 +1,9 @@ + +
+ +This inspection reports any instances of StringBuffer.toString() in String concatenations. +In addition to being confusing, this code performs String allocation and copying, which is unnecessary +as of JDK1.4. + +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/StringCompareTo.html b/plugins/InspectionGadgets/src/inspectionDescriptions/StringCompareTo.html new file mode 100644 index 000000000000..3e203936aa87 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/StringCompareTo.html @@ -0,0 +1,8 @@ + +
+ +This inspection reports any call of compareTo() on String objects. 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/StringConcatenation.html b/plugins/InspectionGadgets/src/inspectionDescriptions/StringConcatenation.html new file mode 100644 index 000000000000..b1b266e14c87 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/StringConcatenation.html @@ -0,0 +1,9 @@ + +
+ +This inspection reports any String concatenation (+). Concatenation is usually +incorrect in an internationalized environment, and should be replace by uses of +java.text.MessageFormat or similar classes. + +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/StringConcatenationInLoops.html b/plugins/InspectionGadgets/src/inspectionDescriptions/StringConcatenationInLoops.html new file mode 100644 index 000000000000..6c4316c0f5fc --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/StringConcatenationInLoops.html @@ -0,0 +1,9 @@ + +
+ +This inspection reports any instances of String concatenation in loops. For performance reasons, it +is almost always preferable to replace such concatenation with explicit calls to +StringBuffer.append() + +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/StringConstructor.html b/plugins/InspectionGadgets/src/inspectionDescriptions/StringConstructor.html new file mode 100644 index 000000000000..bf62e158b580 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/StringConstructor.html @@ -0,0 +1,9 @@ + +
+ +This inspection reports any attempt to instantiate a new String object by copying an existing string. +Constructing new String objects in this way is rarely necessary, and may cause performance problems +if done often enough. + +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/StringEquality.html b/plugins/InspectionGadgets/src/inspectionDescriptions/StringEquality.html new file mode 100644 index 000000000000..b27a08b50fa7 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/StringEquality.html @@ -0,0 +1,8 @@ + +
+ +This inspection reports any use of == to test for String equality, +rather than the ".equals()" method. + +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/StringEquals.html b/plugins/InspectionGadgets/src/inspectionDescriptions/StringEquals.html new file mode 100644 index 000000000000..c285f5e1623a --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/StringEquals.html @@ -0,0 +1,8 @@ + +
+ +This inspection reports any call of equals() on String objects. 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/StringEqualsEmptyString.html b/plugins/InspectionGadgets/src/inspectionDescriptions/StringEqualsEmptyString.html new file mode 100644 index 000000000000..154fb14a51e1 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/StringEqualsEmptyString.html @@ -0,0 +1,9 @@ + +
+ +This inspection reports any instances of .equals() being called +to compare a String with an empty string. It is normally more performant to test a String for emptiness +by comparing it's .length() to zero instead. + +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/StringEqualsIgnoreCase.html b/plugins/InspectionGadgets/src/inspectionDescriptions/StringEqualsIgnoreCase.html new file mode 100644 index 000000000000..f1a5c45aee04 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/StringEqualsIgnoreCase.html @@ -0,0 +1,8 @@ + +
+ +This inspection reports any call of equalsIgnoreCase() on String objects. 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/StringReplaceableByStringBuffer.html b/plugins/InspectionGadgets/src/inspectionDescriptions/StringReplaceableByStringBuffer.html new file mode 100644 index 000000000000..891eeee37767 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/StringReplaceableByStringBuffer.html @@ -0,0 +1,9 @@ + +
+ +This inspection reports any variables declared as java.lang.String which are +repeatedly appended to. Such variables may be declared more efficiently declared as java.lang.StringBuffer +or java.lang.StringBuilder. + +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/StringToString.html b/plugins/InspectionGadgets/src/inspectionDescriptions/StringToString.html new file mode 100644 index 000000000000..de1dbbdc1a99 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/StringToString.html @@ -0,0 +1,7 @@ + +
+This inspection reports any to call toString() on a String object. +This is entirely redundant. + +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/StringToUpperWithoutLocale.html b/plugins/InspectionGadgets/src/inspectionDescriptions/StringToUpperWithoutLocale.html new file mode 100644 index 000000000000..8482fc285af3 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/StringToUpperWithoutLocale.html @@ -0,0 +1,8 @@ + +
+ +This inspection reports any call of toUpperCase() or toLowerCase() on String objects. +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/StringTokenizer.html b/plugins/InspectionGadgets/src/inspectionDescriptions/StringTokenizer.html new file mode 100644 index 000000000000..bc7b80fbc2b7 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/StringTokenizer.html @@ -0,0 +1,8 @@ + +
+ +This inspection reports any use of the StringTokenizer class. Many uses of +StringTokenizer are incorrect in an internationalized environment. + +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/SubtractionInCompareTo.html b/plugins/InspectionGadgets/src/inspectionDescriptions/SubtractionInCompareTo.html new file mode 100644 index 000000000000..899107c8e227 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/SubtractionInCompareTo.html @@ -0,0 +1,11 @@ + +
+This inspection reports any instances of subtraction in +compareTo() methods. While it is a common idiom to +use the results of integer subtraction as the return of a compareTo() +method, this construct may cause subtle and difficult bugs in cases of integer overflow. +Comparing the integer values directly and returning -1, 0, or 1 is better practice in almost +all cases. + +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/SwitchStatement.html b/plugins/InspectionGadgets/src/inspectionDescriptions/SwitchStatement.html new file mode 100644 index 000000000000..3a90f051e47d --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/SwitchStatement.html @@ -0,0 +1,6 @@ + +
+This inspection reports any instances of switch statements. +switch statements are often (but not always) indicators of poor object-oriented design. +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/SwitchStatementDensity.html b/plugins/InspectionGadgets/src/inspectionDescriptions/SwitchStatementDensity.html new file mode 100644 index 000000000000..21a5abf6b822 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/SwitchStatementDensity.html @@ -0,0 +1,7 @@ + +
+This inspection reports any instances of switch statements +with too low a ratio of switch labels to executable statements. Such switch statements +may be confusing, and should probably be refactored. +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/SwitchStatementWithConfusingDeclaration.html b/plugins/InspectionGadgets/src/inspectionDescriptions/SwitchStatementWithConfusingDeclaration.html new file mode 100644 index 000000000000..81096a6e4afb --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/SwitchStatementWithConfusingDeclaration.html @@ -0,0 +1,8 @@ + +
+ +This inspection reports any instances of local variables declared in one branch of a switch statement +and used in a different branch. Such declarations can be extremely confusing. + +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/SwitchStatementWithTooFewBranches.html b/plugins/InspectionGadgets/src/inspectionDescriptions/SwitchStatementWithTooFewBranches.html new file mode 100644 index 000000000000..98433c321e60 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/SwitchStatementWithTooFewBranches.html @@ -0,0 +1,10 @@ + +
+ +This inspection reports instances of switch statements with too few case labels. +Such statements may be more clearly expressed as if statements. +

+Use the field provided below to specify the minimum number of case labels expected. + +

Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/SwitchStatementWithTooManyBranches.html b/plugins/InspectionGadgets/src/inspectionDescriptions/SwitchStatementWithTooManyBranches.html new file mode 100644 index 000000000000..97374fa8b2d1 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/SwitchStatementWithTooManyBranches.html @@ -0,0 +1,9 @@ + +
+ +This inspection reports instances of switch statements with too many case labels. +

+Use the field provided below to specify the maximum number of case labels expected. + +

Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/SwitchStatementsWithoutDefault.html b/plugins/InspectionGadgets/src/inspectionDescriptions/SwitchStatementsWithoutDefault.html new file mode 100644 index 000000000000..f756e039162b --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/SwitchStatementsWithoutDefault.html @@ -0,0 +1,6 @@ + +
+This inspection reports any instances of switch statements that do not contain +default labels. +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/SynchronizeOnLock.html b/plugins/InspectionGadgets/src/inspectionDescriptions/SynchronizeOnLock.html new file mode 100644 index 000000000000..229888234643 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/SynchronizeOnLock.html @@ -0,0 +1,10 @@ + +
+ +This inspection reports any instances of synchronized +blocks which lock on instances of java.util.concurrent.locks.Lock. +Such synchronization is almost certainly inadvertant, and appropriate versions of .lock() +and .unlock() should be used instead. + +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/SynchronizeOnNonFinalField.html b/plugins/InspectionGadgets/src/inspectionDescriptions/SynchronizeOnNonFinalField.html new file mode 100644 index 000000000000..5d28b1b16b96 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/SynchronizeOnNonFinalField.html @@ -0,0 +1,9 @@ + +
+ +This inspection reports instances of synchronized statements where the lock expression +is a non-final field. Such statements are unlikely to have useful semantics, as different +threads may be locking on different objects even when operating on the same object. + +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/SynchronizeOnThis.html b/plugins/InspectionGadgets/src/inspectionDescriptions/SynchronizeOnThis.html new file mode 100644 index 000000000000..8d9d95c369d4 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/SynchronizeOnThis.html @@ -0,0 +1,8 @@ + +
+ +This inspection reports any instances of synchronized blocks which use this as their lock +expression. Such blocks, like synchronized methods, make it hard to track just who is locking on a given +object, and make possible "denial of service" attacks on objects. +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/SynchronizedMethod.html b/plugins/InspectionGadgets/src/inspectionDescriptions/SynchronizedMethod.html new file mode 100644 index 000000000000..eb05922f466b --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/SynchronizedMethod.html @@ -0,0 +1,8 @@ + +
+ +This inspection reports any use of the synchronized modifier on methods. Some coding standards +prohibity the use of the synchronized modifier, in favor of synchronized statements. + +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/SystemExit.html b/plugins/InspectionGadgets/src/inspectionDescriptions/SystemExit.html new file mode 100644 index 000000000000..dfd6445003a2 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/SystemExit.html @@ -0,0 +1,7 @@ + +
+This inspection reports any instances of the calls to System.exit(), +Runtime.exit(), or Runtime.halt(). +Calls to these methods make the calling code unportable to most application servers. +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/SystemGC.html b/plugins/InspectionGadgets/src/inspectionDescriptions/SystemGC.html new file mode 100644 index 000000000000..f04f980431ff --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/SystemGC.html @@ -0,0 +1,7 @@ + +
+This inspection reports any call of System.gc() or Runtime.gc(). +While occasionally useful in testing, explicitly triggering garbage collection via System.gc() is almost always +a bad idea in production code, and can result in serious performance problems. +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/SystemGetenv.html b/plugins/InspectionGadgets/src/inspectionDescriptions/SystemGetenv.html new file mode 100644 index 000000000000..4e65924ec7ce --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/SystemGetenv.html @@ -0,0 +1,8 @@ + +
+ +This inspection reports any instances of the calls to System.getenv(). +Calls to System.getenv() are inherently unportable. + +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/SystemOutErr.html b/plugins/InspectionGadgets/src/inspectionDescriptions/SystemOutErr.html new file mode 100644 index 000000000000..fd2ab6ab6a58 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/SystemOutErr.html @@ -0,0 +1,10 @@ + +
+ +This inspection reports any uses System.out or System.err. +These are often temporary +debugging statements, and should probably be either removed from production code, or replaced by a more robust +logging facility. + +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/TailRecursion.html b/plugins/InspectionGadgets/src/inspectionDescriptions/TailRecursion.html new file mode 100644 index 000000000000..0dc9b8278ded --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/TailRecursion.html @@ -0,0 +1,9 @@ + +
+This inspection reports any instances of tail recursion, that is when a method calls itself +as it's last action before returning. Tail recursion can always be replaced by looping, which will be considerably faster. +Some JVMs perform this optimization, while others do not. Thus, tail recursive solutions may have considerably different +performance characteristics on different virtual machines. + +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/TeardownCallsSuperTeardown.html b/plugins/InspectionGadgets/src/inspectionDescriptions/TeardownCallsSuperTeardown.html new file mode 100644 index 000000000000..a1587c920018 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/TeardownCallsSuperTeardown.html @@ -0,0 +1,7 @@ + +
+ +This inspection reports any instances of JUnit classes whose tearDown() method +does not call super.tearDown(). +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/TeardownIsPublicVoidNoArg.html b/plugins/InspectionGadgets/src/inspectionDescriptions/TeardownIsPublicVoidNoArg.html new file mode 100644 index 000000000000..90f1cc418689 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/TeardownIsPublicVoidNoArg.html @@ -0,0 +1,10 @@ + +
+ +This inspection reports any instances of JUnit classes whose tearDown() method +is not declared +public, does not return void, or takes arguments. +Such tearDown() methods are easy to create inadvertantly, +and will not be executed by JUnit tests runners. +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/TestCaseWithConstructor.html b/plugins/InspectionGadgets/src/inspectionDescriptions/TestCaseWithConstructor.html new file mode 100644 index 000000000000..526a226f2dbd --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/TestCaseWithConstructor.html @@ -0,0 +1,8 @@ + +
+ +This inspection reports on JUnit test cases with initialization logic in their constructors. Initialization +of JUnit test cases should be done in setUp() methods instead. + +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/TestCaseWithNoTestMethods.html b/plugins/InspectionGadgets/src/inspectionDescriptions/TestCaseWithNoTestMethods.html new file mode 100644 index 000000000000..64fafb4105c9 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/TestCaseWithNoTestMethods.html @@ -0,0 +1,8 @@ + +
+ +This inspection reports any instances of non-abstract JUnit test cases which do not +contain any test methods. Such test cases usually indicate developer error. + +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/TestMethodIsPublicVoidNoArg.html b/plugins/InspectionGadgets/src/inspectionDescriptions/TestMethodIsPublicVoidNoArg.html new file mode 100644 index 000000000000..825b9c64b1e8 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/TestMethodIsPublicVoidNoArg.html @@ -0,0 +1,10 @@ + +
+ +This inspection reports any instances of methods on JUnit classes whose names start with "test" but +which are not declared +public, do not return void, or which take arguments. +Such test methods are easy to create inadvertantly, +and will not be executed by JUnit tests runners. +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/TestMethodWithoutAssertion.html b/plugins/InspectionGadgets/src/inspectionDescriptions/TestMethodWithoutAssertion.html new file mode 100644 index 000000000000..10bfb2e0d033 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/TestMethodWithoutAssertion.html @@ -0,0 +1,10 @@ + +
+ +This inspection reports any test methods of JUnit test case classes which do not contain +any assertions. Such methods indicate either incomplete or weak test cases. For purposes +of this inspection, assertions include calls to any method whose name begins with "assert" or +"fail". + +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/TextLabelInSwitchStatement.html b/plugins/InspectionGadgets/src/inspectionDescriptions/TextLabelInSwitchStatement.html new file mode 100644 index 000000000000..8a182015bcc8 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/TextLabelInSwitchStatement.html @@ -0,0 +1,16 @@ + +
+This inspection reports any instances of labelled statements inside of switch statements. +While occasionally intended, this construction is often the result of a typo. + +
+    switch(x)
+    {
+        case 1:
+        case2:   //typo!
+        case 3:
+            break;
+    }
+
+
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/ThisEscapedInConstructor.html b/plugins/InspectionGadgets/src/inspectionDescriptions/ThisEscapedInConstructor.html new file mode 100644 index 000000000000..21cb4e0dcf12 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/ThisEscapedInConstructor.html @@ -0,0 +1,10 @@ + +
+ +This inspection reports possible escapes of 'this' during object construction. +Escapes occur when 'this' is used as a method argument or the object of an assignment +in a constructor or initializer. Such escapes may result in subtle bugs, as the object is now available in a context +in which it is not guaranteed to be initialize. +
Powered by InspectionGadgets
+ + diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/ThreadDeathRethrown.html b/plugins/InspectionGadgets/src/inspectionDescriptions/ThreadDeathRethrown.html new file mode 100644 index 000000000000..5faa7421ca3f --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/ThreadDeathRethrown.html @@ -0,0 +1,6 @@ + +
+This inspection reports any instances of try statements which catch +java.lang.ThreadDeath which do not rethrow the exception. +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/ThreadDumpStack.html b/plugins/InspectionGadgets/src/inspectionDescriptions/ThreadDumpStack.html new file mode 100644 index 000000000000..6057047e4e6a --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/ThreadDumpStack.html @@ -0,0 +1,8 @@ + +
+This inspection reports any uses Thread.dumpStack(). +These are often temporary debugging statements, and should probably be either removed from production code, +or replaced by a more robust logging facility. + +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/ThreadRun.html b/plugins/InspectionGadgets/src/inspectionDescriptions/ThreadRun.html new file mode 100644 index 000000000000..79500502fb0a --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/ThreadRun.html @@ -0,0 +1,8 @@ + +
+ +This inspection reports any calls to run() on java.lang.Thread or any of it's subclasses. +While occasionally intended, this is usually a mistake, with start() intended instead. + +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/ThreadStartInConstruction.html b/plugins/InspectionGadgets/src/inspectionDescriptions/ThreadStartInConstruction.html new file mode 100644 index 000000000000..b95cf1227e30 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/ThreadStartInConstruction.html @@ -0,0 +1,10 @@ + +
+ +This inspection reports any calls to start() on java.lang.Thread +or any of it's subclasses during object construction. While occasionally useful, this construct should be avoided due +to inheritance issues. Subclasses of a class which lauches a thread during object construction will not have finished +any initialization logic of their own before the thread has launched. + +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/ThreeNegationsPerMethod.html b/plugins/InspectionGadgets/src/inspectionDescriptions/ThreeNegationsPerMethod.html new file mode 100644 index 000000000000..4830c0498e82 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/ThreeNegationsPerMethod.html @@ -0,0 +1,8 @@ + +
+ +This inspection reports methods with three or more negation operations (! or !=). +Such methods may be unnecessarily confusing. + +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/ThrowCaughtLocally.html b/plugins/InspectionGadgets/src/inspectionDescriptions/ThrowCaughtLocally.html new file mode 100644 index 000000000000..de865a785b0a --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/ThrowCaughtLocally.html @@ -0,0 +1,9 @@ + +
+ +This inspection reports any instances of throw statements whose exceptions are always +caught by containing try statements. Using throw +statements as a "goto" to change the local flow of control is both confusing and likely to have poor performance. + +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/ThrowFromFinallyBlock.html b/plugins/InspectionGadgets/src/inspectionDescriptions/ThrowFromFinallyBlock.html new file mode 100644 index 000000000000..4c61f89d9279 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/ThrowFromFinallyBlock.html @@ -0,0 +1,9 @@ + +
+ +This inspection reports any instances of throw statements inside of finally +blocks. While occasionally intended, such throw statements may mask exceptions thrown, and +tremendously complicate debugging. + +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/ThrowablePrintStackTrace.html b/plugins/InspectionGadgets/src/inspectionDescriptions/ThrowablePrintStackTrace.html new file mode 100644 index 000000000000..98018ae3ed36 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/ThrowablePrintStackTrace.html @@ -0,0 +1,8 @@ + +
+This inspection reports any uses Throwable.printStackTrace() without arguments. +These are often temporary debugging statements, and should probably be either removed from production code, +or replaced by a more robust logging facility. + +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/TimeToString.html b/plugins/InspectionGadgets/src/inspectionDescriptions/TimeToString.html new file mode 100644 index 000000000000..fe3a31c515c7 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/TimeToString.html @@ -0,0 +1,8 @@ + +
+ +This inspection reports any call of toString() on java.sql.Time objects. 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/TooBroadCatch.html b/plugins/InspectionGadgets/src/inspectionDescriptions/TooBroadCatch.html new file mode 100644 index 000000000000..3fd54f7347b9 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/TooBroadCatch.html @@ -0,0 +1,8 @@ + +
+ +This inspection reports instances of catch blocks which have parameters which are more generic than the +exceptions thrown by the corresponding try block. + +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/TransientFieldInNonSerializableClass.html b/plugins/InspectionGadgets/src/inspectionDescriptions/TransientFieldInNonSerializableClass.html new file mode 100644 index 000000000000..5c1a08a3ab46 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/TransientFieldInNonSerializableClass.html @@ -0,0 +1,6 @@ + +
+ +This inspection reports any instances of transient fields in non-Serializable classes. +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/TrivialIf.html b/plugins/InspectionGadgets/src/inspectionDescriptions/TrivialIf.html new file mode 100644 index 000000000000..67805ee716e2 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/TrivialIf.html @@ -0,0 +1,22 @@ + +
+ +This inspection reports instances of if statements which can be simplified to single assignment or +return statements. For example: +
+    if(foo())
+    {
+       return true;
+    }
+    else
+    {
+       return false;
+    }
+
+can be simplified to +
+    return foo();
+
+
+
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/TrivialStringConcatenation.html b/plugins/InspectionGadgets/src/inspectionDescriptions/TrivialStringConcatenation.html new file mode 100644 index 000000000000..fe1a5275da99 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/TrivialStringConcatenation.html @@ -0,0 +1,9 @@ + +
+ +This inspection reports instances of string concatenation where one of the arguments is the +empty string. Such concatenation is unnecessary and inefficient, particularly when used as +an idiom for formatting non-String objects or primitives into Strings. + +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/TypeParameterExtendsObject.html b/plugins/InspectionGadgets/src/inspectionDescriptions/TypeParameterExtendsObject.html new file mode 100644 index 000000000000..5d88f6fae732 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/TypeParameterExtendsObject.html @@ -0,0 +1,7 @@ + +
+ +This inspection reports any type parameters explicitly declared to extend java.lang.Object. + +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/UncheckedExceptionClass.html b/plugins/InspectionGadgets/src/inspectionDescriptions/UncheckedExceptionClass.html new file mode 100644 index 000000000000..f6e9ae77f7be --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/UncheckedExceptionClass.html @@ -0,0 +1,8 @@ + +
+ +This inspection reports any instances of unchecked exception classes (i.e. subclasses of RuntimeException). +Certain coding standards require that all user-defined exception classes be checked. + +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/UnconditionalWait.html b/plugins/InspectionGadgets/src/inspectionDescriptions/UnconditionalWait.html new file mode 100644 index 000000000000..01ae2e4da838 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/UnconditionalWait.html @@ -0,0 +1,14 @@ + +
+ +This inspection reports any instances of .wait() +being called unconditionally within a synchronized context. +Normally, .wait() is +used to block a thread until some condition is true. If .wait() +is called unconditionally, that often indicates that the condition was checked before a lock was +acquired. In that case a data race may occur, with the condition becoming true between the time +it was checked and the time the lock was acquired. While constructs found by this inspection +are not necessarily incorrect, they are certainly worth examining. + +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/UnnecessarilyQualifiedStaticUsage.html b/plugins/InspectionGadgets/src/inspectionDescriptions/UnnecessarilyQualifiedStaticUsage.html new file mode 100644 index 000000000000..d06d4d1d6a10 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/UnnecessarilyQualifiedStaticUsage.html @@ -0,0 +1,8 @@ + +
+ +This inspection reports any instances of calls to static methods or accesses of static fields +on the current class which are qualified with the class name. Such qualification is unnecessary, +and may be safely removed. +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/UnnecessaryBlockStatement.html b/plugins/InspectionGadgets/src/inspectionDescriptions/UnnecessaryBlockStatement.html new file mode 100644 index 000000000000..5b5a41b9086b --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/UnnecessaryBlockStatement.html @@ -0,0 +1,10 @@ + +
+ +This inspection reports instances of code blocks which are unnecessary to the semantics of the program, and can +be replaced by their contents. Code blocks which are the bodies of if, do, +while or for statements will not be reported by this +inspection. + +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/UnnecessaryBoxing.html b/plugins/InspectionGadgets/src/inspectionDescriptions/UnnecessaryBoxing.html new file mode 100644 index 000000000000..20a07bc770e8 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/UnnecessaryBoxing.html @@ -0,0 +1,9 @@ + +
+ +This inspection reports any instances of "boxing", e.g. wrapping of primitive values in objects. +Boxing is unnecessary under Java 5.0, and can be safely removed. +

+For safety, this inspection is disabled unless the project uses J2SDK 5.0. +

Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/UnnecessaryConditionalExpression.html b/plugins/InspectionGadgets/src/inspectionDescriptions/UnnecessaryConditionalExpression.html new file mode 100644 index 000000000000..7fb7457c99ab --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/UnnecessaryConditionalExpression.html @@ -0,0 +1,8 @@ + +
+ +This inspection reports any instances of conditional expressions of the form +condition?true:false or condition?false:true. These expressions may be safely simplified +to condition or !condition, respectively. +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/UnnecessaryContinue.html b/plugins/InspectionGadgets/src/inspectionDescriptions/UnnecessaryContinue.html new file mode 100644 index 000000000000..20366eacd03a --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/UnnecessaryContinue.html @@ -0,0 +1,8 @@ + +
+ +This inspection reports on any unnecessary continue statements at the end of loops. +These may be safely removed. + +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/UnnecessaryDefault.html b/plugins/InspectionGadgets/src/inspectionDescriptions/UnnecessaryDefault.html new file mode 100644 index 000000000000..bca2d53f370f --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/UnnecessaryDefault.html @@ -0,0 +1,10 @@ + +
+ +This inspection reports instances of switch statements with +default branches which +can never be taken. At present, such branches are only marked for switch statements +over enumerated types all of whose instances have corresponding case branches. + +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/UnnecessaryFinalOnLocalVariable.html b/plugins/InspectionGadgets/src/inspectionDescriptions/UnnecessaryFinalOnLocalVariable.html new file mode 100644 index 000000000000..56fbe2ef329b --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/UnnecessaryFinalOnLocalVariable.html @@ -0,0 +1,7 @@ + +
+ +This inspection reports any instances of local variables declared final unnecessarily. +Some coding standards frown on such variables, for reasons of terseness. +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/UnnecessaryFinalOnParameter.html b/plugins/InspectionGadgets/src/inspectionDescriptions/UnnecessaryFinalOnParameter.html new file mode 100644 index 000000000000..b1482c787d10 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/UnnecessaryFinalOnParameter.html @@ -0,0 +1,8 @@ + +
+ +This inspection reports any instances of method parameters declared final unnecessarily. +Some coding standards frown on such parameters, so as to have shorter and more +understandable parameter lists. +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/UnnecessaryFullyQualifiedName.html b/plugins/InspectionGadgets/src/inspectionDescriptions/UnnecessaryFullyQualifiedName.html new file mode 100644 index 000000000000..456b7ef4a71b --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/UnnecessaryFullyQualifiedName.html @@ -0,0 +1,8 @@ + +
+ +This inspection reports on any instances of fully qualified class names which can be shortened. The quick fix for this +inspection will shorten the fully qualified names, adding import statments as necessary. + +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/UnnecessaryInterfaceModifier.html b/plugins/InspectionGadgets/src/inspectionDescriptions/UnnecessaryInterfaceModifier.html new file mode 100644 index 000000000000..6298ca8dfb72 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/UnnecessaryInterfaceModifier.html @@ -0,0 +1,7 @@ + +
+ +This inspection reports on any redundant modifiers on interfaces or interface components. + +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/UnnecessaryLabelOnBreakStatement.html b/plugins/InspectionGadgets/src/inspectionDescriptions/UnnecessaryLabelOnBreakStatement.html new file mode 100644 index 000000000000..478d91f82c9f --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/UnnecessaryLabelOnBreakStatement.html @@ -0,0 +1,8 @@ + +
+ +This inspection reports any instances of break statements with unnecessary +labels. + +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/UnnecessaryLabelOnContinueStatement.html b/plugins/InspectionGadgets/src/inspectionDescriptions/UnnecessaryLabelOnContinueStatement.html new file mode 100644 index 000000000000..c4efed022778 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/UnnecessaryLabelOnContinueStatement.html @@ -0,0 +1,8 @@ + +
+ +This inspection reports any instances of continue statements with unnecessary +labels. + +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/UnnecessaryParentheses.html b/plugins/InspectionGadgets/src/inspectionDescriptions/UnnecessaryParentheses.html new file mode 100644 index 000000000000..b8605cef9ae2 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/UnnecessaryParentheses.html @@ -0,0 +1,7 @@ + +
+ +This inspection reports on any instance of unnecessary parentheses. + +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/UnnecessaryQualifierForThis.html b/plugins/InspectionGadgets/src/inspectionDescriptions/UnnecessaryQualifierForThis.html new file mode 100644 index 000000000000..1034c1214f9b --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/UnnecessaryQualifierForThis.html @@ -0,0 +1,9 @@ + +
+ +This inspection reports on any unnecessary qualification of this in the code. +Using a qualifier on this to +disambiguity a code reference may easily become unnecessary via automatic refactorings, and should be deleted for clarity. + +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/UnnecessaryReturn.html b/plugins/InspectionGadgets/src/inspectionDescriptions/UnnecessaryReturn.html new file mode 100644 index 000000000000..da1e72f2db2a --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/UnnecessaryReturn.html @@ -0,0 +1,8 @@ + +
+ +This inspection reports on any unnecessary return statements at the end of constructors and methods returning +void. These may be safely removed. + +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/UnnecessarySemicolon.html b/plugins/InspectionGadgets/src/inspectionDescriptions/UnnecessarySemicolon.html new file mode 100644 index 000000000000..221d3741aec4 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/UnnecessarySemicolon.html @@ -0,0 +1,8 @@ + +
+ +This inspection reports on any unnecessary semicolons, whether between class members, inside block statements, or after +class definitions. While valid Java, these semicolons are redundant, and may be removed. + +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/UnnecessarySuperConstructor.html b/plugins/InspectionGadgets/src/inspectionDescriptions/UnnecessarySuperConstructor.html new file mode 100644 index 000000000000..56245b22e32b --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/UnnecessarySuperConstructor.html @@ -0,0 +1,7 @@ + +
+This inspection reports any no-argument calls to a superclass +constructor as the first call of a constructor. Such calls are unnecessary, and may be removed. + +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/UnnecessaryTemporaryOnConversionFromString.html b/plugins/InspectionGadgets/src/inspectionDescriptions/UnnecessaryTemporaryOnConversionFromString.html new file mode 100644 index 000000000000..9280aa96b072 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/UnnecessaryTemporaryOnConversionFromString.html @@ -0,0 +1,10 @@ + +
+ +This inspection reports any instances of unnecessary creation of temporary objects when converting +from Strings to primitive types. For example, new Integer("3").intValue() +would be reported, and could +be automatically converted to Integer.valueOf("3"). + +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/UnnecessaryTemporaryOnConversionToString.html b/plugins/InspectionGadgets/src/inspectionDescriptions/UnnecessaryTemporaryOnConversionToString.html new file mode 100644 index 000000000000..05bca6e065cd --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/UnnecessaryTemporaryOnConversionToString.html @@ -0,0 +1,9 @@ + +
+ +This inspection reports any instances of unnecessary creation of temporary objects when converting +from primitive types to Strings. For example, new Integer(3).toString() would be reported, and could +be automatically converted to Integer.toString(3). + +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/UnnecessaryThis.html b/plugins/InspectionGadgets/src/inspectionDescriptions/UnnecessaryThis.html new file mode 100644 index 000000000000..4a1f55a4e06b --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/UnnecessaryThis.html @@ -0,0 +1,10 @@ + +
+ +This inspection reports on any unnecessary uses of this in the code. +Using this to +disambiguity a code reference may easily become unnecessary via automatic refactorings, and is discouraged +by in many coding styles. + +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/UnnecessaryUnboxing.html b/plugins/InspectionGadgets/src/inspectionDescriptions/UnnecessaryUnboxing.html new file mode 100644 index 000000000000..c7625a83595c --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/UnnecessaryUnboxing.html @@ -0,0 +1,9 @@ + +
+ +This inspection reports any instances of "unboxing", e.g. explicit unwrapping of wrapped primitive values. +Unboxing is unnecessary under Java 5.0, and can be safely removed. +

+For safety, this inspection is disabled unless the project uses J2SDK 5.0. +

Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/UnqualifiedStaticUsage.html b/plugins/InspectionGadgets/src/inspectionDescriptions/UnqualifiedStaticUsage.html new file mode 100644 index 000000000000..018a79e7ceda --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/UnqualifiedStaticUsage.html @@ -0,0 +1,8 @@ + +
+ +This inspection reports any instances of static method calls or field accesse which are not qualified +with the class name of the static method. This is legal if the static method or field is in +the same class as the call, but may be confusing. +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/UnusedCatchParameter.html b/plugins/InspectionGadgets/src/inspectionDescriptions/UnusedCatchParameter.html new file mode 100644 index 000000000000..595916a27801 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/UnusedCatchParameter.html @@ -0,0 +1,8 @@ + +
+ +This inspection reports any catch parameters that are unused in their +corresponding blocks. + +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/UnusedImport.html b/plugins/InspectionGadgets/src/inspectionDescriptions/UnusedImport.html new file mode 100644 index 000000000000..460cb787dc5f --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/UnusedImport.html @@ -0,0 +1,9 @@ + +
+ +This inspection reports any import statements that are unused. Since IDEA can automatically +detect and fix such statements with it's "Optimize Imports" command, this inspection is mostly useful +for off-line reporting on code bases that you don't intend to change. + +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/UnusedLabel.html b/plugins/InspectionGadgets/src/inspectionDescriptions/UnusedLabel.html new file mode 100644 index 000000000000..0f6beff4f78d --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/UnusedLabel.html @@ -0,0 +1,7 @@ + +
+ +This inspection reports any instances of unused code labels. + +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/UpperCaseFieldNameNotConstant.html b/plugins/InspectionGadgets/src/inspectionDescriptions/UpperCaseFieldNameNotConstant.html new file mode 100644 index 000000000000..0e601da45e50 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/UpperCaseFieldNameNotConstant.html @@ -0,0 +1,9 @@ + +
+ +This inspection reports any instances of nonstatic nonfinal +fields whose names are all upper-case. Such fields may cause confusion by breaking a common naming convention, and +are often the result of developer error. + +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/UseOfSunClasses.html b/plugins/InspectionGadgets/src/inspectionDescriptions/UseOfSunClasses.html new file mode 100644 index 000000000000..3ce9d065fa9d --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/UseOfSunClasses.html @@ -0,0 +1,7 @@ + +
+ +This inspection reports any uses of classes from the sun.* hierarchy. +Such classes are non-portable between different JVM's. +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/UtilityClass.html b/plugins/InspectionGadgets/src/inspectionDescriptions/UtilityClass.html new file mode 100644 index 000000000000..148ce51dfd09 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/UtilityClass.html @@ -0,0 +1,8 @@ + +
+ +This inspection reports any instances of utility classes. +Utility classes have all fields and methods declared static, and their +presence may indicate a lack of object-oriented design. +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/UtilityClassWithPublicConstructor.html b/plugins/InspectionGadgets/src/inspectionDescriptions/UtilityClassWithPublicConstructor.html new file mode 100644 index 000000000000..40a0914a05cc --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/UtilityClassWithPublicConstructor.html @@ -0,0 +1,8 @@ + +
+ +This inspection reports any instances of utility classes with public constructors. Utility +classes have all fields and methods declared 'static'. Giving such classes a public +constructor is confusing, and may lead to the class being inadvertantly instantiated. +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/UtilityClassWithoutPrivateConstructor.html b/plugins/InspectionGadgets/src/inspectionDescriptions/UtilityClassWithoutPrivateConstructor.html new file mode 100644 index 000000000000..e2dbdf7b5840 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/UtilityClassWithoutPrivateConstructor.html @@ -0,0 +1,8 @@ + +
+ +This inspection reports any instances of utility classes which do not have private constructors. +Utility classes have all fields and methods declared static . Giving such classes a private +constructor prevents them from being inadvertantly instantiated. +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/VarargParameter.html b/plugins/InspectionGadgets/src/inspectionDescriptions/VarargParameter.html new file mode 100644 index 000000000000..19483d3d53d9 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/VarargParameter.html @@ -0,0 +1,7 @@ + +
+ +This inspection reports any instances of methods taking variable numbers of parameters. +Such methods are not supported under Java 1.4 or earlier JVMs. +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/VolatileLongOrDoubleField.html b/plugins/InspectionGadgets/src/inspectionDescriptions/VolatileLongOrDoubleField.html new file mode 100644 index 000000000000..a01dd13852b4 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/VolatileLongOrDoubleField.html @@ -0,0 +1,9 @@ + +
+ +This inspection reports fields of tlong or double +which are declared as volatile. While Java specifies that reads +and writes from such fields are atomic, many JVM's have violated this specification. Unless you +are certain of your JVM, it is better to syncronized access to such fields rather than declare them volatile. +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/WaitNotInLoop.html b/plugins/InspectionGadgets/src/inspectionDescriptions/WaitNotInLoop.html new file mode 100644 index 000000000000..cbbb0b4ebbd3 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/WaitNotInLoop.html @@ -0,0 +1,9 @@ + +
+ +This inspection reports on any call to wait() not made inside a loop. wait() is normally +used to suspend a thread until a condition is true, and that condition should be checked after the wait() +returns. A loop is the clearest way to acheive this. + +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/WaitNotInSynchronizedContext.html b/plugins/InspectionGadgets/src/inspectionDescriptions/WaitNotInSynchronizedContext.html new file mode 100644 index 000000000000..827655d5c70d --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/WaitNotInSynchronizedContext.html @@ -0,0 +1,10 @@ + +
+ +This inspection reports on any call to wait() not made inside a corresponding synchronized +statement or synchronized method. Calling wait() on an object +without holding a lock on that object will result in an IllegalMonitorStateException being thrown. +Such a construct is not necessarily an error, as the necessary lock may be acquired before +the containing method is called, but it's worth looking at. +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/WaitWhileHoldingTwoLocks.html b/plugins/InspectionGadgets/src/inspectionDescriptions/WaitWhileHoldingTwoLocks.html new file mode 100644 index 000000000000..e15b6e9f8567 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/WaitWhileHoldingTwoLocks.html @@ -0,0 +1,9 @@ + +
+ +This inspection reports any instances of .wait() +being called while the current thread is holding two locks. Since the call to .wait() +only frees locks on the it's target, waiting with two locks held can easily lead to deadlock. + +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/WhileLoopSpinsOnField.html b/plugins/InspectionGadgets/src/inspectionDescriptions/WhileLoopSpinsOnField.html new file mode 100644 index 000000000000..4fbca66d6d33 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/WhileLoopSpinsOnField.html @@ -0,0 +1,10 @@ + +
+ +This inspection reports on any instances of while loops which spin on the +value of a non-volatile field, waiting for it to be changed by another thread. In addition to being extremely CPU intensive, such +loops are likely have different semantics than intended, as the Java Memory Model allows such field accesses +to be hoisted out of the loop, causing the loop to never complete even if another thread does change the +field's value. +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/ZeroLengthArrayInitialization.html b/plugins/InspectionGadgets/src/inspectionDescriptions/ZeroLengthArrayInitialization.html new file mode 100644 index 000000000000..4f6a07e25e10 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/ZeroLengthArrayInitialization.html @@ -0,0 +1,11 @@ + +
+ +This inspection reports on allocations of arrays with known lengths of zero. Since array lengths in +Java are non-modifiable, it is almost always possible to share zero-length arrays, rather than repeatedly +allocating new zero-length arrays. Such sharing may provide useful optimizations in program runtime or +footprint. Note that this inspection does not report zero-length arrays allocated as static final fields, +as it is assumed that those arrays are being used to implement array sharing. + +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/test/TopLevelClass.java b/plugins/InspectionGadgets/test/TopLevelClass.java new file mode 100644 index 000000000000..d3bea422913c --- /dev/null +++ b/plugins/InspectionGadgets/test/TopLevelClass.java @@ -0,0 +1,10 @@ + +public class TopLevelClass +{ + private int m_foo = 0; + public static void main(String[] args) + { + + + } +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/abstraction/CastToConcreteClassInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/abstraction/CastToConcreteClassInspection.java new file mode 100644 index 000000000000..ca3909ceefba --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/abstraction/CastToConcreteClassInspection.java @@ -0,0 +1,15 @@ +package com.siyeh.igtest.abstraction; + +import com.siyeh.igtest.classlayout.AbstractClass; +import com.siyeh.igtest.classlayout.ConstantInterface; + + +public class CastToConcreteClassInspection +{ + public static void main(String[] args) + { + Object foo = null; + final AbstractClass abstractFoo = (AbstractClass)foo; + final ConstantInterface interfaceFoo = (ConstantInterface)foo; + } +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/abstraction/ClassReferencesSubclassInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/abstraction/ClassReferencesSubclassInspection.java new file mode 100644 index 000000000000..318133eae600 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/abstraction/ClassReferencesSubclassInspection.java @@ -0,0 +1,5 @@ +package com.siyeh.igtest.abstraction; + +public class ClassReferencesSubclassInspection extends ClassReferencesSubclassInspectionParent +{ +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/abstraction/ClassReferencesSubclassInspectionParent.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/abstraction/ClassReferencesSubclassInspectionParent.java new file mode 100644 index 000000000000..66676c4e96de --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/abstraction/ClassReferencesSubclassInspectionParent.java @@ -0,0 +1,14 @@ +package com.siyeh.igtest.abstraction; + + + + +public abstract class ClassReferencesSubclassInspectionParent +{ + public ClassReferencesSubclassInspection child; + + void foo() + { + ClassReferencesSubclassInspection child; + } +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/abstraction/DeclareCollectionsAsInterfaceInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/abstraction/DeclareCollectionsAsInterfaceInspection.java new file mode 100644 index 000000000000..55854e8f3460 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/abstraction/DeclareCollectionsAsInterfaceInspection.java @@ -0,0 +1,35 @@ +package com.siyeh.igtest.abstraction; + +import java.util.*; + +public class DeclareCollectionsAsInterfaceInspection +{ + private HashSet m_setThree = new HashSet(2); + private HashSet m_setOne = new HashSet(2); + private Set m_setTwo = new HashSet(2); + + public DeclareCollectionsAsInterfaceInspection() + { + m_setOne.add("foo"); + m_setTwo.add("bar"); + } + + public void fooBar() + { + final HashSet set1 = new HashSet(2); + final Set set2 = new HashSet(2); + set1.add("foo"); + set2.add("bar"); + } + + public void fooBaz(TreeSet set1, Set set2) + { + set1.add("foo"); + set2.add("bar"); + } + + public HashSet fooBaz() + { + return new HashSet(); + } +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/abstraction/InstanceVariableOfConcreteClassInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/abstraction/InstanceVariableOfConcreteClassInspection.java new file mode 100644 index 000000000000..c3a71dbce912 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/abstraction/InstanceVariableOfConcreteClassInspection.java @@ -0,0 +1,21 @@ +package com.siyeh.igtest.abstraction; + +import com.siyeh.igtest.classlayout.AbstractClass; +import com.siyeh.igtest.classlayout.ConstantInterface; + +public class InstanceVariableOfConcreteClassInspection +{ + private Object foo = barangus(); + private AbstractClass bar = (AbstractClass)barangus(); + private ConstantInterface baz = (ConstantInterface)barangus(); + + public static void main(String[] args) + { + + } + + private static Object barangus() + { + return null; + } +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/abstraction/InstanceofInterfacesInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/abstraction/InstanceofInterfacesInspection.java new file mode 100644 index 000000000000..7bee93d7cded --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/abstraction/InstanceofInterfacesInspection.java @@ -0,0 +1,25 @@ +package com.siyeh.igtest.abstraction; + +import com.siyeh.igtest.classlayout.AbstractClass; +import com.siyeh.igtest.classlayout.ConstantInterface; + + +public class InstanceofInterfacesInspection +{ + public static void main(String[] args) + { + final Object foo = barangus(); + if(foo instanceof AbstractClass) + { + return; + } + if(foo instanceof ConstantInterface) + { + return; + } + } + + private static Object barangus() + { + } +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/abstraction/InstanceofThisInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/abstraction/InstanceofThisInspection.java new file mode 100644 index 000000000000..7390b5cf8868 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/abstraction/InstanceofThisInspection.java @@ -0,0 +1,13 @@ +package com.siyeh.igtest.abstraction; + +public abstract class InstanceofThisInspection +{ + public void foo(String[] args) + { + if(this instanceof InstanceofThisInspectionChild) + { + return; + } + } + +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/abstraction/InstanceofThisInspectionChild.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/abstraction/InstanceofThisInspectionChild.java new file mode 100644 index 000000000000..b77d9615b5d3 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/abstraction/InstanceofThisInspectionChild.java @@ -0,0 +1,7 @@ +package com.siyeh.igtest.abstraction; + +public class InstanceofThisInspectionChild extends InstanceofThisInspection{ + public InstanceofThisInspectionChild(){ + super(); + } +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/abstraction/Interface.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/abstraction/Interface.java new file mode 100644 index 000000000000..f1eab98ca081 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/abstraction/Interface.java @@ -0,0 +1,5 @@ +package com.siyeh.igtest.abstraction; + +public interface Interface { + void baz(); +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/abstraction/LocalVariableOfConcreteClassInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/abstraction/LocalVariableOfConcreteClassInspection.java new file mode 100644 index 000000000000..44b2aaf97644 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/abstraction/LocalVariableOfConcreteClassInspection.java @@ -0,0 +1,19 @@ +package com.siyeh.igtest.abstraction; + +import com.siyeh.igtest.classlayout.AbstractClass; +import com.siyeh.igtest.classlayout.ConstantInterface; + + +public class LocalVariableOfConcreteClassInspection +{ + public static void main(String[] args) + { + Object foo = barangus(); + AbstractClass bar = (AbstractClass)barangus(); + ConstantInterface baz = (ConstantInterface)barangus(); + } + + private static Object barangus() + { + } +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/abstraction/MagicNumberInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/abstraction/MagicNumberInspection.java new file mode 100644 index 000000000000..fe2695a10d09 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/abstraction/MagicNumberInspection.java @@ -0,0 +1,20 @@ +package com.siyeh.igtest.abstraction; + +import java.util.Set; +import java.util.HashSet; + +public class MagicNumberInspection +{ + private static final int s_foo = 400; + private int m_foo = 400; + private static int s_foo2 = 400; + private final int m_foo2 = 400; + private static final Set s_set = new HashSet(400); + + public static void main(String[] args) + { + final Set set = new HashSet(400); + set.toString(); + } + +} \ No newline at end of file diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/abstraction/MethodReturnOfConcreteClassInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/abstraction/MethodReturnOfConcreteClassInspection.java new file mode 100644 index 000000000000..fb19e9fc9013 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/abstraction/MethodReturnOfConcreteClassInspection.java @@ -0,0 +1,23 @@ +package com.siyeh.igtest.abstraction; + +import com.siyeh.igtest.classlayout.AbstractClass; +import com.siyeh.igtest.classlayout.ConstantInterface; + +public class MethodReturnOfConcreteClassInspection +{ + + private Object foo(Object bar) + { + return null; + } + + private static AbstractClass barangus(AbstractClass baz) + { + return null; + } + + private static ConstantInterface barangus(ConstantInterface baz) + { + return null; + } +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/abstraction/OverlyStrongTypeCastInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/abstraction/OverlyStrongTypeCastInspection.java new file mode 100644 index 000000000000..0b03087442f5 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/abstraction/OverlyStrongTypeCastInspection.java @@ -0,0 +1,17 @@ +package com.siyeh.igtest.abstraction; + +import java.util.ArrayList; +import java.util.List; +import java.util.AbstractList; + + +public class OverlyStrongTypeCastInspection +{ + public static void main(String[] args) + { + List bar = new ArrayList(); + AbstractList foo = (ArrayList) bar; + List foo2 = (List) bar; + double x = (double)3.0f; + } +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/abstraction/ParameterOfConcreteClassInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/abstraction/ParameterOfConcreteClassInspection.java new file mode 100644 index 000000000000..aef80ccc2eb5 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/abstraction/ParameterOfConcreteClassInspection.java @@ -0,0 +1,24 @@ +package com.siyeh.igtest.abstraction; + +import com.siyeh.igtest.classlayout.AbstractClass; +import com.siyeh.igtest.classlayout.ConstantInterface; + +public class ParameterOfConcreteClassInspection +{ + + + private Object foo(Object bar) + { + return null; + } + + private static AbstractClass barangus(AbstractClass baz) + { + return null; + } + + private static ConstantInterface barangus(ConstantInterface baz) + { + return null; + } +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/abstraction/PublicMethodNotExposedInInterface.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/abstraction/PublicMethodNotExposedInInterface.java new file mode 100644 index 000000000000..9dbe2de1031a --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/abstraction/PublicMethodNotExposedInInterface.java @@ -0,0 +1,20 @@ +package com.siyeh.igtest.abstraction; + +public class PublicMethodNotExposedInInterface implements Interface { + public void foo() { + + } + + public void baz() { + bar2(); + } + + public static void bar() { + + } + + private void bar2() { + + } + +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/abstraction/PublicMethodNotExposedInInterfaceEnum.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/abstraction/PublicMethodNotExposedInInterfaceEnum.java new file mode 100644 index 000000000000..73cd3a454d2d --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/abstraction/PublicMethodNotExposedInInterfaceEnum.java @@ -0,0 +1,9 @@ +package com.siyeh.igtest.abstraction; + +public enum PublicMethodNotExposedInInterfaceEnum implements Interface { + a, b, c; + + public void baz() { + } + +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/abstraction/StaticVariableOfConcreteClassInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/abstraction/StaticVariableOfConcreteClassInspection.java new file mode 100644 index 000000000000..8bcc105212a7 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/abstraction/StaticVariableOfConcreteClassInspection.java @@ -0,0 +1,21 @@ +package com.siyeh.igtest.abstraction; + +import com.siyeh.igtest.classlayout.AbstractClass; +import com.siyeh.igtest.classlayout.ConstantInterface; + +public class StaticVariableOfConcreteClassInspection +{ + private static Object foo = barangus(); + private static AbstractClass bar = (AbstractClass)barangus(); + private static ConstantInterface baz = (ConstantInterface)barangus(); + + public static void main(String[] args) + { + + } + + private static Object barangus() + { + return null; + } +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/abstraction/X.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/abstraction/X.java new file mode 100644 index 000000000000..e59756d3a506 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/abstraction/X.java @@ -0,0 +1,25 @@ +package com.siyeh.igtest.abstraction; + +public enum X implements Y { + ONE(0x101, "One"), + TWO(0x102, "Two"), + THREE(0x103, "Three"); + + private int value; + + private String description; + + X(int value, String description) { + this.value = value; + this.description = description; + } + + public int getValue() { + return value; + } + + public String toString() { + return description; + } + +} \ No newline at end of file diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/abstraction/Y.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/abstraction/Y.java new file mode 100644 index 000000000000..cef7b05229d8 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/abstraction/Y.java @@ -0,0 +1,5 @@ +package com.siyeh.igtest.abstraction; + +public interface Y { + int getValue(); +} \ No newline at end of file diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/ArrayTest.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/ArrayTest.java new file mode 100644 index 000000000000..5c8a1df752c6 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/ArrayTest.java @@ -0,0 +1,16 @@ +package com.siyeh.igtest.bugs; +public class ArrayTest { + + private String[] array; // <-- warning! + + public void setArray(String[] array) { + this.array = (String[]) array.clone(); + } + + void doSomething() { + for (int x = 0; x < array.length; x++) { + System.out.println(array[x]); + } + } +} + diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/AssignmentToNullInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/AssignmentToNullInspection.java new file mode 100644 index 000000000000..2c89c12f4d20 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/AssignmentToNullInspection.java @@ -0,0 +1,26 @@ +package com.siyeh.igtest.bugs; + +public class AssignmentToNullInspection +{ + private Object m_foo = null; + + public static void main(String[] args) + { + new AssignmentToNullInspection(new Object()).bar(); + } + + public AssignmentToNullInspection(Object foo) + { + m_foo = foo; + } + + public void bar() + { + Object foo = new Object(); + System.out.println("foo = " + foo); + foo = null; + m_foo = null; + System.out.println("foo = " + foo); + System.out.println("m_foo = " + m_foo); + } +} \ No newline at end of file diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/AssignmentUsedAsConditionInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/AssignmentUsedAsConditionInspection.java new file mode 100644 index 000000000000..edabb98c4781 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/AssignmentUsedAsConditionInspection.java @@ -0,0 +1,41 @@ +package com.siyeh.igtest.bugs; + +public class AssignmentUsedAsConditionInspection +{ + private final Object m_foo; + private final boolean m_bar; + + public static void main(String[] args) + { + new AssignmentUsedAsConditionInspection(new Object()).fooBar(); + } + + public AssignmentUsedAsConditionInspection(Object foo) + { + m_foo = foo; + m_bar = m_foo == null; + } + + private void fooBar() + { + final boolean[] foo = new boolean[1]; + Runnable runnable = new Runnable() + { + public void run() + { + if(foo[0] = m_bar) + { + System.out.println("foo = " + foo[0]); + } + } + }; + if(foo[0] = true) + { + System.out.println("foo = " + foo[0]); + } + if(foo[0] = m_bar) + { + System.out.println("foo = " + foo[0]); + } + } +} \ No newline at end of file diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/BigDecimalEqualsInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/BigDecimalEqualsInspection.java new file mode 100644 index 000000000000..a1411963c9ce --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/BigDecimalEqualsInspection.java @@ -0,0 +1,16 @@ +package com.siyeh.igtest.bugs; + +import java.math.BigDecimal; + +public class BigDecimalEqualsInspection { + public void foo() + { + final BigDecimal foo = new BigDecimal(3); + final BigDecimal bar = new BigDecimal(3); + foo.equals(bar); + if(foo.equals(bar)) + { + return; + } + } +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/ChainedMethodInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/ChainedMethodInspection.java new file mode 100644 index 000000000000..584be27c5304 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/ChainedMethodInspection.java @@ -0,0 +1,19 @@ +package com.siyeh.igtest.bugs; + +public class ChainedMethodInspection{ + private ChainedMethodInspection baz = foo().bar(); + public void baz(){ + foo().bar(); + (foo()).bar(); + } + + public ChainedMethodInspection foo() + { + return this; + } + + public ChainedMethodInspection bar() + { + return this; + } +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/CompareToUsesNonFinalVariableInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/CompareToUsesNonFinalVariableInspection.java new file mode 100644 index 000000000000..23b6a12e2cb5 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/CompareToUsesNonFinalVariableInspection.java @@ -0,0 +1,69 @@ +package com.siyeh.igtest.bugs; + +public class CompareToUsesNonFinalVariableInspection implements Comparable +{ + private int foo = 0; + private final int bar; + + public CompareToUsesNonFinalVariableInspection(int foo, int bar) + { + this.foo = foo; + this.bar = bar; + } + + + public boolean equals(Object o) + { + if(this == o) + { + return true; + } + if(!(o instanceof CompareToUsesNonFinalVariableInspection)) + { + return false; + } + + final CompareToUsesNonFinalVariableInspection nonFinalFieldReferencedInEquals = (CompareToUsesNonFinalVariableInspection) o; + + if(bar != nonFinalFieldReferencedInEquals.bar) + { + return false; + } + if(foo != nonFinalFieldReferencedInEquals.foo) + { + return false; + } + + return true; + } + + public int hashCode() + { + int result; + result = foo; + result = 29 * result + bar; + return result; + } + + public int compareTo(Object o) + { + if(foo > ((CompareToUsesNonFinalVariableInspection)o).foo) + { + return 1; + } + if(foo < ((CompareToUsesNonFinalVariableInspection)o).foo) + { + return -1; + } + if(bar > ((CompareToUsesNonFinalVariableInspection)o).bar) + { + return 1; + } + if(bar < ((CompareToUsesNonFinalVariableInspection)o).bar) + { + return -1; + } + return 0; + + } +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/ComparisonOfShortAndChar.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/ComparisonOfShortAndChar.java new file mode 100644 index 000000000000..7c15213320b0 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/ComparisonOfShortAndChar.java @@ -0,0 +1,21 @@ +package com.siyeh.igtest.bugs; + +public class ComparisonOfShortAndChar +{ + + public int foo() + { + char bar = 'c'; + short baz = (short) bar2(); + final boolean isEqual = bar == baz; + System.out.println("isEqual = " + isEqual); + final boolean isNotEqual = bar != baz; + System.out.println("isEqual = " + isEqual); + return 3; + } + + private char bar2() + { + return (char) 3; + } +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/CovariantComparetoInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/CovariantComparetoInspection.java new file mode 100644 index 000000000000..327c27577272 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/CovariantComparetoInspection.java @@ -0,0 +1,9 @@ +package com.siyeh.igtest.bugs; + +public class CovariantComparetoInspection +{ + public int compareTo(CovariantComparetoInspection foo) + { + return -1; + } +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/CovariantComparetoInspection15.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/CovariantComparetoInspection15.java new file mode 100644 index 000000000000..4446849625ae --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/CovariantComparetoInspection15.java @@ -0,0 +1,9 @@ +package com.siyeh.igtest.bugs; + +public class CovariantComparetoInspection15 implements Comparable +{ + + public int compareTo(CovariantComparetoInspection15 covariantComparetoInspection15) { + return 0; + } +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/CovariantComparetoInspection2.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/CovariantComparetoInspection2.java new file mode 100644 index 000000000000..59eb5a100521 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/CovariantComparetoInspection2.java @@ -0,0 +1,14 @@ +package com.siyeh.igtest.bugs; + +public class CovariantComparetoInspection2 +{ + public int compareTo(Object foo) + { + return -1; + } + + public int compareTo(CovariantComparetoInspection2 foo) + { + return -1; + } +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/CovariantEqualsInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/CovariantEqualsInspection.java new file mode 100644 index 000000000000..e0ea3d2009f0 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/CovariantEqualsInspection.java @@ -0,0 +1,13 @@ +package com.siyeh.igtest.bugs; + +public class CovariantEqualsInspection +{ + public CovariantEqualsInspection() + { + } + + public boolean equals(CovariantEqualsInspection foo) + { + return true; + } +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/CovariantEqualsInspection2.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/CovariantEqualsInspection2.java new file mode 100644 index 000000000000..526f7e7887ac --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/CovariantEqualsInspection2.java @@ -0,0 +1,18 @@ +package com.siyeh.igtest.bugs; + +public class CovariantEqualsInspection2 +{ + public CovariantEqualsInspection2() + { + } + + public boolean equals(CovariantEqualsInspection2 foo) + { + return true; + } + + public boolean equals(Object foo) + { + return true; + } +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/DefaultLastLabelInSwitchInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/DefaultLastLabelInSwitchInspection.java new file mode 100644 index 000000000000..fc28f89512c7 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/DefaultLastLabelInSwitchInspection.java @@ -0,0 +1,32 @@ +package com.siyeh.igtest.bugs; + +public class DefaultLastLabelInSwitchInspection +{ + private int m_bar; + + public DefaultLastLabelInSwitchInspection() + { + m_bar = 0; + } + + public void foo() + { + final int bar = m_bar; + switch(bar) + { + case 3: + case 4: + System.out.println("3"); + break; + case 7: + System.out.println("bar"); + break; + default: + break; + case 6: + System.out.println("4"); + break; + + } + } +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/EmptyStatementBodyInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/EmptyStatementBodyInspection.java new file mode 100644 index 000000000000..4b1aca254417 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/EmptyStatementBodyInspection.java @@ -0,0 +1,38 @@ +package com.siyeh.igtest.bugs; + +public class EmptyStatementBodyInspection +{ + private void foo() + { + while(bar()); + while(bar()){ + + } + for(int i = 0;i<4;i++); + for(int i = 0;i<4;i++) + { + + } + if(bar()); + if(bar()){ + + } + if(bar()){ + return; + } + else + { + + } + if(bar()){ + return; + } + else; + + } + + private boolean bar() + { + return true; + } +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/EqualsBetweenInconvertibleTypesInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/EqualsBetweenInconvertibleTypesInspection.java new file mode 100644 index 000000000000..5a99f5bbd026 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/EqualsBetweenInconvertibleTypesInspection.java @@ -0,0 +1,11 @@ +package com.siyeh.igtest.bugs; + +public class EqualsBetweenInconvertibleTypesInspection { + + public void foo() + { + final Integer foo = new Integer(3); + final Double bar = new Double(3); + foo.equals(bar); + } +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/EqualsUsesNonFinalVariableInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/EqualsUsesNonFinalVariableInspection.java new file mode 100644 index 000000000000..15c85c5be4d1 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/EqualsUsesNonFinalVariableInspection.java @@ -0,0 +1,69 @@ +package com.siyeh.igtest.bugs; + +public class EqualsUsesNonFinalVariableInspection implements Comparable +{ + private int foo = 0; + private final int bar; + + public EqualsUsesNonFinalVariableInspection(int foo, int bar) + { + this.foo = foo; + this.bar = bar; + } + + + public boolean equals(Object o) + { + if(this == o) + { + return true; + } + if(!(o instanceof EqualsUsesNonFinalVariableInspection)) + { + return false; + } + + final EqualsUsesNonFinalVariableInspection nonFinalFieldReferencedInEquals = (EqualsUsesNonFinalVariableInspection) o; + + if(bar != nonFinalFieldReferencedInEquals.bar) + { + return false; + } + if(foo != nonFinalFieldReferencedInEquals.foo) + { + return false; + } + + return true; + } + + public int hashCode() + { + int result; + result = foo; + result = 29 * result + bar; + return result; + } + + public int compareTo(Object o) + { + if(foo > ((EqualsUsesNonFinalVariableInspection)o).foo) + { + return 1; + } + if(foo < ((EqualsUsesNonFinalVariableInspection)o).foo) + { + return -1; + } + if(bar > ((EqualsUsesNonFinalVariableInspection)o).bar) + { + return 1; + } + if(bar < ((EqualsUsesNonFinalVariableInspection)o).bar) + { + return -1; + } + return 0; + + } +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/FallthruInSwithInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/FallthruInSwithInspection.java new file mode 100644 index 000000000000..94629ee3a6dd --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/FallthruInSwithInspection.java @@ -0,0 +1,25 @@ +package com.siyeh.igtest.bugs; + +public class FallthruInSwithInspection +{ + private int m_bar; + + public FallthruInSwithInspection() + { + m_bar = 0; + } + + public void foo() + { + final int bar = m_bar; + switch(bar) + { + case (3): + case (4): + System.out.println("3"); + case (5): + case (6): + System.out.println("4"); + } + } +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/FloatingPointEqualityInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/FloatingPointEqualityInspection.java new file mode 100644 index 000000000000..6ccfbada720b --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/FloatingPointEqualityInspection.java @@ -0,0 +1,36 @@ +package com.siyeh.igtest.bugs; + +public class FloatingPointEqualityInspection +{ + private double m_bar; + private double m_baz; + private float m_barf; + private float m_bazf; + + public static final float TENTH = 0.1f; + public static final float fifth = 0.2f; + + public FloatingPointEqualityInspection() + { + m_bar = 0.0; + m_baz = 1.0; + m_barf = TENTH; + m_bazf = fifth; + } + + public void foo() + { + if(m_bar == m_baz) + { + System.out.println("m_bar = " + m_bar); + } + if(m_barf == m_bazf) + { + System.out.println("m_barf = " + m_barf); + } + if(m_barf != m_bar) + { + System.out.println("m_barf = " + m_barf); + } + } +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/ForLoopThatDoesntUseLoopVariableInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/ForLoopThatDoesntUseLoopVariableInspection.java new file mode 100644 index 000000000000..c616cae37071 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/ForLoopThatDoesntUseLoopVariableInspection.java @@ -0,0 +1,52 @@ +package com.siyeh.igtest.bugs; + +public class ForLoopThatDoesntUseLoopVariableInspection +{ + + public ForLoopThatDoesntUseLoopVariableInspection() + { + } + + private void foo() throws Exception + { + int j = 0; + for(int i = 0; j < 100; i++) + { + System.out.println("i" + i); + if(bar()) + break; + } + + for(int i = 0; i < 100; j++) + { + System.out.println("i" + i); + if(bar()) + break; + } + + for(int i = 0; j < 100; j++) + { + System.out.println("i" + i); + if(bar()) + break; + } + for(int i = 0, k = 0; j < 100; j++) + { + System.out.println("i" + i); + if(bar()) + break; + } + for(int i = 0; i < 100; i++) + { + System.out.println("i" + i); + if(bar()) + break; + } + } + + private boolean bar() + { + return true; + } + +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/ForLoopWithMissingComponentsInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/ForLoopWithMissingComponentsInspection.java new file mode 100644 index 000000000000..edd5e5d6a188 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/ForLoopWithMissingComponentsInspection.java @@ -0,0 +1,55 @@ +package com.siyeh.igtest.bugs; + +public class ForLoopWithMissingComponentsInspection +{ + + public ForLoopWithMissingComponentsInspection() + { + } + + private void foo() throws Exception + { + + for(;;) + { + if(bar()) + { + break; + } + } + for(int i = 0;;) + { + if(bar()) + { + break; + } + } + for(;true;) + { + if(bar()) + { + break; + } + } + for(int i = 0;;i++) + { + if(bar()) + { + break; + } + } + for(int i = 0;true;i++) + { + if(bar()) + { + break; + } + } + } + + private boolean bar() + { + return true; + } + +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/IgnoreResultsOfReadInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/IgnoreResultsOfReadInspection.java new file mode 100644 index 000000000000..010b97103504 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/IgnoreResultsOfReadInspection.java @@ -0,0 +1,23 @@ +package com.siyeh.igtest.bugs; + +import java.io.*; + +public class IgnoreResultsOfReadInspection +{ + private void foo() + { + try + { + final FileInputStream stream = new FileInputStream("FOO"); + final byte[] buffer = new byte[10]; + stream.read(buffer); + } + catch(FileNotFoundException e) + { + } + catch(IOException e) + { + } + + } +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/IncompatibleMaskInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/IncompatibleMaskInspection.java new file mode 100644 index 000000000000..cfc1bbd94d4c --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/IncompatibleMaskInspection.java @@ -0,0 +1,37 @@ +package com.siyeh.igtest.bugs; + +public class IncompatibleMaskInspection { + public static void main(String[] args) { + final int i = foo(); + if((i & 0x1) == 0x2) + { + + }if((i & 0x3) == 0x2) // this should be fine + { + + } + if((i & 0x1) != 0x2) + { + + } + + if((i | 0x1) == 0x2) + { + + } + if((i | 0x1) == 0x3) // this should be fine + { + + } + final boolean b = (i | 0x1) != 0x2; + if(b) + { + + } + } + + private static int foo() { + return 6; + } + +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/InfiniteLoopStatementInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/InfiniteLoopStatementInspection.java new file mode 100644 index 000000000000..fc882f226abe --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/InfiniteLoopStatementInspection.java @@ -0,0 +1,89 @@ +package com.siyeh.igtest.bugs; + +public class InfiniteLoopStatementInspection +{ + + public InfiniteLoopStatementInspection() + { + } + + private void foo() throws Exception + { + + try + { + for(; true;) + { + } + } + catch(Exception e) + { + + } + try + { + for(int i = 0; true; i++) + { + if(bar()) + return; + } + } + catch(Exception e) + { + + } + try + { + while(true) + { + System.out.println(""); + } + } + catch(Exception e) + { + + } + try + { + while(bar()) + { + if(bar()) + return; + } + } + catch(Exception e) + { + + } + try + { + while(bar()) + { + System.out.println(""); + } + } + catch(Exception e) + { + + } + try + { + do + { + System.out.println(""); + } + while(true); + } + catch(Exception e) + { + + } + + } + + private boolean bar() + { + return true; + } + +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/InfiniteRecursionInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/InfiniteRecursionInspection.java new file mode 100644 index 000000000000..0ea471af5396 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/InfiniteRecursionInspection.java @@ -0,0 +1,125 @@ +package com.siyeh.igtest.bugs; + +import com.intellij.psi.PsiClass; + +import java.util.List; +import java.io.IOException; +import java.io.File; + +public class InfiniteRecursionInspection +{ + public void foo() + { + foo(); + } + + public void bar() + { + foo(); + } + + public int baz() + { + return baz(); + } + + public int bazoom() + { + if(foobar()) + { + return bazoom(); + } + return 3; + } + + public void bazoomvoid() + { + if(foobar()) + { + bazoomvoid(); + } + } + + public int barangus() + { + while(foobar()) + { + return barangus(); + } + return 3; + } + + public int barangoo() + { + do + { + return barangoo(); + } + while(foobar()); + } + + public int bazoomer() + { + if(foobar()) + { + return bazoomer(); + } + else + { + return bazoomer() + 3; + } + } + + public boolean foobar() + { + return false && foobar(); + } + + public boolean foobarangus() + { + return foobarangus() && false; + } + + public int bangem(PsiClass aClass) + { + final PsiClass superClass = aClass.getSuperClass(); + if(superClass ==null) + { + return 0; + } + else + { + return bangem(aClass)+1; + } + } + + private boolean foo(final PsiClass superClass) + { + return superClass ==null; + } + + public int getInheritanceDepth(PsiClass aClass) + { + final PsiClass superClass = aClass.getSuperClass(); + if(superClass == null) + { + return 0; + } + else + { + return getInheritanceDepth(superClass) + 1; + } + } + + void rec(List pageConfig) { + try { + new File("c:/").getCanonicalFile(); + } catch (IOException e) { + + } + for (int j = 0; j < pageConfig.size(); j++) { + List pc = (List) pageConfig.get(j); + rec(pc); + } + } +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/IntegerDivisionInFloatingPointContextInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/IntegerDivisionInFloatingPointContextInspection.java new file mode 100644 index 000000000000..ce2a6f391566 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/IntegerDivisionInFloatingPointContextInspection.java @@ -0,0 +1,8 @@ +package com.siyeh.igtest.bugs; + +public class IntegerDivisionInFloatingPointContextInspection{ + public void foo() + { + float x = 3.0F + 3/5; + } +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/LoopStatementsThatDontLoopInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/LoopStatementsThatDontLoopInspection.java new file mode 100644 index 000000000000..a1bf714bf28d --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/LoopStatementsThatDontLoopInspection.java @@ -0,0 +1,47 @@ +package com.siyeh.igtest.bugs; + +public class LoopStatementsThatDontLoopInspection +{ + private final int m_foo = 3; + + public static void main(String[] args) throws Exception + { + new LoopStatementsThatDontLoopInspection().foo(); + } + + public LoopStatementsThatDontLoopInspection() + { + } + + private void foo() throws Exception + { + System.out.println("m_foo =" + m_foo); + for(; ;) + { + break; + } + + while(true) + { + break; + } + + do + { + break; + } + while(true); + + while(true) + { + throw new Exception(); + } + + // for(; ;) + //{ + // return; + // } + + } + +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/MismatchedCollectionQueryUpdateInspection2.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/MismatchedCollectionQueryUpdateInspection2.java new file mode 100644 index 000000000000..0298348dfe73 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/MismatchedCollectionQueryUpdateInspection2.java @@ -0,0 +1,13 @@ +package com.siyeh.igtest.bugs; + +import java.util.*; + +public class MismatchedCollectionQueryUpdateInspection2 { + private Set foo = new HashSet(); + + public void foo() + { + final Set localFoo = foo; + } + +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/MisspelledComparetoInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/MisspelledComparetoInspection.java new file mode 100644 index 000000000000..533a46565e16 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/MisspelledComparetoInspection.java @@ -0,0 +1,16 @@ +package com.siyeh.igtest.bugs; + +public class MisspelledComparetoInspection +{ + private int m_bar; + + public MisspelledComparetoInspection() + { + m_bar = 0; + } + + public int compareto(int foo) + { + return m_bar; + } +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/MisspelledEqualInsspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/MisspelledEqualInsspection.java new file mode 100644 index 000000000000..12411a377505 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/MisspelledEqualInsspection.java @@ -0,0 +1,16 @@ +package com.siyeh.igtest.bugs; + +public class MisspelledEqualInsspection +{ + private int m_bar; + + public MisspelledEqualInsspection() + { + m_bar = 0; + } + + public boolean equal(Object foo) + { + return m_bar == 3; + } +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/MisspelledHashcodeInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/MisspelledHashcodeInspection.java new file mode 100644 index 000000000000..8d5fbae6001f --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/MisspelledHashcodeInspection.java @@ -0,0 +1,16 @@ +package com.siyeh.igtest.bugs; + +public class MisspelledHashcodeInspection +{ + private int m_bar; + + public MisspelledHashcodeInspection() + { + m_bar = 0; + } + + public int hashcode() + { + return m_bar; + } +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/MisspelledToStringInsspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/MisspelledToStringInsspection.java new file mode 100644 index 000000000000..17df7e3556f7 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/MisspelledToStringInsspection.java @@ -0,0 +1,16 @@ +package com.siyeh.igtest.bugs; + +public class MisspelledToStringInsspection +{ + private int m_bar; + + public MisspelledToStringInsspection() + { + m_bar = 0; + } + + public String tostring() + { + return String.valueOf(m_bar == 3); + } +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/MyEnum.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/MyEnum.java new file mode 100644 index 000000000000..15f3fd265f61 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/MyEnum.java @@ -0,0 +1,5 @@ +package com.siyeh.igtest.bugs; + +public enum MyEnum{ + foo, bar, baz; +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/NonShortCircuitBooleanInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/NonShortCircuitBooleanInspection.java new file mode 100644 index 000000000000..ee89680d3638 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/NonShortCircuitBooleanInspection.java @@ -0,0 +1,16 @@ +package com.siyeh.igtest.bugs; + +public class NonShortCircuitBooleanInspection +{ + private boolean m_bar = true; + private boolean m_baz = false; + + public NonShortCircuitBooleanInspection() + { + final boolean nonShortAnd = m_bar & m_baz; + final boolean nonShortOr = m_bar | m_baz; + m_bar |= m_baz; + m_bar &= m_baz; + } + +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/ObjectEqualsInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/ObjectEqualsInspection.java new file mode 100644 index 000000000000..211935750216 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/ObjectEqualsInspection.java @@ -0,0 +1,39 @@ +package com.siyeh.igtest.bugs; + +import java.util.HashMap; +import java.util.Map; + +public class ObjectEqualsInspection +{ + public ObjectEqualsInspection() + { + } + + public void fooBar() + { + final Map map1 = new HashMap(5); + final Map map2 = new HashMap(5); + if (map1 == map2) + { + + } + if (null == map2) + { + + } + if (map1 == null) + { + + } + } + + public void fooBarEnum() + { + final MyEnum enum1 = MyEnum.foo; + final MyEnum enum2 = MyEnum.bar; + if (enum1 == enum2) + { + + } + } +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/ObjectEqualsNullInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/ObjectEqualsNullInspection.java new file mode 100644 index 000000000000..854161b5e6e3 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/ObjectEqualsNullInspection.java @@ -0,0 +1,10 @@ +package com.siyeh.igtest.bugs; + +public class ObjectEqualsNullInspection { + private Object lock = new Object(); + + public boolean foo() + { + return lock.equals(null); + } +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/OctalDecimalMixedInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/OctalDecimalMixedInspection.java new file mode 100644 index 000000000000..842ec32c8a2b --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/OctalDecimalMixedInspection.java @@ -0,0 +1,8 @@ +package com.siyeh.igtest.bugs; + +public class OctalDecimalMixedInspection +{ + private static int[] s_bar = new int[]{3, 4, 05}; + private static int[] s_foo = new int[]{3, 4, 0}; + +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/ResultOfObjectAllocationIgnoredInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/ResultOfObjectAllocationIgnoredInspection.java new file mode 100644 index 000000000000..7b9bbe9e1fae --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/ResultOfObjectAllocationIgnoredInspection.java @@ -0,0 +1,12 @@ +package com.siyeh.igtest.bugs; + +public class ResultOfObjectAllocationIgnoredInspection { + private ResultOfObjectAllocationIgnoredInspection() { + super(); + } + + public static void foo() + { + new Integer(3); + } +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/ResultSetIndexZeroInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/ResultSetIndexZeroInspection.java new file mode 100644 index 000000000000..cbb5e0eaf8a8 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/ResultSetIndexZeroInspection.java @@ -0,0 +1,14 @@ +package com.siyeh.igtest.bugs; + +import java.sql.ResultSet; +import java.sql.SQLException; + +public class ResultSetIndexZeroInspection { + private static final int COLUMN_INDEX = 0; + + public void foo(ResultSet resultSet) throws SQLException { + resultSet.getInt(0); + resultSet.getInt(COLUMN_INDEX); + resultSet.getInt(3); + } +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/ReturnNullInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/ReturnNullInspection.java new file mode 100644 index 000000000000..d034dd0a6da2 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/ReturnNullInspection.java @@ -0,0 +1,15 @@ +package com.siyeh.igtest.bugs; + +public class ReturnNullInspection +{ + + public Object bar() + { + return null; + } + + public int[] bar2() + { + return null; + } +} \ No newline at end of file diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/StreamOpenCloseInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/StreamOpenCloseInspection.java new file mode 100644 index 000000000000..f69d678a1a24 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/StreamOpenCloseInspection.java @@ -0,0 +1,55 @@ +package com.siyeh.igtest.bugs; + +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; + +public class StreamOpenCloseInspection { + public void foo() throws FileNotFoundException { + // new FileInputStream("bar"); + } + + public void foo2() throws FileNotFoundException { + final FileInputStream str = new FileInputStream("bar"); + + } + + public void foo25() throws FileNotFoundException { + try { + final FileInputStream str = new FileInputStream("bar"); + } finally { + } + + } + + public void foo3() throws IOException { + final FileInputStream str = new FileInputStream("bar"); + str.close(); + } + + public void foo4() throws IOException { + FileInputStream str = null; + try { + str = new FileInputStream("bar"); + } catch (FileNotFoundException e) { + e.printStackTrace(); //TODO + } + str.close(); + } + + public void foo5() throws IOException { + FileInputStream str = null; + try { + str = new FileInputStream("bar"); + } finally { + str.close(); + } + } + public void foo6() throws IOException { + FileInputStream str = null; + try { + str = new FileInputStream("bar"); + } finally { + } + } +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/StringEqualsInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/StringEqualsInspection.java new file mode 100644 index 000000000000..976df62d1480 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/StringEqualsInspection.java @@ -0,0 +1,36 @@ +package com.siyeh.igtest.bugs; + +public class StringEqualsInspection +{ + public StringEqualsInspection() + { + } + + public void foo() + { + if ("foo" == "bar") + { + + } + + String foo = "foo"; + String bar = bar("bar"); + if (foo == bar) + { + + } + if (bar == null) + { + + } + if (null == bar) + { + + } + } + + private String bar(String s) + { + return s; + } +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/SubtractionInComparetoInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/SubtractionInComparetoInspection.java new file mode 100644 index 000000000000..107e78eb8c43 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/SubtractionInComparetoInspection.java @@ -0,0 +1,12 @@ +package com.siyeh.igtest.bugs; + +public class SubtractionInComparetoInspection +{ + private int m_foo = 3; + + public int compareTo(Object foo) + { + final int temp = m_foo + ((SubtractionInComparetoInspection)foo).m_foo; + return m_foo - ((SubtractionInComparetoInspection)foo).m_foo; + } +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/SwitchStatementDensityInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/SwitchStatementDensityInspection.java new file mode 100644 index 000000000000..338e69cb98be --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/SwitchStatementDensityInspection.java @@ -0,0 +1,41 @@ +package com.siyeh.igtest.bugs; + +public class SwitchStatementDensityInspection +{ + private int m_bar; + + public SwitchStatementDensityInspection() + { + m_bar = 0; + } + + public void fooBar() + { + final int bar = m_bar; + switch(bar) + { + case 3: + case 4: + System.out.println("3"); + System.out.println("3"); + System.out.println("3"); + System.out.println("3"); + System.out.println("3"); + System.out.println("3"); + System.out.println("3"); + System.out.println("3"); + System.out.println("3"); + System.out.println("3"); + System.out.println("3"); + System.out.println("3"); + break; + case 6: + System.out.println("4"); + break; + default: + break; + } + + + } +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/SwitchStatementsWithoutDefaultInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/SwitchStatementsWithoutDefaultInspection.java new file mode 100644 index 000000000000..f33bc24694c7 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/SwitchStatementsWithoutDefaultInspection.java @@ -0,0 +1,62 @@ +package com.siyeh.igtest.bugs; + +public class SwitchStatementsWithoutDefaultInspection +{ + private int m_bar; + + public SwitchStatementsWithoutDefaultInspection() + { + m_bar = 0; + } + + public void fooBar() + { + final int bar = m_bar; + switch(bar) + { + case 3: + case 4: + System.out.println("3"); + break; + case 7: + case5: + System.out.println("bar"); + break; + case 6: + System.out.println("4"); + break; + default: + break; + } + + switch(bar) + { + case 3: + case 4: + System.out.println("3"); + + break; + case 7: + case5: + System.out.println("bar"); + break; + case 6: + System.out.println("4"); + break; + } + MyEnum var = MyEnum.foo; + switch(var) + { + case foo: + case bar: + case baz: + break; + } + switch(var) + { + case bar: + case baz: + break; + } + } +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/TextLabelInSwitchInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/TextLabelInSwitchInspection.java new file mode 100644 index 000000000000..537666d8088e --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/TextLabelInSwitchInspection.java @@ -0,0 +1,32 @@ +package com.siyeh.igtest.bugs; + +public class TextLabelInSwitchInspection +{ + private int m_bar; + + public TextLabelInSwitchInspection() + { + m_bar = 0; + } + + public void foo() + { + final int bar = m_bar; + switch(bar) + { + case 3: + case 4: + System.out.println("3"); + break; + case 7: + case5: + System.out.println("bar"); + break; + case 6: + System.out.println("4"); + break; + default: + break; + } + } +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/classlayout/AbstractClass.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/classlayout/AbstractClass.java new file mode 100644 index 000000000000..d40c9799bfa4 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/classlayout/AbstractClass.java @@ -0,0 +1,5 @@ +package com.siyeh.igtest.classlayout; + +public abstract class AbstractClass extends ConcreteClass +{ +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/classlayout/AbstractClassWithoutAbstractMethodsChildInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/classlayout/AbstractClassWithoutAbstractMethodsChildInspection.java new file mode 100644 index 000000000000..19c4efd2dce3 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/classlayout/AbstractClassWithoutAbstractMethodsChildInspection.java @@ -0,0 +1,8 @@ +package com.siyeh.igtest.classlayout; + +public abstract class AbstractClassWithoutAbstractMethodsChildInspection + extends ClassWithAbstractMethods +{ + + +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/classlayout/AbstractClassWithoutAbstractMethodsChildInspection2.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/classlayout/AbstractClassWithoutAbstractMethodsChildInspection2.java new file mode 100644 index 000000000000..4f266f8fd548 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/classlayout/AbstractClassWithoutAbstractMethodsChildInspection2.java @@ -0,0 +1,11 @@ +package com.siyeh.igtest.classlayout; + +public abstract class AbstractClassWithoutAbstractMethodsChildInspection2 + extends ClassWithAbstractMethods +{ + + public void barangus() + { + } + +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/classlayout/AbstractClassWithoutAbstractMethodsInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/classlayout/AbstractClassWithoutAbstractMethodsInspection.java new file mode 100644 index 000000000000..da5a8d990350 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/classlayout/AbstractClassWithoutAbstractMethodsInspection.java @@ -0,0 +1,12 @@ +package com.siyeh.igtest.classlayout; + +public abstract class AbstractClassWithoutAbstractMethodsInspection +{ + public static final int CONSTANT = 1; + + public int barangus() + { + return CONSTANT; + } + +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/classlayout/AbstractMethodOverridesConcreteMethodInspection1.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/classlayout/AbstractMethodOverridesConcreteMethodInspection1.java new file mode 100644 index 000000000000..aaeda0796943 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/classlayout/AbstractMethodOverridesConcreteMethodInspection1.java @@ -0,0 +1,17 @@ +package com.siyeh.igtest.classlayout; + +public abstract class AbstractMethodOverridesConcreteMethodInspection1 +{ + public abstract void fooBar(); + public abstract void fooBang(); + + public void fooBaz() + { + + } + + public void fooBarangus() + { + + } +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/classlayout/AbstractMethodOverridesConcreteMethodInspection2.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/classlayout/AbstractMethodOverridesConcreteMethodInspection2.java new file mode 100644 index 000000000000..f8196e589bd0 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/classlayout/AbstractMethodOverridesConcreteMethodInspection2.java @@ -0,0 +1,19 @@ +package com.siyeh.igtest.classlayout; + +public abstract class AbstractMethodOverridesConcreteMethodInspection2 + extends AbstractMethodOverridesConcreteMethodInspection1 +{ + public void fooBar() + { + + } + + public abstract void fooBang(); + + public abstract void fooBaz(); + + public void fooBarangus() + { + + } +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/classlayout/AnonymousInnerClassInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/classlayout/AnonymousInnerClassInspection.java new file mode 100644 index 000000000000..100282ddb0cf --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/classlayout/AnonymousInnerClassInspection.java @@ -0,0 +1,12 @@ +package com.siyeh.igtest.classlayout; + +public class AnonymousInnerClassInspection { + public void foo() + { + final Runnable runnable = new Runnable(){ + public void run() { + } + }; + runnable.run(); + } +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/classlayout/ClassInitializerInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/classlayout/ClassInitializerInspection.java new file mode 100644 index 000000000000..dff8a694cb27 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/classlayout/ClassInitializerInspection.java @@ -0,0 +1,13 @@ +package com.siyeh.igtest.classlayout; + +public class ClassInitializerInspection { + static private int foo; + + static { + foo = 3; + } + + { + foo = 3; + } +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/classlayout/ClassMayBeInterfaceInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/classlayout/ClassMayBeInterfaceInspection.java new file mode 100644 index 000000000000..ee7e0a7ca5dc --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/classlayout/ClassMayBeInterfaceInspection.java @@ -0,0 +1,8 @@ +package com.siyeh.igtest.classlayout; + +public abstract class ClassMayBeInterfaceInspection +{ + public static final int foo = 1; + + public abstract void bar(); +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/classlayout/ClassNameDiffersFromFileNameInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/classlayout/ClassNameDiffersFromFileNameInspection.java new file mode 100644 index 000000000000..38a4171bfb16 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/classlayout/ClassNameDiffersFromFileNameInspection.java @@ -0,0 +1,11 @@ +package com.siyeh.igtest.classlayout; + + class ClassNameDaffersFromFileNameInspection { + private ClassNameDaffersFromFileNameInspection() { + super(); + } + + public static void main(String[] args) { + + } +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/classlayout/ClassWithAbstractMethods.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/classlayout/ClassWithAbstractMethods.java new file mode 100644 index 000000000000..f3dfb8badea8 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/classlayout/ClassWithAbstractMethods.java @@ -0,0 +1,6 @@ +package com.siyeh.igtest.classlayout; + +public abstract class ClassWithAbstractMethods +{ + public abstract void barangus(); +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/classlayout/ClassWithoutConstructorInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/classlayout/ClassWithoutConstructorInspection.java new file mode 100644 index 000000000000..ecb07cc95271 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/classlayout/ClassWithoutConstructorInspection.java @@ -0,0 +1,7 @@ +package com.siyeh.igtest.classlayout; + +import java.util.*; + +public class ClassWithoutConstructorInspection extends ArrayList +{ +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/classlayout/ConcreteClass.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/classlayout/ConcreteClass.java new file mode 100644 index 000000000000..673a3aa8f8ae --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/classlayout/ConcreteClass.java @@ -0,0 +1,7 @@ +package com.siyeh.igtest.classlayout; + +public class ConcreteClass +{ + private AbstractClass m_class; + private ConcreteClass m_class2; +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/classlayout/ConstantAbstractClass.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/classlayout/ConstantAbstractClass.java new file mode 100644 index 000000000000..c7a44589979d --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/classlayout/ConstantAbstractClass.java @@ -0,0 +1,7 @@ +package com.siyeh.igtest.classlayout; + +public abstract class ConstantAbstractClass +{ + public static final int CONST1 = 0; + public static final int CONST2 = 0; +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/classlayout/ConstantInterface.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/classlayout/ConstantInterface.java new file mode 100644 index 000000000000..90e0c367a2b4 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/classlayout/ConstantInterface.java @@ -0,0 +1,7 @@ +package com.siyeh.igtest.classlayout; + +public interface ConstantInterface +{ + int CONST1 = 0; + int CONST2 = 0; +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/classlayout/ConstantInterfaceImpl.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/classlayout/ConstantInterfaceImpl.java new file mode 100644 index 000000000000..ef7f9bae65bb --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/classlayout/ConstantInterfaceImpl.java @@ -0,0 +1,6 @@ +package com.siyeh.igtest.classlayout; + +public class ConstantInterfaceImpl implements ConstantInterface +{ + +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/classlayout/InnerClassOnInterface.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/classlayout/InnerClassOnInterface.java new file mode 100644 index 000000000000..219e62b1fd56 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/classlayout/InnerClassOnInterface.java @@ -0,0 +1,9 @@ +package com.siyeh.igtest.classlayout; + +public interface InnerClassOnInterface +{ + class Inner + { + + } +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/classlayout/LimitedScopeInnerClassInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/classlayout/LimitedScopeInnerClassInspection.java new file mode 100644 index 000000000000..f2dd30adeaa7 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/classlayout/LimitedScopeInnerClassInspection.java @@ -0,0 +1,13 @@ +package com.siyeh.igtest.classlayout; + +public class LimitedScopeInnerClassInspection { + public void foo() { + class MyRunnable implements Runnable { + public void run() { + } + } + final Runnable runnable = new MyRunnable(); + runnable.run(); + } + +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/classlayout/MarkerInterface.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/classlayout/MarkerInterface.java new file mode 100644 index 000000000000..69bf2830166c --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/classlayout/MarkerInterface.java @@ -0,0 +1,4 @@ +package com.siyeh.igtest.classlayout; + +public interface MarkerInterface { +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/classlayout/MutipleTopLevelClassesInFileInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/classlayout/MutipleTopLevelClassesInFileInspection.java new file mode 100644 index 000000000000..599d769d1321 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/classlayout/MutipleTopLevelClassesInFileInspection.java @@ -0,0 +1,18 @@ +package com.siyeh.igtest.classlayout; + +public class MutipleTopLevelClassesInFileInspection { + private MutipleTopLevelClassesInFileInspection() { + super(); + } + + public static void main(String[] args) { + + } +} + +class MutipleTopLevelClassesInFileInspection2 { + public static void main(String[] args) { + + } +} + diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/classlayout/NonPrivateFieldOfPrivateClassInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/classlayout/NonPrivateFieldOfPrivateClassInspection.java new file mode 100644 index 000000000000..387e7653157e --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/classlayout/NonPrivateFieldOfPrivateClassInspection.java @@ -0,0 +1,11 @@ +package com.siyeh.igtest.classlayout; + +public class NonPrivateFieldOfPrivateClassInspection{ + + public PrivateInner foo; + + private class PrivateInner + { + + } +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/classlayout/NonPrivateMethodReturnsPrivateClassInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/classlayout/NonPrivateMethodReturnsPrivateClassInspection.java new file mode 100644 index 000000000000..63a894556ee5 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/classlayout/NonPrivateMethodReturnsPrivateClassInspection.java @@ -0,0 +1,14 @@ +package com.siyeh.igtest.classlayout; + +public class NonPrivateMethodReturnsPrivateClassInspection{ + + public PrivateInner foo() + { + return null; + } + + private class PrivateInner + { + + } +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/classlayout/NonProtectedConstructorInAbstractClassInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/classlayout/NonProtectedConstructorInAbstractClassInspection.java new file mode 100644 index 000000000000..8141d73a833f --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/classlayout/NonProtectedConstructorInAbstractClassInspection.java @@ -0,0 +1,11 @@ +package com.siyeh.igtest.classlayout; + +public abstract class NonProtectedConstructorInAbstractClassInspection +{ + public NonProtectedConstructorInAbstractClassInspection() + { + } + private NonProtectedConstructorInAbstractClassInspection(int foo) + { + } +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/classlayout/NonProtectedConstructorInAbstractClassInspection2.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/classlayout/NonProtectedConstructorInAbstractClassInspection2.java new file mode 100644 index 000000000000..1573ec53efbc --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/classlayout/NonProtectedConstructorInAbstractClassInspection2.java @@ -0,0 +1,11 @@ +package com.siyeh.igtest.classlayout; + +public abstract class NonProtectedConstructorInAbstractClassInspection2 { + protected NonProtectedConstructorInAbstractClassInspection2() { + this(2); + } + + private NonProtectedConstructorInAbstractClassInspection2(int foo) { + super(); + } +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/classlayout/Singleton.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/classlayout/Singleton.java new file mode 100644 index 000000000000..81ffc1e94669 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/classlayout/Singleton.java @@ -0,0 +1,12 @@ +package com.siyeh.igtest.classlayout; + +public class Singleton{ + private static Singleton ourInstance = new Singleton(); + + public static Singleton getInstance(){ + return ourInstance; + } + + private Singleton(){ + } +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/classlayout/StaticNonFinalInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/classlayout/StaticNonFinalInspection.java new file mode 100644 index 000000000000..5067f1bbca77 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/classlayout/StaticNonFinalInspection.java @@ -0,0 +1,11 @@ +package com.siyeh.igtest.classlayout; + +public class StaticNonFinalInspection +{ + private static int s_foo = 3; + + static + { + System.out.println("s_foo = " + s_foo); + } +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/classlayout/UtilityClassWithPublicConstructorInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/classlayout/UtilityClassWithPublicConstructorInspection.java new file mode 100644 index 000000000000..7b27670ee1c8 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/classlayout/UtilityClassWithPublicConstructorInspection.java @@ -0,0 +1,16 @@ +package com.siyeh.igtest.classlayout; + +public class UtilityClassWithPublicConstructorInspection +{ + public static final int CONSTANT = 1; + + public UtilityClassWithPublicConstructorInspection() + { + + } + + public static int barangus() + { + return CONSTANT; + } +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/classmetrics/AnonymousClassComplexityInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/classmetrics/AnonymousClassComplexityInspection.java new file mode 100644 index 000000000000..16e5ce8c8b2a --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/classmetrics/AnonymousClassComplexityInspection.java @@ -0,0 +1,25 @@ +package com.siyeh.igtest.classmetrics; + +public class AnonymousClassComplexityInspection { + private boolean bar; + private boolean baz; + private boolean bazoom; + public void foo() + { + Runnable runnable = new Runnable() { + public void run() { + if(bar) + { + + }else if(baz) + { + + }else if(bazoom) + { + + } + foo(); + } + }; + } +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/classmetrics/AnonymousMethodCountInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/classmetrics/AnonymousMethodCountInspection.java new file mode 100644 index 000000000000..7f311728e9f7 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/classmetrics/AnonymousMethodCountInspection.java @@ -0,0 +1,15 @@ +package com.siyeh.igtest.classmetrics; + +public class AnonymousMethodCountInspection { + public void foo() + { + Runnable runnable = new Runnable() { + public void run() { + foo(); + } + public void run2() { + foo(); + } + }; + } +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/classmetrics/Child.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/classmetrics/Child.java new file mode 100644 index 000000000000..198ab51d8e72 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/classmetrics/Child.java @@ -0,0 +1,5 @@ +package com.siyeh.igtest.classmetrics; + +public class Child extends Parent +{ +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/classmetrics/ClassNestingDepthInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/classmetrics/ClassNestingDepthInspection.java new file mode 100644 index 000000000000..31967516d338 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/classmetrics/ClassNestingDepthInspection.java @@ -0,0 +1,15 @@ +package com.siyeh.igtest.classmetrics; + +public class ClassNestingDepthInspection +{ + public class InnerClass + { + public class InnerClazz + { + public class InnerClassy + { + + } + } + } +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/classmetrics/ConstantFieldCountInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/classmetrics/ConstantFieldCountInspection.java new file mode 100644 index 000000000000..4b65d19f59f8 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/classmetrics/ConstantFieldCountInspection.java @@ -0,0 +1,19 @@ +package com.siyeh.igtest.classmetrics; + +public class ConstantFieldCountInspection +{ + private static final int m_aaa = 3; + private static final int m_bbb = 4; + private static final int m_ccc = 5; + private static final int m_ddd = 6; + private int m_eee; + private int m_fff; + private int m_ggg; + private int m_hhh; + private int m_iii; + private int m_jjj; + private int m_kkk; + private int m_lll; + private int m_mmm; + private int m_nnn; +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/classmetrics/ConstructorCountInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/classmetrics/ConstructorCountInspection.java new file mode 100644 index 000000000000..5eb1247adc33 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/classmetrics/ConstructorCountInspection.java @@ -0,0 +1,16 @@ +package com.siyeh.igtest.classmetrics; + +public class ConstructorCountInspection +{ + public ConstructorCountInspection(int i){} + + public ConstructorCountInspection(boolean ch){} + + public ConstructorCountInspection(char b){} + + public ConstructorCountInspection(float d){} + + public ConstructorCountInspection(double f){} + + public ConstructorCountInspection(long s){} +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/classmetrics/FieldCountInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/classmetrics/FieldCountInspection.java new file mode 100644 index 000000000000..c39f3d00fa5e --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/classmetrics/FieldCountInspection.java @@ -0,0 +1,25 @@ +package com.siyeh.igtest.classmetrics; + +public class FieldCountInspection +{ + public static final int CONSTANT = 3; + public static final int CONSTANT1 = 3; + public static final int CONSTANT2 = 3; + public static final int CONSTANT3 = 3; + public static final int CONSTANT4 = 3; + public static final int CONSTANT5 = 3; + private int m_aaa; + private int m_bbb; + private int m_ccc; + private int m_ddd; + private int m_eee; + private int m_fff; + private int m_ggg; + private int m_hhh; + private int m_iii; + private int m_jjj; + private int m_kkk; + private int m_lll; + private int m_mmm; + private int m_nnn; +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/classmetrics/Grandparent.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/classmetrics/Grandparent.java new file mode 100644 index 000000000000..a8c364c18a56 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/classmetrics/Grandparent.java @@ -0,0 +1,5 @@ +package com.siyeh.igtest.classmetrics; + +public class Grandparent +{ +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/classmetrics/MethodCountInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/classmetrics/MethodCountInspection.java new file mode 100644 index 000000000000..51b2abeaf530 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/classmetrics/MethodCountInspection.java @@ -0,0 +1,84 @@ +package com.siyeh.igtest.classmetrics; + +public class MethodCountInspection +{ + public void aaa(){} + + public void bbb(){} + + public void ccc(){} + + public void ddd(){} + + public void eee(){} + + public void fff(){} + + public void ggg(){} + + public void hhh(){} + + public void iii(){} + + public void jjj(){} + + public void kkk(){} + + public void lll(){} + + public void mmm(){} + + public void nnn(){} + + public void ooo(){} + + public void ppp(){} + + public void qqq(){} + + public void rrr(){} + + public void sss(){} + + public void ttt(){} + + public void aaa2(){} + + public void bbb2(){} + + public void ccc2(){} + + public void ddd2(){} + + public void eee2(){} + + public void fff2(){} + + public void ggg2(){} + + public void hhh2(){} + + public void iii2(){} + + public void jjj2(){} + + public void kkk2(){} + + public void lll2(){} + + public void mmm2(){} + + public void nnn2(){} + + public void ooo2(){} + + public void ppp2(){} + + public void qqq2(){} + + public void rrr2(){} + + public void sss2(){} + + public void ttt2(){} +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/classmetrics/Parent.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/classmetrics/Parent.java new file mode 100644 index 000000000000..35b5771f9321 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/classmetrics/Parent.java @@ -0,0 +1,5 @@ +package com.siyeh.igtest.classmetrics; + +public class Parent extends Grandparent +{ +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/cloneable/CloneCallsConstructorInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/cloneable/CloneCallsConstructorInspection.java new file mode 100644 index 000000000000..46814725bfb6 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/cloneable/CloneCallsConstructorInspection.java @@ -0,0 +1,15 @@ +package com.siyeh.igtest.cloneable; + +public class CloneCallsConstructorInspection implements Cloneable +{ + + public void foo() + { + + } + + public Object clone() + { + return new CloneCallsConstructorInspection(); + } +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/cloneable/CloneCallsSuperCloneInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/cloneable/CloneCallsSuperCloneInspection.java new file mode 100644 index 000000000000..2d18b36fdcae --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/cloneable/CloneCallsSuperCloneInspection.java @@ -0,0 +1,15 @@ +package com.siyeh.igtest.cloneable; + +public class CloneCallsSuperCloneInspection implements Cloneable +{ + + public void foo() + { + + } + + public Object clone() + { + return this; + } +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/cloneable/CloneDeclaresCloneNonSupportedExceptionInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/cloneable/CloneDeclaresCloneNonSupportedExceptionInspection.java new file mode 100644 index 000000000000..1635b005565e --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/cloneable/CloneDeclaresCloneNonSupportedExceptionInspection.java @@ -0,0 +1,22 @@ +package com.siyeh.igtest.cloneable; + +public class CloneDeclaresCloneNonSupportedExceptionInspection implements Cloneable +{ + + public void foo() + { + + } + + public Object clone() + { + try + { + return super.clone(); + } + catch(CloneNotSupportedException e) + { + return null; + } + } +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/cloneable/CloneableDeclaresCloneInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/cloneable/CloneableDeclaresCloneInspection.java new file mode 100644 index 000000000000..356ab7a935b2 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/cloneable/CloneableDeclaresCloneInspection.java @@ -0,0 +1,10 @@ +package com.siyeh.igtest.cloneable; + +public class CloneableDeclaresCloneInspection implements Cloneable +{ + + public void foo() + { + + } +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/confusing/AssignmentToCatchParameterInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/confusing/AssignmentToCatchParameterInspection.java new file mode 100644 index 000000000000..df5b48e50c98 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/confusing/AssignmentToCatchParameterInspection.java @@ -0,0 +1,18 @@ +package com.siyeh.igtest.confusing; + +public class AssignmentToCatchParameterInspection +{ + public AssignmentToCatchParameterInspection() + { + } + + public void fooBar(int bar, int baz) + { + try { + } catch (Exception e) { + e = new Exception(); + e.printStackTrace(); + } + + } +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/confusing/AssignmentToForLoopParameterInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/confusing/AssignmentToForLoopParameterInspection.java new file mode 100644 index 000000000000..2a6932132d12 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/confusing/AssignmentToForLoopParameterInspection.java @@ -0,0 +1,31 @@ +package com.siyeh.igtest.confusing; + +public class AssignmentToForLoopParameterInspection +{ + public AssignmentToForLoopParameterInspection() + { + } + + public void fooBar(int bar, int baz) + { + + for(int i = 0; i < 5; i++) + { + for(int j = 0; j < 5; i++) + { + + } + } + for(int j = 0; j < 5; j++) + { + j = 2; + } + for(int k = 0; k < 5; k++) + { + k++; + k--; + ++k; + --k; + } + } +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/confusing/AssignmentToParameterInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/confusing/AssignmentToParameterInspection.java new file mode 100644 index 000000000000..34fe6d8e7922 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/confusing/AssignmentToParameterInspection.java @@ -0,0 +1,23 @@ +package com.siyeh.igtest.confusing; + +public class AssignmentToParameterInspection +{ + public AssignmentToParameterInspection() + { + } + + public void fooBar(int bar, int baz) + { + try { + bar = 0; + System.out.println("bar = " + bar); + baz = 0; + System.out.println("baz = " + baz); + baz++; + --baz; + } catch (Exception e) { + e.printStackTrace(); + } + + } +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/confusing/BreakInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/confusing/BreakInspection.java new file mode 100644 index 000000000000..6749b2e285f5 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/confusing/BreakInspection.java @@ -0,0 +1,21 @@ +package com.siyeh.igtest.confusing; + +public class BreakInspection +{ + + public static void main(String[] args) + { + for(int i = 0; i < 4; i++) + { + if(i == 2) + { + break; + } + if(i == 3) + { + break; + } + System.out.println("i = " + i); + } + } +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/confusing/CastThatLosesPrecisionInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/confusing/CastThatLosesPrecisionInspection.java new file mode 100644 index 000000000000..2a799f4093d9 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/confusing/CastThatLosesPrecisionInspection.java @@ -0,0 +1,41 @@ +package com.siyeh.igtest.confusing; + +public class CastThatLosesPrecisionInspection +{ + public CastThatLosesPrecisionInspection() + { + } + + public void fooBar() + { + byte b; + int i; + char ch; + long l = 0L; + double d = 0.0; + float f = 0.0f; + + i = (int) f; + System.out.println("i = " + i); + ch = (char) d; + System.out.println("ch = " + ch); + i = (int) d; + System.out.println("i = " + i); + i = (int) l; + System.out.println("i = " + i); + b = (byte) l; + System.out.println("b = " + b); + + l = (long) d; + System.out.println("l = " + l); + l = (long) f; + System.out.println("l = " + l); + + d = (double) f; + System.out.println("d = " + d); + + f = (float) d; + System.out.println("f = " + f); + } + +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/confusing/ChainedEqualityInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/confusing/ChainedEqualityInspection.java new file mode 100644 index 000000000000..a3c14b552634 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/confusing/ChainedEqualityInspection.java @@ -0,0 +1,20 @@ +package com.siyeh.igtest.confusing; + +public class ChainedEqualityInspection +{ + public void fooBar() + { + boolean foo = fooBaz(); + boolean bar = fooBaz(); + boolean barangus = fooBaz(); + if(foo == bar == barangus) + { + System.out.println(""); + } + } + + private boolean fooBaz() + { + return true; + } +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/confusing/ConditionalExpressionInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/confusing/ConditionalExpressionInspection.java new file mode 100644 index 000000000000..2f70af28d9e3 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/confusing/ConditionalExpressionInspection.java @@ -0,0 +1,11 @@ +package com.siyeh.igtest.confusing; + +public class ConditionalExpressionInspection +{ + + public static void main(String[] args) + { + final int foo = (3<5)?3:5; + System.out.println("foo = " + foo); + } +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/confusing/ConfusingElseInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/confusing/ConfusingElseInspection.java new file mode 100644 index 000000000000..5b76c7657e92 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/confusing/ConfusingElseInspection.java @@ -0,0 +1,26 @@ +package com.siyeh.igtest.confusing; + +public class ConfusingElseInspection +{ + public static void main(String[] args) + { + if(foo()) + { + return; + } + else + { + System.out.println("ConfusingElseInspection.main"); + } + bar(); + } + + private static void bar() + { + } + + private static boolean foo() + { + return true; + } +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/confusing/ConfusingFloatingPointLiteralInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/confusing/ConfusingFloatingPointLiteralInspection.java new file mode 100644 index 000000000000..065906f0881a --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/confusing/ConfusingFloatingPointLiteralInspection.java @@ -0,0 +1,18 @@ +package com.siyeh.igtest.confusing; + +public class ConfusingFloatingPointLiteralInspection +{ + double baz = 0e6; + double baz2 = 0.e6; + double baz3 = 0.0e6; + double baz4 = 0.0e-6; + double baz5 = 0.0e-6; + double foo = 3.0; + double barangus2 = .03; + double barangus = 3.; + float bazf = 0e6f; + float baz2f = 0.e6f; + float baz3f = 0.0e6f; + float foof = 3.0f; + float barangus2f = .03f; + float barangusf = 3.f;} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/confusing/ConfusingOctalEscapeInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/confusing/ConfusingOctalEscapeInspection.java new file mode 100644 index 000000000000..ce4da03d70e5 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/confusing/ConfusingOctalEscapeInspection.java @@ -0,0 +1,6 @@ +package com.siyeh.igtest.confusing; + +public class ConfusingOctalEscapeInspection { + public static final String foo = "asdf\01234"; + public static final String boo = "asdf\01834"; +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/confusing/ContinueInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/confusing/ContinueInspection.java new file mode 100644 index 000000000000..087afe92c2ea --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/confusing/ContinueInspection.java @@ -0,0 +1,21 @@ +package com.siyeh.igtest.confusing; + +public class ContinueInspection +{ + + public static void main(String[] args) + { + Label: + while(true) + { + for(int i = 0;i<4;i++) + { + if(i == 2) + { + continue; + } + System.out.println("i = " + i); + } + } + } +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/confusing/IfStatementWithTooManyBranches.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/confusing/IfStatementWithTooManyBranches.java new file mode 100644 index 000000000000..ed05f4a31c14 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/confusing/IfStatementWithTooManyBranches.java @@ -0,0 +1,26 @@ +package com.siyeh.igtest.confusing; + +public class IfStatementWithTooManyBranches +{ + public void foo() + { + final int x = barangus(); + if(x == 1){ + } else if(x == 2){ + } else if(x == 3){ + } else if(x == 4){ + } else if(x == 5){ + } else if(x == 6){ + } else if(x == 7){ + } else if(x == 8){ + } else if(x == 9){ + } else if(x == 10){ + } else if(x == 11){ + } + } + + private int barangus() + { + return 3; + } +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/confusing/ImplicitNumericConversionInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/confusing/ImplicitNumericConversionInspection.java new file mode 100644 index 000000000000..a5353454aa2c --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/confusing/ImplicitNumericConversionInspection.java @@ -0,0 +1,71 @@ +package com.siyeh.igtest.confusing; + +public class ImplicitNumericConversionInspection +{ + public ImplicitNumericConversionInspection() + { + } + + public void fooBar() + { + final int i = 0; + final char ch = (char) 0; + final long l = 0L; + final double d = 0.0; + float f = (float)1.0; + + f = f+1; + f = i; + + useInt(i); + useInt('c'); + useInt(ch); + + useDouble(0); + useDouble(0.0F); + useDouble(i); + useDouble(ch); + useDouble(l); + useDouble(d); + useDouble(f); + useDouble(1.0); + useDouble(1.0F); + + useFloat(0); + useFloat(0L); + useFloat(0.0F); + useFloat(i); + useFloat(ch); + useFloat(l); + useFloat(f); + useFloat(1.0F); + + useLong(i); + useLong(ch); + useLong(l); + useLong(3L); + useLong(3L); + } + + private int useLong(long l) + { + System.out.println(l); + return (int) l; + } + + private int useInt(int i) + { + System.out.println(i); + return i; + } + + private void useDouble(double d) + { + System.out.println(d); + } + + private void useFloat(float d) + { + System.out.println(d); + } +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/confusing/IncrementDecrementInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/confusing/IncrementDecrementInspection.java new file mode 100644 index 000000000000..e61a788952ef --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/confusing/IncrementDecrementInspection.java @@ -0,0 +1,21 @@ +package com.siyeh.igtest.confusing; + +public class IncrementDecrementInspection +{ + public IncrementDecrementInspection() + { + } + + public void foo() + { + final int[] baz = new int[3]; + int i = 0; + i++; + final int val = baz[i++]; + final int val2 = baz[i--]; + final int val3 = baz[++i]; + final int val4 = baz[--i]; + System.out.println("i = " + i); + System.out.println("val = " + val); + } +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/confusing/LabeledBreakInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/confusing/LabeledBreakInspection.java new file mode 100644 index 000000000000..7488a7a2aa33 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/confusing/LabeledBreakInspection.java @@ -0,0 +1,21 @@ +package com.siyeh.igtest.confusing; + +public class LabeledBreakInspection +{ + + public static void main(String[] args) + { + Label: + while(true) + { + for(int i = 0; i < 4; i++) + { + if(i == 2) + { + break Label; + } + System.out.println("i = " + i); + } + } + } +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/confusing/LabeledContinueInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/confusing/LabeledContinueInspection.java new file mode 100644 index 000000000000..46a67e709bbd --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/confusing/LabeledContinueInspection.java @@ -0,0 +1,21 @@ +package com.siyeh.igtest.confusing; + +public class LabeledContinueInspection +{ + + public static void main(String[] args) + { + Label: + while (true) + { + for (int i = 0; i < 4; i++) + { + if (i == 2) + { + continue Label; + } + System.out.println("i = " + i); + } + } + } +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/confusing/LongLiteralWithLowercaseLInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/confusing/LongLiteralWithLowercaseLInspection.java new file mode 100644 index 000000000000..e14144848739 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/confusing/LongLiteralWithLowercaseLInspection.java @@ -0,0 +1,22 @@ +package com.siyeh.igtest.confusing; + +public class LongLiteralWithLowercaseLInspection +{ + public static final long s_foo = 3l; + public static final long s_bar = 3L; + + public LongLiteralWithLowercaseLInspection() + { + } + + public void foo() + { + System.out.println("s_bar = " + s_bar); + System.out.println("s_foo = " + s_foo); + + final long foo = 3l; + final long bar = 3L; + System.out.println("bar = " + bar); + System.out.println("foo = " + foo); + } +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/confusing/MethodNamesDifferOnlyByCaseInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/confusing/MethodNamesDifferOnlyByCaseInspection.java new file mode 100644 index 000000000000..23b76e0d99ff --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/confusing/MethodNamesDifferOnlyByCaseInspection.java @@ -0,0 +1,15 @@ +package com.siyeh.igtest.confusing; + +public class MethodNamesDifferOnlyByCaseInspection +{ + public void fooBar() + { + + } + + public void fooBAr() + { + + } + +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/confusing/NegatedConditionalInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/confusing/NegatedConditionalInspection.java new file mode 100644 index 000000000000..ad43cabf07bb --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/confusing/NegatedConditionalInspection.java @@ -0,0 +1,19 @@ +package com.siyeh.igtest.confusing; + +public class NegatedConditionalInspection +{ + + public static void main(String[] args) + { + final boolean foo = baz(); + final boolean bar = baz(); + final Object bazoom = new Object(); + final boolean out = (foo != bar)?bar:foo; + + } + + private static boolean baz() + { + return true; + } +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/confusing/NegatedIfInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/confusing/NegatedIfInspection.java new file mode 100644 index 000000000000..dbb8e0fc11fc --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/confusing/NegatedIfInspection.java @@ -0,0 +1,33 @@ +package com.siyeh.igtest.confusing; + +public class NegatedIfInspection +{ + + public static void main(String[] args) + { + final boolean foo = baz(); + final boolean bar = baz(); + final Object bazoom = new Object(); + if(foo != bar) + { + System.out.println(""); + } + else + { + System.out.println(""); + } + if(bazoom != null) + { + System.out.println(""); + } + else + { + System.out.println(""); + } + } + + private static boolean baz() + { + return true; + } +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/confusing/NestedAssignmentInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/confusing/NestedAssignmentInspection.java new file mode 100644 index 000000000000..e48d2c2a49be --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/confusing/NestedAssignmentInspection.java @@ -0,0 +1,21 @@ +package com.siyeh.igtest.confusing; + +public class NestedAssignmentInspection +{ + public NestedAssignmentInspection() + { + } + + public void foo() + { + final int[] baz = new int[3]; + final int i; + final int val = baz[i=2]; + System.out.println("i = " + i); + System.out.println("val = " + val); + for(int j=0,k=0;j<1000;j += 1,k += 1) + { + + } + } +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/confusing/NestedConditionalInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/confusing/NestedConditionalInspection.java new file mode 100644 index 000000000000..1f2154015d44 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/confusing/NestedConditionalInspection.java @@ -0,0 +1,19 @@ +package com.siyeh.igtest.confusing; + +public class NestedConditionalInspection +{ + public NestedConditionalInspection() + { + } + + public void foo() + { + final int val = bar()?3:(bar()?4:5); + System.out.println("val = " + val); + } + + private boolean bar() + { + return true; + } +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/confusing/NestedMethodCallInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/confusing/NestedMethodCallInspection.java new file mode 100644 index 000000000000..e700bc5c683f --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/confusing/NestedMethodCallInspection.java @@ -0,0 +1,35 @@ +package com.siyeh.igtest.confusing; + +import java.util.ArrayList; + +public class NestedMethodCallInspection extends ArrayList{ + private int baz = bar(foo()); + + public NestedMethodCallInspection(int initialCapacity) { + super(Math.abs(initialCapacity)); + } + + public NestedMethodCallInspection() { + this(Math.abs(3)); + } + + public int foo() + { + return 3; + } + public int bar(int val) + { + return 3+val; + } + + public int baz() + { + bar(Math.abs(3)); + return bar(foo()); + } + + public int barangus() + { + return bar(foo()+3); + } +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/confusing/NestedSwitchStatementInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/confusing/NestedSwitchStatementInspection.java new file mode 100644 index 000000000000..f092cdc4f790 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/confusing/NestedSwitchStatementInspection.java @@ -0,0 +1,35 @@ +package com.siyeh.igtest.confusing; + +public class NestedSwitchStatementInspection +{ + public NestedSwitchStatementInspection() + { + } + + public void foo() + { + switch(bar()) + { + case 3: + break; + case 4: + switch(bar()) + { + case 3: + break; + case 4: + break; + default: + break; + } + break; + default: + break; + } + } + + private int bar() + { + return 3; + } +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/confusing/SwitchStatementWithConfusingDeclaration.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/confusing/SwitchStatementWithConfusingDeclaration.java new file mode 100644 index 000000000000..bd4d476b85ca --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/confusing/SwitchStatementWithConfusingDeclaration.java @@ -0,0 +1,18 @@ +package com.siyeh.igtest.confusing; + +public class SwitchStatementWithConfusingDeclaration +{ + public static void main(String[] args) + { + switch(3) + { + case 2: + int x = 0; + break; + case 3: + x = 3; + System.out.println(x); + break; + } + } +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/confusing/SwitchStatementWithTooManyCases.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/confusing/SwitchStatementWithTooManyCases.java new file mode 100644 index 000000000000..44a223f8011d --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/confusing/SwitchStatementWithTooManyCases.java @@ -0,0 +1,41 @@ +package com.siyeh.igtest.confusing; + +public class SwitchStatementWithTooManyCases +{ + public void foo() + { + final int x = barangus(); + switch(x) + { + case 1: + break; + case 2: + break; + case 3: + break; + case 4: + break; + case 5: + break; + case 6: + break; + case 7: + break; + case 8: + break; + case 9: + break; + case 10: + break; + case 11: + break; + default: + break; + } + } + + private int barangus() + { + return 3; + } +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/encapsulation/AssignmentToCollectionFieldFromParameterInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/encapsulation/AssignmentToCollectionFieldFromParameterInspection.java new file mode 100644 index 000000000000..261433f988af --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/encapsulation/AssignmentToCollectionFieldFromParameterInspection.java @@ -0,0 +1,34 @@ +package com.siyeh.igtest.encapsulation; + +import java.util.Set; +import java.util.HashSet; +import java.util.List; + +public class AssignmentToCollectionFieldFromParameterInspection +{ + private Set m_foo; + //private List m_fooBar; + private int[] m_bar; + + public static void main(String[] args) + { + new AssignmentToCollectionFieldFromParameterInspection(new HashSet(4)); + } +/* + + public AssignmentToCollectionFieldFromParameterInspection(List fooBar) + { + m_fooBar = fooBar; + } +*/ + + public AssignmentToCollectionFieldFromParameterInspection(Set foo) + { + m_foo = foo; + } + + public AssignmentToCollectionFieldFromParameterInspection(int[] bar) + { + m_bar = bar; + } +} \ No newline at end of file diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/encapsulation/AssignmentToDateFieldFromParameterInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/encapsulation/AssignmentToDateFieldFromParameterInspection.java new file mode 100644 index 000000000000..d24fb2995c47 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/encapsulation/AssignmentToDateFieldFromParameterInspection.java @@ -0,0 +1,32 @@ +package com.siyeh.igtest.encapsulation; + +import java.util.Calendar; +import java.util.Date; + +public class AssignmentToDateFieldFromParameterInspection +{ + private Date m_foo; + private Calendar m_bar; + + public static void main(String[] args) + { + new AssignmentToDateFieldFromParameterInspection(new Date()); + } +/* + + public AssignmentToCollectionFieldFromParameterInspection(List fooBar) + { + m_fooBar = fooBar; + } +*/ + + public AssignmentToDateFieldFromParameterInspection(Date foo) + { + m_foo = foo; + } + + public AssignmentToDateFieldFromParameterInspection(Calendar bar) + { + m_bar = bar; + } +} \ No newline at end of file diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/encapsulation/PackageVisibleFieldInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/encapsulation/PackageVisibleFieldInspection.java new file mode 100644 index 000000000000..b8145c5073af --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/encapsulation/PackageVisibleFieldInspection.java @@ -0,0 +1,10 @@ +package com.siyeh.igtest.encapsulation; + +import java.util.Set; +import java.util.HashSet; + +public class PackageVisibleFieldInspection +{ + int m_barargus = -1; + +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/encapsulation/PackageVisibleInnerClassInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/encapsulation/PackageVisibleInnerClassInspection.java new file mode 100644 index 000000000000..166939029774 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/encapsulation/PackageVisibleInnerClassInspection.java @@ -0,0 +1,19 @@ +package com.siyeh.igtest.encapsulation; + +import java.util.Set; +import java.util.HashSet; + +public class PackageVisibleInnerClassInspection +{ + class Barangus + { + + public Barangus(int val) + { + this.val = val; + } + + int val = -1; + } + +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/encapsulation/ProtectedFieldInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/encapsulation/ProtectedFieldInspection.java new file mode 100644 index 000000000000..1bd8311e778d --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/encapsulation/ProtectedFieldInspection.java @@ -0,0 +1,10 @@ +package com.siyeh.igtest.encapsulation; + +import java.util.Set; +import java.util.HashSet; + +public class ProtectedFieldInspection +{ + protected int m_barangus = -1; + +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/encapsulation/ProtectedInnerClassInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/encapsulation/ProtectedInnerClassInspection.java new file mode 100644 index 000000000000..9565fe1cb30f --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/encapsulation/ProtectedInnerClassInspection.java @@ -0,0 +1,19 @@ +package com.siyeh.igtest.encapsulation; + +import java.util.Set; +import java.util.HashSet; + +public class ProtectedInnerClassInspection +{ + protected class Barangus + { + + public Barangus(int val) + { + this.val = val; + } + + int val = -1; + } + +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/encapsulation/PublicFieldInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/encapsulation/PublicFieldInspection.java new file mode 100644 index 000000000000..70cd883826ec --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/encapsulation/PublicFieldInspection.java @@ -0,0 +1,8 @@ +package com.siyeh.igtest.encapsulation; + + +public class PublicFieldInspection +{ + public int m_barangus = -1; + +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/encapsulation/PublicInnerClassInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/encapsulation/PublicInnerClassInspection.java new file mode 100644 index 000000000000..53acd8a353c3 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/encapsulation/PublicInnerClassInspection.java @@ -0,0 +1,16 @@ +package com.siyeh.igtest.encapsulation; + +public class PublicInnerClassInspection +{ + public class Barangus + { + + public Barangus(int val) + { + this.val = val; + } + + int val = -1; + } + +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/encapsulation/ReturnOfCollectionFieldInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/encapsulation/ReturnOfCollectionFieldInspection.java new file mode 100644 index 000000000000..80e659bdff78 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/encapsulation/ReturnOfCollectionFieldInspection.java @@ -0,0 +1,39 @@ +package com.siyeh.igtest.encapsulation; + +import java.util.*; + +public class ReturnOfCollectionFieldInspection +{ + private Set m_foo; + // private List m_fooBar; + private int[] m_bar; + + public static void main(String[] args) + { + new ReturnOfCollectionFieldInspection(new HashSet(4)); + } + + public ReturnOfCollectionFieldInspection(Set foo) + { + m_foo = Collections.unmodifiableSet(foo); + } + + public Set foo() + { + return m_foo; + } +/* + + public List fooBar() + { + return m_fooBar; + } +*/ + + public int[] bar() + { + return m_bar; + } + + +} \ No newline at end of file diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/encapsulation/ReturnOfDateFieldInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/encapsulation/ReturnOfDateFieldInspection.java new file mode 100644 index 000000000000..723bbf7a1183 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/encapsulation/ReturnOfDateFieldInspection.java @@ -0,0 +1,39 @@ +package com.siyeh.igtest.encapsulation; + +import java.util.*; + +public class ReturnOfDateFieldInspection +{ + private Date m_foo; + // private List m_fooBar; + private Calendar m_bar; + + public static void main(String[] args) + { + new ReturnOfDateFieldInspection(new Date()); + } + + public ReturnOfDateFieldInspection(Date foo) + { + m_foo = new Date(foo.getTime()); + } + + public Date foo() + { + return m_foo; + } +/* + + public List fooBar() + { + return m_fooBar; + } +*/ + + public Calendar bar() + { + return m_bar; + } + + +} \ No newline at end of file diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/exceptionHandling/CatchGenericClassInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/exceptionHandling/CatchGenericClassInspection.java new file mode 100644 index 000000000000..c1138d37a6ef --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/exceptionHandling/CatchGenericClassInspection.java @@ -0,0 +1,98 @@ +package com.siyeh.igtest.exceptionHandling; + +public class CatchGenericClassInspection +{ + public void foo() throws Throwable + { + if(bar()) + { + try + { + } + catch(Exception e) + { + System.out.println("foo"); + } + } + if(bar()) + { + try + { + } + catch(RuntimeException e) + { + System.out.println("foo"); + } + } + if(bar()) + { + try + { + } + catch(Throwable e) + { + System.out.println("foo"); + } + } + if(bar()) + { + try + { + } + catch(Error e) + { + System.out.println("foo"); + } + } + if(bar()) + { + try + { + throw new Exception(); + } + catch(Exception e) + { + System.out.println("foo"); + } + } + if(bar()) + { + try + { + throw new RuntimeException(); + } + catch(RuntimeException e) + { + System.out.println("foo"); + } + } + if(bar()) + { + try + { + throw new Throwable(); + } + catch(Throwable e) + { + System.out.println("foo"); + } + } + if(bar()) + { + try + { + throw new Error(); + } + catch(Error e) + { + System.out.println("foo"); + } + } + } + + private boolean bar() + { + return true; + } + +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/exceptionHandling/ContinueOrBreakFromFinallyBlockInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/exceptionHandling/ContinueOrBreakFromFinallyBlockInspection.java new file mode 100644 index 000000000000..c8653e223595 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/exceptionHandling/ContinueOrBreakFromFinallyBlockInspection.java @@ -0,0 +1,23 @@ +package com.siyeh.igtest.exceptionHandling; + +public class ContinueOrBreakFromFinallyBlockInspection { + public void foo() { + while (true) { + try { + + } finally { + break; + } + } + } + + public int bar() { + while (true) { + try { + + } finally { + continue; + } + } + } +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/exceptionHandling/EmptyCatchBlockInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/exceptionHandling/EmptyCatchBlockInspection.java new file mode 100644 index 000000000000..b03a0247fbea --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/exceptionHandling/EmptyCatchBlockInspection.java @@ -0,0 +1,23 @@ +package com.siyeh.igtest.exceptionHandling; + +public class EmptyCatchBlockInspection +{ + public void foo() + { + try + { + throw new Exception(); + } + catch(Exception e) + { + } + try + { + throw new Exception(); + } + catch(Exception e) + { + //catch comment + } + } +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/exceptionHandling/EmptyCatchBlockInspectionInTestCase.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/exceptionHandling/EmptyCatchBlockInspectionInTestCase.java new file mode 100644 index 000000000000..b79d71a19032 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/exceptionHandling/EmptyCatchBlockInspectionInTestCase.java @@ -0,0 +1,25 @@ +package com.siyeh.igtest.exceptionHandling; + +import junit.framework.TestCase; + +public class EmptyCatchBlockInspectionInTestCase extends TestCase +{ + public void foo() + { + try + { + throw new Exception(); + } + catch(Exception e) + { + } + try + { + throw new Exception(); + } + catch(Exception e) + { + //catch comment + } + } +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/exceptionHandling/EmptyFinallyBlockInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/exceptionHandling/EmptyFinallyBlockInspection.java new file mode 100644 index 000000000000..196f74f4f199 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/exceptionHandling/EmptyFinallyBlockInspection.java @@ -0,0 +1,26 @@ +package com.siyeh.igtest.exceptionHandling; + +public class EmptyFinallyBlockInspection +{ + public void foo() + { + try + { + + } + finally + { + } + } + + public int bar() + { + try + { + return 4; + } + finally + { + } + } +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/exceptionHandling/ErrorRethrownInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/exceptionHandling/ErrorRethrownInspection.java new file mode 100644 index 000000000000..6dcba83d5d06 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/exceptionHandling/ErrorRethrownInspection.java @@ -0,0 +1,44 @@ +package com.siyeh.igtest.exceptionHandling; + +public class ErrorRethrownInspection +{ + public void foo() + { + try + { + System.out.println("foo"); + } + catch(Error e) + { + e.printStackTrace(); + } + + try + { + System.out.println("foo"); + } + catch(Error e) + { + e.printStackTrace(); + throw e; + } + + try + { + System.out.println("foo"); + } + catch(OutOfMemoryError e) + { + e.printStackTrace(); + throw e; + } + try + { + System.out.println("foo"); + } + catch(OutOfMemoryError e) + { + e.printStackTrace(); + } + } +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/exceptionHandling/ExceptionWrappedInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/exceptionHandling/ExceptionWrappedInspection.java new file mode 100644 index 000000000000..515470d79867 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/exceptionHandling/ExceptionWrappedInspection.java @@ -0,0 +1,44 @@ +package com.siyeh.igtest.exceptionHandling; + +public class ExceptionWrappedInspection +{ + public void foo() throws Exception + { + try + { + System.out.println("foo"); + } + catch(Error e) + { + throw new Exception(); + } + + try + { + System.out.println("foo"); + } + catch(Error e) + { + e.printStackTrace(); + throw e; + } + + try + { + System.out.println("foo"); + } + catch(OutOfMemoryError e) + { + e.printStackTrace(); + throw e; + } + try + { + System.out.println("foo"); + } + catch(OutOfMemoryError e) + { + throw new IllegalAccessError(); + } + } +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/exceptionHandling/MyCheckedException.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/exceptionHandling/MyCheckedException.java new file mode 100644 index 000000000000..f5ea803bf1d4 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/exceptionHandling/MyCheckedException.java @@ -0,0 +1,23 @@ +package com.siyeh.igtest.exceptionHandling; + +public class MyCheckedException extends Exception +{ + public MyCheckedException() + { + } + + public MyCheckedException(String message) + { + super(message); + } + + public MyCheckedException(String message, Throwable cause) + { + super(message, cause); + } + + public MyCheckedException(Throwable cause) + { + super(cause); + } +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/exceptionHandling/MyUncheckedException.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/exceptionHandling/MyUncheckedException.java new file mode 100644 index 000000000000..6c56297ebd2a --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/exceptionHandling/MyUncheckedException.java @@ -0,0 +1,23 @@ +package com.siyeh.igtest.exceptionHandling; + +public class MyUncheckedException extends RuntimeException +{ + public MyUncheckedException() + { + } + + public MyUncheckedException(String message) + { + super(message); + } + + public MyUncheckedException(String message, Throwable cause) + { + super(message, cause); + } + + public MyUncheckedException(Throwable cause) + { + super(cause); + } +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/exceptionHandling/NestedTryStatementInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/exceptionHandling/NestedTryStatementInspection.java new file mode 100644 index 000000000000..8540a09cc111 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/exceptionHandling/NestedTryStatementInspection.java @@ -0,0 +1,23 @@ +package com.siyeh.igtest.exceptionHandling; + +public class NestedTryStatementInspection +{ + public void foo() + { + try + { + try + { + System.out.println("NestedTryStatementInspection.foo"); + } + finally + { + + } + } + finally + { + + } + } +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/exceptionHandling/ReturnFromFinallyBlockInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/exceptionHandling/ReturnFromFinallyBlockInspection.java new file mode 100644 index 000000000000..002bdec7eff9 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/exceptionHandling/ReturnFromFinallyBlockInspection.java @@ -0,0 +1,28 @@ +package com.siyeh.igtest.exceptionHandling; + +public class ReturnFromFinallyBlockInspection +{ + public void foo() + { + try + { + + } + finally + { + return; + } + } + + public int bar() + { + try + { + return 4; + } + finally + { + return 3; + } + } +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/exceptionHandling/ThreadDeathRethrownInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/exceptionHandling/ThreadDeathRethrownInspection.java new file mode 100644 index 000000000000..1a262c8759b0 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/exceptionHandling/ThreadDeathRethrownInspection.java @@ -0,0 +1,26 @@ +package com.siyeh.igtest.exceptionHandling; + +public class ThreadDeathRethrownInspection +{ + public void foo() + { + try + { + System.out.println("foo"); + } + catch(ThreadDeath e) + { + e.printStackTrace(); + } + + try + { + System.out.println("foo"); + } + catch(ThreadDeath e) + { + e.printStackTrace(); + throw e; + } + } +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/exceptionHandling/ThrowCaughtLocallInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/exceptionHandling/ThrowCaughtLocallInspection.java new file mode 100644 index 000000000000..f9ce009a3e74 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/exceptionHandling/ThrowCaughtLocallInspection.java @@ -0,0 +1,40 @@ +package com.siyeh.igtest.exceptionHandling; + +public class ThrowCaughtLocallInspection +{ + public void foo() throws Exception + { + try { + throw new MyCheckedException(); + } catch (MyCheckedException e) { + e.printStackTrace(); //TODO + } + try { + throw new MyCheckedException(); + } catch (Exception e) { + e.printStackTrace(); //TODO + } + + try { + throw new MyCheckedException(); + } catch (MyUncheckedException e) { + if (false) { + throw new MyUncheckedException(e); + } else { + } + } + + try { + try { + throw new MyCheckedException(); + } catch (MyUncheckedException e) { + e.printStackTrace(); //TODO + + } + } catch (MyCheckedException e) { + e.printStackTrace(); //TODO + } + } + + +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/exceptionHandling/ThrowFromFinallyBlockInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/exceptionHandling/ThrowFromFinallyBlockInspection.java new file mode 100644 index 000000000000..d006df6f1b55 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/exceptionHandling/ThrowFromFinallyBlockInspection.java @@ -0,0 +1,36 @@ +package com.siyeh.igtest.exceptionHandling; + +public class ThrowFromFinallyBlockInspection +{ + public void foo() throws Exception + { + try + { + return; + } + finally + { + throw new Exception(); + } + } + + public void bar() throws Exception + { + try + { + return; + } + finally + { + try + { + throw new Exception(); + } + finally + { + throw new Exception(); + } + } + } + +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/exceptionHandling/ThrowGenericClassInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/exceptionHandling/ThrowGenericClassInspection.java new file mode 100644 index 000000000000..f1029c1ee2c2 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/exceptionHandling/ThrowGenericClassInspection.java @@ -0,0 +1,30 @@ +package com.siyeh.igtest.exceptionHandling; + +public class ThrowGenericClassInspection +{ + public void foo() throws Throwable + { + if(bar()) + { + throw new Exception(); + } + if(bar()) + { + throw new RuntimeException(); + } + if(bar()) + { + throw new Throwable(); + } + if(bar()) + { + throw new Error(); + } + } + + private boolean bar() + { + return true; + } + +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/exceptionHandling/UnusedCatchParameterInspectionInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/exceptionHandling/UnusedCatchParameterInspectionInspection.java new file mode 100644 index 000000000000..b11151a06dcc --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/exceptionHandling/UnusedCatchParameterInspectionInspection.java @@ -0,0 +1,23 @@ +package com.siyeh.igtest.exceptionHandling; + +public class UnusedCatchParameterInspectionInspection +{ + public void foo() + { + try + { + throw new Exception(); + } + catch(Exception e) + { + } + try + { + throw new Exception(); + } + catch(Exception e) + { + //catch comment + } + } +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/finalization/FinalizeDoesntCallSuperFinalizeInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/finalization/FinalizeDoesntCallSuperFinalizeInspection.java new file mode 100644 index 000000000000..6b686242b694 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/finalization/FinalizeDoesntCallSuperFinalizeInspection.java @@ -0,0 +1,13 @@ +package com.siyeh.igtest.finalization; + +public class FinalizeDoesntCallSuperFinalizeInspection +{ + public FinalizeDoesntCallSuperFinalizeInspection() + { + } + + protected void finalize() + { + + } +} \ No newline at end of file diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/finalization/FinalizeInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/finalization/FinalizeInspection.java new file mode 100644 index 000000000000..5bb781525cde --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/finalization/FinalizeInspection.java @@ -0,0 +1,15 @@ +package com.siyeh.igtest.finalization; + +public class FinalizeInspection +{ + public FinalizeInspection() throws Throwable + { + super(); + } + + protected void finalize() throws Throwable + { + super.finalize(); + } + +} \ No newline at end of file diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/finalization/FinalizeNotProtectedInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/finalization/FinalizeNotProtectedInspection.java new file mode 100644 index 000000000000..f135ad3ed048 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/finalization/FinalizeNotProtectedInspection.java @@ -0,0 +1,13 @@ +package com.siyeh.igtest.finalization; + +public class FinalizeNotProtectedInspection +{ + public FinalizeNotProtectedInspection() + { + } + + public void finalize() throws Throwable + { + super.finalize(); + } +} \ No newline at end of file diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/finalization/Integer.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/finalization/Integer.java new file mode 100644 index 000000000000..ed910adda9ea --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/finalization/Integer.java @@ -0,0 +1,4 @@ +package com.siyeh.igtest.finalization; + +public class Integer{ +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/finalization/NoExplictCallToFinalizeInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/finalization/NoExplictCallToFinalizeInspection.java new file mode 100644 index 000000000000..34bd288f7204 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/finalization/NoExplictCallToFinalizeInspection.java @@ -0,0 +1,12 @@ +package com.siyeh.igtest.finalization; + +public class NoExplictCallToFinalizeInspection +{ + public NoExplictCallToFinalizeInspection() throws Throwable + { + finalize(); + this.finalize(); + new FinalizeNotProtectedInspection().finalize(); + } + +} \ No newline at end of file diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/imports/JavaLangImportInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/imports/JavaLangImportInspection.java new file mode 100644 index 000000000000..e1a4a3330ef9 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/imports/JavaLangImportInspection.java @@ -0,0 +1,14 @@ +package com.siyeh.igtest.imports; +import com.siyeh.igtest.finalization.*; + +import java.lang.Integer; +import java.lang.Byte; +import java.lang.*; + + +public class JavaLangImportInspection +{ + public Byte m_map; + public Integer foo; + public FinalizeNotProtectedInspection bar; +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/imports/OnDemandImportInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/imports/OnDemandImportInspection.java new file mode 100644 index 000000000000..2e3698982f70 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/imports/OnDemandImportInspection.java @@ -0,0 +1,7 @@ +package com.siyeh.igtest.imports; +import java.util.*; + +public class OnDemandImportInspection +{ + public HashMap m_map; +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/imports/SamePackageImportInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/imports/SamePackageImportInspection.java new file mode 100644 index 000000000000..1c9669802788 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/imports/SamePackageImportInspection.java @@ -0,0 +1,8 @@ +package com.siyeh.igtest.imports; +import com.siyeh.igtest.imports.*; +import com.siyeh.igtest.imports.OnDemandImportInspection; + +public class SamePackageImportInspection +{ + public OnDemandImportInspection m_map; +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/initialization/AbstractMethodCallInConstructorInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/initialization/AbstractMethodCallInConstructorInspection.java new file mode 100644 index 000000000000..5e1a964abf99 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/initialization/AbstractMethodCallInConstructorInspection.java @@ -0,0 +1,12 @@ +package com.siyeh.igtest.initialization; + +public abstract class AbstractMethodCallInConstructorInspection +{ + + protected AbstractMethodCallInConstructorInspection() + { + fooBar(); + } + + public abstract void fooBar(); +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/initialization/InstanceVaraibleUnitintializedUse.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/initialization/InstanceVaraibleUnitintializedUse.java new file mode 100644 index 000000000000..d9e57b3f68b9 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/initialization/InstanceVaraibleUnitintializedUse.java @@ -0,0 +1,17 @@ +package com.siyeh.igtest.initialization; + +public class InstanceVaraibleUnitintializedUse{ + private int foo; + + { + foo++; + } + + public InstanceVaraibleUnitintializedUse() + { + System.out.println(foo); + foo = 3; + System.out.println(foo); + } + +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/initialization/OverridableMethodCallInConstructorInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/initialization/OverridableMethodCallInConstructorInspection.java new file mode 100644 index 000000000000..07e1d694e16f --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/initialization/OverridableMethodCallInConstructorInspection.java @@ -0,0 +1,33 @@ +package com.siyeh.igtest.initialization; + +public class OverridableMethodCallInConstructorInspection +{ + + protected OverridableMethodCallInConstructorInspection() + { + fooFinal(); + fooStatic(); + fooPrivate(); + fooOverridable(); + } + + public final void fooFinal() + { + + } + + public static void fooStatic() + { + + } + + private void fooPrivate() + { + + } + + public void fooOverridable() + { + + } +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/initialization/StaticVariableInitializationInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/initialization/StaticVariableInitializationInspection.java new file mode 100644 index 000000000000..705b4678a69a --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/initialization/StaticVariableInitializationInspection.java @@ -0,0 +1,20 @@ +package com.siyeh.igtest.initialization; + +public class StaticVariableInitializationInspection +{ + public static int s_fooBar; // may not be initialized + public static int s_fooBaz = 1; + public static int s_fooBarangus; + public static int s_fooBazongas; + + static + { + s_fooBarangus = 2; + staticCall(); + } + + private static void staticCall() + { + s_fooBazongas = 3; + } +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/initialization/ThisEscapedInConstructorInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/initialization/ThisEscapedInConstructorInspection.java new file mode 100644 index 000000000000..4523dc11dc75 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/initialization/ThisEscapedInConstructorInspection.java @@ -0,0 +1,14 @@ +package com.siyeh.igtest.initialization; + +import java.util.ArrayList; +import java.util.List; + +public class ThisEscapedInConstructorInspection{ + private int foo = 3; + + public ThisEscapedInConstructorInspection(){ + super(); + final List list = new ArrayList(foo); + list.add(this); + } +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/internationalization/CharacterComparisonInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/internationalization/CharacterComparisonInspection.java new file mode 100644 index 000000000000..90d047e7d7ef --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/internationalization/CharacterComparisonInspection.java @@ -0,0 +1,32 @@ +package com.siyeh.igtest.internationalization; + +public class CharacterComparisonInspection +{ + public CharacterComparisonInspection() + { + } + + public void foo() + { + char c = 'c'; + char d = 'd'; + if(c < d) + { + return; + } + if(c > d) + { + return; + } + if(c >= d) + { + return; + } + if(c <= d) + { + return; + } + + } + +} \ No newline at end of file diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/internationalization/DateToStringInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/internationalization/DateToStringInspection.java new file mode 100644 index 000000000000..50b2e938cc6b --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/internationalization/DateToStringInspection.java @@ -0,0 +1,17 @@ +package com.siyeh.igtest.internationalization; + +import java.io.IOException; +import java.util.Date; + +public class DateToStringInspection +{ + public DateToStringInspection() + { + } + + public void foo() throws IOException + { + final Date date = new Date(); + date.toString(); + } +} \ No newline at end of file diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/internationalization/MagicCharacterInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/internationalization/MagicCharacterInspection.java new file mode 100644 index 000000000000..45167b2c02b9 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/internationalization/MagicCharacterInspection.java @@ -0,0 +1,23 @@ +package com.siyeh.igtest.internationalization; + +public class MagicCharacterInspection +{ + char m_c = 'c'; + char m_d = 'd'; + + static final char s_c = 'c'; + static final char s_d = 'd'; + + public MagicCharacterInspection() + { + } + + public void foo() + { + char c = 'c'; + char d = 'd'; + + + } + +} \ No newline at end of file diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/internationalization/NumericToStringInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/internationalization/NumericToStringInspection.java new file mode 100644 index 000000000000..9630f314ee55 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/internationalization/NumericToStringInspection.java @@ -0,0 +1,24 @@ +package com.siyeh.igtest.internationalization; + +public class NumericToStringInspection +{ + public NumericToStringInspection() + { + } + + public void foo() + { + final Integer j = new Integer(0); + j.toString(); + final Short k = new Short((short) 0); + k.toString(); + final Long m = new Long(0); + m.toString(); + final Double d = new Double(0); + d.toString(); + final Float f = new Float(0); + f.toString(); + final Object g = new Float(0); + g.toString(); + } +} \ No newline at end of file diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/internationalization/StringCompareToInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/internationalization/StringCompareToInspection.java new file mode 100644 index 000000000000..df6da4d5e838 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/internationalization/StringCompareToInspection.java @@ -0,0 +1,13 @@ +package com.siyeh.igtest.internationalization; + +public class StringCompareToInspection +{ + public StringCompareToInspection() + { + } + + public void foo() + { + "foo".compareTo("bar"); + } +} \ No newline at end of file diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/internationalization/StringConcatenationInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/internationalization/StringConcatenationInspection.java new file mode 100644 index 000000000000..6052a5a5ea0c --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/internationalization/StringConcatenationInspection.java @@ -0,0 +1,14 @@ +package com.siyeh.igtest.internationalization; + +public class StringConcatenationInspection +{ + public StringConcatenationInspection() + { + } + + public void foo() + { + final String concat = "foo" + "bar"; + System.out.println("concat = " + concat); + } +} \ No newline at end of file diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/internationalization/StringEqualsIgnoreCaseInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/internationalization/StringEqualsIgnoreCaseInspection.java new file mode 100644 index 000000000000..1fab129ff45f --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/internationalization/StringEqualsIgnoreCaseInspection.java @@ -0,0 +1,13 @@ +package com.siyeh.igtest.internationalization; + +public class StringEqualsIgnoreCaseInspection +{ + public StringEqualsIgnoreCaseInspection() + { + } + + public void foo() + { + "foo".equalsIgnoreCase("bar"); + } +} \ No newline at end of file diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/internationalization/StringEqualsInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/internationalization/StringEqualsInspection.java new file mode 100644 index 000000000000..aa1754bdc48a --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/internationalization/StringEqualsInspection.java @@ -0,0 +1,13 @@ +package com.siyeh.igtest.internationalization; + +public class StringEqualsInspection +{ + public StringEqualsInspection() + { + } + + public void foo() + { + "foo".equals("bar"); + } +} \ No newline at end of file diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/internationalization/StringLiteralInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/internationalization/StringLiteralInspection.java new file mode 100644 index 000000000000..5cc6f1023d71 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/internationalization/StringLiteralInspection.java @@ -0,0 +1,25 @@ +package com.siyeh.igtest.internationalization; + +public class StringLiteralInspection +{ + public StringLiteralInspection() + { + } + + public void foo() + { + final Exception string6 = new Exception("foo"); + final String string1 = "foo" + "bar"; + final String string2 = "foo"; + + final String string3 = bar("foo"); + assert false: "false"; + final String string4 = ""; + final String string5 = " "; + } + + private String bar(String s) + { + return s; + } +} \ No newline at end of file diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/internationalization/StringToUpperWithoutLocaleInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/internationalization/StringToUpperWithoutLocaleInspection.java new file mode 100644 index 000000000000..b671431f855f --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/internationalization/StringToUpperWithoutLocaleInspection.java @@ -0,0 +1,11 @@ +package com.siyeh.igtest.internationalization; + +import java.util.Locale; + +public class StringToUpperWithoutLocaleInspection { + public void foo() + { + final String foo = "foo".toUpperCase(); + final String bar = "bar".toUpperCase(Locale.US); + } +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/internationalization/StringTokenizerInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/internationalization/StringTokenizerInspection.java new file mode 100644 index 000000000000..025a41ecb74e --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/internationalization/StringTokenizerInspection.java @@ -0,0 +1,25 @@ +package com.siyeh.igtest.internationalization; + +import java.util.StringTokenizer; + +public class StringTokenizerInspection +{ + StringTokenizer m_c; + StringTokenizer n_d; + + static final StringTokenizer s_c = new StringTokenizer("c"); + static final StringTokenizer s_d = new StringTokenizer("d"); + + public StringTokenizerInspection() + { + } + + public void foo() + { + StringTokenizer c = new StringTokenizer("c") ; + StringTokenizer d = new StringTokenizer("d"); + c.toString(); + d.toString(); + } + +} \ No newline at end of file diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/internationalization/TimeToStringInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/internationalization/TimeToStringInspection.java new file mode 100644 index 000000000000..37f0f539cc0e --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/internationalization/TimeToStringInspection.java @@ -0,0 +1,17 @@ +package com.siyeh.igtest.internationalization; + +import java.io.IOException; +import java.sql.Time; + +public class TimeToStringInspection +{ + public TimeToStringInspection() + { + } + + public void foo() + { + final Time time = new Time(0L); + time.toString(); + } +} \ No newline at end of file diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/junit/AssertsWithoutMessagesInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/junit/AssertsWithoutMessagesInspection.java new file mode 100644 index 000000000000..7c0d54b4f71e --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/junit/AssertsWithoutMessagesInspection.java @@ -0,0 +1,20 @@ +package com.siyeh.igtest.junit; + +import junit.framework.TestCase; + +public class AssertsWithoutMessagesInspection extends TestCase +{ + public AssertsWithoutMessagesInspection() + { + } + + public void test() + { + assertTrue(true); + assertTrue("Barangus", true); + assertEquals(true, false); + assertEquals("Notorious JCKG", true, false); + assertEquals("foo", "bar"); + assertEquals("message", "foo", "bar"); + } +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/junit/MisspelledSetUpInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/junit/MisspelledSetUpInspection.java new file mode 100644 index 000000000000..17762b4b4be7 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/junit/MisspelledSetUpInspection.java @@ -0,0 +1,15 @@ +package com.siyeh.igtest.junit; + +import junit.framework.TestCase; + +public class MisspelledSetUpInspection extends TestCase +{ + public MisspelledSetUpInspection() + { + } + + public void setup() + { + + } +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/junit/MisspelledTearDownInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/junit/MisspelledTearDownInspection.java new file mode 100644 index 000000000000..0e885e1c2ae4 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/junit/MisspelledTearDownInspection.java @@ -0,0 +1,15 @@ +package com.siyeh.igtest.junit; + +import junit.framework.TestCase; + +public class MisspelledTearDownInspection extends TestCase +{ + public MisspelledTearDownInspection() + { + } + + public void teardown() + { + + } +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/junit/StaticSuiteInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/junit/StaticSuiteInspection.java new file mode 100644 index 000000000000..f56941246a6c --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/junit/StaticSuiteInspection.java @@ -0,0 +1,15 @@ +package com.siyeh.igtest.junit; + +import junit.framework.TestCase; + +public class StaticSuiteInspection extends TestCase +{ + public StaticSuiteInspection() + { + } + + public void suite() + { + + } +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/junit/TestCaseWithConstructorInspection1.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/junit/TestCaseWithConstructorInspection1.java new file mode 100644 index 000000000000..56f565d8fe2b --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/junit/TestCaseWithConstructorInspection1.java @@ -0,0 +1,12 @@ +package com.siyeh.igtest.junit; + +import junit.framework.TestCase; + +public class TestCaseWithConstructorInspection1 extends TestCase +{ + public TestCaseWithConstructorInspection1() + { + System.out.println(""); + } + +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/junit/TestCaseWithConstructorInspection2.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/junit/TestCaseWithConstructorInspection2.java new file mode 100644 index 000000000000..ba90cd452440 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/junit/TestCaseWithConstructorInspection2.java @@ -0,0 +1,12 @@ +package com.siyeh.igtest.junit; + +import junit.framework.TestCase; + +public class TestCaseWithConstructorInspection2 extends TestCase +{ + public TestCaseWithConstructorInspection2() + { + super(); + } + +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/junit/TestCaseWithConstructorInspection3.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/junit/TestCaseWithConstructorInspection3.java new file mode 100644 index 000000000000..c1954dc6914a --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/junit/TestCaseWithConstructorInspection3.java @@ -0,0 +1,13 @@ +package com.siyeh.igtest.junit; + +import junit.framework.TestCase; + +public class TestCaseWithConstructorInspection3 extends TestCase +{ + public TestCaseWithConstructorInspection3() + { + super(); + System.out.println("TestCaseWithConstructorInspection3.TestCaseWithConstructorInspection3"); + } + +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/junit/TestCaseWithNoTestMethodsInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/junit/TestCaseWithNoTestMethodsInspection.java new file mode 100644 index 000000000000..f2f0afea3a7c --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/junit/TestCaseWithNoTestMethodsInspection.java @@ -0,0 +1,15 @@ +package com.siyeh.igtest.junit; + +import junit.framework.TestCase; + +public class TestCaseWithNoTestMethodsInspection extends TestCase +{ + public TestCaseWithNoTestMethodsInspection() + { + } + + public void teardown() + { + + } +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/junit/TestMethodWithNoAssertionsInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/junit/TestMethodWithNoAssertionsInspection.java new file mode 100644 index 000000000000..97037895dfa3 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/junit/TestMethodWithNoAssertionsInspection.java @@ -0,0 +1,25 @@ +package com.siyeh.igtest.junit; + +import junit.framework.TestCase; + +public class TestMethodWithNoAssertionsInspection extends TestCase +{ + public TestMethodWithNoAssertionsInspection() + { + } + + public void test() + { + + } + + public void test2() + { + assertTrue(true); + } + + public void test3() + { + fail(); + } +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/logging/ClassWithMultipleLoggersInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/logging/ClassWithMultipleLoggersInspection.java new file mode 100644 index 000000000000..8dd6ec981e0e --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/logging/ClassWithMultipleLoggersInspection.java @@ -0,0 +1,14 @@ +package com.siyeh.igtest.logging; + +import java.util.logging.Logger; + +public class ClassWithMultipleLoggersInspection { + private Logger foo = Logger.getLogger("foo"); + private Logger bar = Logger.getLogger("bar"); + private ClassWithMultipleLoggersInspection() { + } + + public static void main(String[] args) { + + } +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/logging/ClassWithoutLoggerInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/logging/ClassWithoutLoggerInspection.java new file mode 100644 index 000000000000..b7e31ab46361 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/logging/ClassWithoutLoggerInspection.java @@ -0,0 +1,10 @@ +package com.siyeh.igtest.logging; + +public class ClassWithoutLoggerInspection { + private ClassWithoutLoggerInspection() { + } + + public static void main(String[] args) { + + } +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/logging/NonStaticFinalLoggerInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/logging/NonStaticFinalLoggerInspection.java new file mode 100644 index 000000000000..408a2a5e46a0 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/logging/NonStaticFinalLoggerInspection.java @@ -0,0 +1,13 @@ +package com.siyeh.igtest.logging; + +import java.util.logging.Logger; + +public class NonStaticFinalLoggerInspection { + private Logger foo = Logger.getLogger("foo"); + private NonStaticFinalLoggerInspection() { + } + + public static void main(String[] args) { + + } +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/maturity/ObsoleteCollectionsInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/maturity/ObsoleteCollectionsInspection.java new file mode 100644 index 000000000000..5d6537754199 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/maturity/ObsoleteCollectionsInspection.java @@ -0,0 +1,21 @@ +package com.siyeh.igtest.maturity; + +import java.io.IOException; +import java.io.PrintStream; +import java.util.*; + +public class ObsoleteCollectionsInspection +{ + private Vector m_foo; + private Hashtable m_bar; + public ObsoleteCollectionsInspection() + { + } + + public void foo() throws IOException + { + List foo = new Vector(3); + Map bar = new Hashtable(3); + + } +} \ No newline at end of file diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/maturity/SystemOutErrInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/maturity/SystemOutErrInspection.java new file mode 100644 index 000000000000..67a0670fc78d --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/maturity/SystemOutErrInspection.java @@ -0,0 +1,20 @@ +package com.siyeh.igtest.maturity; + +import java.io.IOException; +import java.io.PrintStream; + +public class SystemOutErrInspection +{ + public SystemOutErrInspection() + { + } + + public void foo() throws IOException + { + System.out.println(0); + System.err.println(0); + final PrintStream out = System.out; + final PrintStream err = System.err; + + } +} \ No newline at end of file diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/maturity/ThreadDumpStackInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/maturity/ThreadDumpStackInspection.java new file mode 100644 index 000000000000..d75e57d67d89 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/maturity/ThreadDumpStackInspection.java @@ -0,0 +1,16 @@ +package com.siyeh.igtest.maturity; + +import java.io.IOException; +import java.io.PrintStream; + +public class ThreadDumpStackInspection +{ + public ThreadDumpStackInspection() + { + } + + public void foo() + { + Thread.dumpStack(); + } +} \ No newline at end of file diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/maturity/ThrowablePrintStackTraceInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/maturity/ThrowablePrintStackTraceInspection.java new file mode 100644 index 000000000000..fb06eb5c9ba8 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/maturity/ThrowablePrintStackTraceInspection.java @@ -0,0 +1,16 @@ +package com.siyeh.igtest.maturity; + +import java.io.IOException; +import java.io.PrintStream; + +public class ThrowablePrintStackTraceInspection +{ + public ThrowablePrintStackTraceInspection() + { + } + + public void foo() + { + new Throwable().printStackTrace(); + } +} \ No newline at end of file diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/metrics/CyclomaticComplexityInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/metrics/CyclomaticComplexityInspection.java new file mode 100644 index 000000000000..bff9076706de --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/metrics/CyclomaticComplexityInspection.java @@ -0,0 +1,59 @@ +package com.siyeh.igtest.metrics; + +public class CyclomaticComplexityInspection +{ + public void fooBar() + { + int i = 0; + if(bar()) + { + i++; + } + if(bar()) + { + i++; + } + if(bar()) + { + i++; + } + if(bar()) + { + i++; + } + if(bar()) + { + i++; + } + if(bar()) + { + i++; + } + if(bar()) + { + i++; + } + if(bar()) + { + i++; + } + if(bar()) + { + i++; + } + if(bar()) + { + i++; + } + if(bar()) + { + i++; + } + System.out.println("i = " + i); + } + + private boolean bar() + { + return true; + } +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/metrics/FiveParametersPerMethodInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/metrics/FiveParametersPerMethodInspection.java new file mode 100644 index 000000000000..a1a22494c404 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/metrics/FiveParametersPerMethodInspection.java @@ -0,0 +1,14 @@ +package com.siyeh.igtest.metrics; + +public class FiveParametersPerMethodInspection +{ + public void foobar(int i1, int i2, int j, int k, int l) + { + + } + + public void barangus(int i1, int i2, int j, int k, int l, int m) + { + + } +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/metrics/MultipleReturnPointsInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/metrics/MultipleReturnPointsInspection.java new file mode 100644 index 000000000000..fc1d798f6b3f --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/metrics/MultipleReturnPointsInspection.java @@ -0,0 +1,21 @@ +package com.siyeh.igtest.metrics; + +public class MultipleReturnPointsInspection +{ + public void fooBar() + { + if(barangus()) + { + return; + } + } + + private boolean barangus() + { + if(true) + { + return true; + } + return false; + } +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/metrics/NestingDepthInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/metrics/NestingDepthInspection.java new file mode 100644 index 000000000000..c8c60a0fa23d --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/metrics/NestingDepthInspection.java @@ -0,0 +1,33 @@ +package com.siyeh.igtest.metrics; + +public class NestingDepthInspection +{ + public void fooBar() + { + if(bar()) + { + if(bar()) + { + if(bar()) + { + if(bar()) + { + if(bar()) + { + if(bar()) + { + + } + } + } + } + } + } + } + + private boolean bar() + { + return true; + } + +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/metrics/NonCommentSourceStatementsInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/metrics/NonCommentSourceStatementsInspection.java new file mode 100644 index 000000000000..fb8d021a3c74 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/metrics/NonCommentSourceStatementsInspection.java @@ -0,0 +1,40 @@ +package com.siyeh.igtest.metrics; + +public class NonCommentSourceStatementsInspection +{ + public void fooBar() + { + System.out.println("1"); + System.out.println("2"); + System.out.println("3"); + System.out.println("4"); + System.out.println("5"); + System.out.println("6"); + System.out.println("7"); + System.out.println("8"); + System.out.println("9"); + System.out.println("10"); + System.out.println("1"); + System.out.println("2"); + System.out.println("3"); + System.out.println("4"); + System.out.println("5"); + System.out.println("6"); + System.out.println("7"); + System.out.println("8"); + System.out.println("9"); + System.out.println("10"); + System.out.println("1"); + System.out.println("2"); + System.out.println("3"); + System.out.println("4"); + System.out.println("5"); + System.out.println("6"); + System.out.println("7"); + System.out.println("8"); + System.out.println("9"); + System.out.println("10"); + System.out.println("31"); + } + +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/metrics/ThreeNegationsPerMethodInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/metrics/ThreeNegationsPerMethodInspection.java new file mode 100644 index 000000000000..cf856331d342 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/metrics/ThreeNegationsPerMethodInspection.java @@ -0,0 +1,28 @@ +package com.siyeh.igtest.metrics; + +public class ThreeNegationsPerMethodInspection +{ + public void okayMethod() + { + if(!!!true) + { + return; + } + } + + public void badMethod() + { + if(!!!!true) + { + return; + } + } + + public void badMethod2() + { + if(!!!true && 3 !=4) + { + return; + } + } +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/naming/ClassNameConvention2.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/naming/ClassNameConvention2.java new file mode 100644 index 000000000000..9a88be4e06c7 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/naming/ClassNameConvention2.java @@ -0,0 +1,8 @@ +package com.siyeh.igtest.naming; + +public class ClassNameConvention2 +{ + public ClassNameConvention2() + { + } +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/naming/ConfusingMainMethodInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/naming/ConfusingMainMethodInspection.java new file mode 100644 index 000000000000..b38e91420960 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/naming/ConfusingMainMethodInspection.java @@ -0,0 +1,19 @@ +package com.siyeh.igtest.naming; + +public class ConfusingMainMethodInspection +{ + public static void main() + { + + } + + public void main(String[] args) + { + + } + + void main(String[][] args) + { + + } +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/naming/ConstantNamingConvention.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/naming/ConstantNamingConvention.java new file mode 100644 index 000000000000..17027d8d6c33 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/naming/ConstantNamingConvention.java @@ -0,0 +1,7 @@ +package com.siyeh.igtest.naming; + +public class ConstantNamingConvention +{ + public static final int lowercaseConstant = 2; + private static final int PRIVATE_CONSTANT2 = 2; +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/naming/DollarSignInIdentifierInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/naming/DollarSignInIdentifierInspection.java new file mode 100644 index 000000000000..b337eb03c56f --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/naming/DollarSignInIdentifierInspection.java @@ -0,0 +1,13 @@ +package com.siyeh.igtest.naming; + +public class DollarSignInIdentifierInspection { + private int foo$; + + public int getFoo$() { + return foo$; + } + + public void setFoo$(int foo$) { + this.foo$ = foo$; + } +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/naming/ExceptionWithBadName.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/naming/ExceptionWithBadName.java new file mode 100644 index 000000000000..f80121610bc3 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/naming/ExceptionWithBadName.java @@ -0,0 +1,23 @@ +package com.siyeh.igtest.naming; + +public class ExceptionWithBadName extends Exception +{ + public ExceptionWithBadName() + { + } + + public ExceptionWithBadName(String message) + { + super(message); + } + + public ExceptionWithBadName(String message, Throwable cause) + { + super(message, cause); + } + + public ExceptionWithBadName(Throwable cause) + { + super(cause); + } +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/naming/InstanceMethodNamingConvention.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/naming/InstanceMethodNamingConvention.java new file mode 100644 index 000000000000..a09b69122af4 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/naming/InstanceMethodNamingConvention.java @@ -0,0 +1,27 @@ +package com.siyeh.igtest.naming; + +public class InstanceMethodNamingConvention implements Runnable +{ + public void UpperaseMethod() + { + + } + + public void methodNameEndingIn2() + { + + } + + public void foo() + { + + } + + public void methodNameTooLoooooooooooooooooooooooooooooooooooooooooooooong() + { + + } + + public void run(){ + } +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/naming/InstanceVariableNamingConvention.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/naming/InstanceVariableNamingConvention.java new file mode 100644 index 000000000000..b5c1e93ea7d1 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/naming/InstanceVariableNamingConvention.java @@ -0,0 +1,15 @@ +package com.siyeh.igtest.naming; + +public class InstanceVariableNamingConvention +{ + public final int lowercaseConstant = 2; + private final int s_lowercaseConstant = 2; + private int m_lowercaseConstant = 2; + + public void fooBar() + { + System.out.println("lowercaseConstant = " + lowercaseConstant); + System.out.println("m_lowercaseConstant = " + m_lowercaseConstant); + System.out.println("s_lowercaseConstant = " + s_lowercaseConstant); + } +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/naming/List.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/naming/List.java new file mode 100644 index 000000000000..f7745cfbc6ba --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/naming/List.java @@ -0,0 +1,6 @@ +package com.siyeh.igtest.naming; + +import java.util.ArrayList; + +public class List extends ArrayList{ +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/naming/LocalVarNameConvention.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/naming/LocalVarNameConvention.java new file mode 100644 index 000000000000..c73496a9c6d4 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/naming/LocalVarNameConvention.java @@ -0,0 +1,15 @@ +package com.siyeh.igtest.naming; + +public class LocalVarNameConvention +{ + public LocalVarNameConvention() + { + } + + public int foobar() + { + final int x32 = 0; + final int loooooooooooooooooooooooooooooooooooooooooooooooongvarName = x32; + return loooooooooooooooooooooooooooooooooooooooooooooooongvarName; + } +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/naming/MethodNameSameAsClassNameConvention.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/naming/MethodNameSameAsClassNameConvention.java new file mode 100644 index 000000000000..8031730af113 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/naming/MethodNameSameAsClassNameConvention.java @@ -0,0 +1,13 @@ +package com.siyeh.igtest.naming; + +public class MethodNameSameAsClassNameConvention +{ + public MethodNameSameAsClassNameConvention() + { + } + + public int MethodNameSameAsClassNameConvention(int x) + { + return 0; + } +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/naming/MethodNameSameAsParemtNameConvention.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/naming/MethodNameSameAsParemtNameConvention.java new file mode 100644 index 000000000000..f53e1973c63a --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/naming/MethodNameSameAsParemtNameConvention.java @@ -0,0 +1,13 @@ +package com.siyeh.igtest.naming; + +public class MethodNameSameAsParemtNameConvention extends MethodNameSameAsClassNameConvention +{ + public MethodNameSameAsParemtNameConvention() + { + } + + public int MethodNameSameAsClassNameConvention(int x) + { + return 0; + } +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/naming/MyInterface2.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/naming/MyInterface2.java new file mode 100644 index 000000000000..09fd173fc5bf --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/naming/MyInterface2.java @@ -0,0 +1,5 @@ +package com.siyeh.igtest.naming; + +public interface MyInterface2 +{ +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/naming/NamingTest2.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/naming/NamingTest2.java new file mode 100644 index 000000000000..b5c26edfb181 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/naming/NamingTest2.java @@ -0,0 +1,8 @@ +package com.siyeh.igtest.naming; + +public class NamingTest2 +{ + public NamingTest2() + { + } +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/naming/NamingTestBeginsWithPackageName.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/naming/NamingTestBeginsWithPackageName.java new file mode 100644 index 000000000000..458011be8a44 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/naming/NamingTestBeginsWithPackageName.java @@ -0,0 +1,8 @@ +package com.siyeh.igtest.naming; + +public class NamingTestBeginsWithPackageName +{ + public NamingTestBeginsWithPackageName() + { + } +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/naming/NotAnException.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/naming/NotAnException.java new file mode 100644 index 000000000000..999d268ce493 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/naming/NotAnException.java @@ -0,0 +1,9 @@ +package com.siyeh.igtest.naming; + +public class NotAnException +{ + public NotAnException() + { + } + +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/naming/ParameterNameConvention.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/naming/ParameterNameConvention.java new file mode 100644 index 000000000000..456d0f505dd3 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/naming/ParameterNameConvention.java @@ -0,0 +1,13 @@ +package com.siyeh.igtest.naming; + +public class ParameterNameConvention +{ + public ParameterNameConvention() + { + } + + public int foobar(int Z, int x3, int loooooooooooooooooooooooooooooooooooooooooooooooongvarName) + { + return 0; + } +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/naming/Runnable.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/naming/Runnable.java new file mode 100644 index 000000000000..9cd8f6137f09 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/naming/Runnable.java @@ -0,0 +1,6 @@ +package com.siyeh.igtest.naming; + +public class Runnable implements java.lang.Runnable{ + public void run() { + } +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/naming/StandardNamesInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/naming/StandardNamesInspection.java new file mode 100644 index 000000000000..67ae312b7b5f --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/naming/StandardNamesInspection.java @@ -0,0 +1,32 @@ +package com.siyeh.igtest.naming; + +public class StandardNamesInspection +{ + public void foo() + { + final short i = 0; + System.out.println(i); + final short j = 0; + System.out.println(j); + final short k = 0; + System.out.println(k); + final short m = 0; + System.out.println(m); + final short n = 0; + System.out.println(n); + final int s = 0; + System.out.println(s); + final int str = 0; + System.out.println(str); + final int d= 0; + System.out.println(d); + final int l = 0; + System.out.println(l); + final int b = 0; + System.out.println(b); + final int c = 0; + System.out.println(c); + final int ch = 0; + System.out.println(ch); + } +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/naming/StaticMethodNamingConvention.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/naming/StaticMethodNamingConvention.java new file mode 100644 index 000000000000..48bdff52ce64 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/naming/StaticMethodNamingConvention.java @@ -0,0 +1,24 @@ +package com.siyeh.igtest.naming; + +public class StaticMethodNamingConvention +{ + public static void UpperaseMethod() + { + + } + + public static void methodNameEndingIn2() + { + + } + + public static void foo() + { + + } + + public static void methodNameTooLoooooooooooooooooooooooooooooooooooooooooooooong() + { + + } +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/naming/StaticVariableNamingConvention.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/naming/StaticVariableNamingConvention.java new file mode 100644 index 000000000000..7e38839db55c --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/naming/StaticVariableNamingConvention.java @@ -0,0 +1,15 @@ +package com.siyeh.igtest.naming; + +public class StaticVariableNamingConvention +{ + public static int lowercaseConstant = 2; + private static int s_lowercaseConstant = 2; + private static int m_lowercaseConstant = 2; + + public static void fooBar() + { + System.out.println("lowercaseConstant = " + lowercaseConstant); + System.out.println("m_lowercaseConstant = " + m_lowercaseConstant); + System.out.println("s_lowercaseConstant = " + s_lowercaseConstant); + } +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/naming/UpperCaseFieldNameNotConstantInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/naming/UpperCaseFieldNameNotConstantInspection.java new file mode 100644 index 000000000000..1f47a0eb0f16 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/naming/UpperCaseFieldNameNotConstantInspection.java @@ -0,0 +1,8 @@ +package com.siyeh.igtest.naming; + +public class UpperCaseFieldNameNotConstantInspection { + public int FOO = 3; + public static int FOO2 = 3; + public final int FOO3 = 3; + public static final int FOO4 = 3; +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/performance/BooleanConstructorInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/performance/BooleanConstructorInspection.java new file mode 100644 index 000000000000..691685ee3196 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/performance/BooleanConstructorInspection.java @@ -0,0 +1,18 @@ +package com.siyeh.igtest.performance; + +import java.io.IOException; + +public class BooleanConstructorInspection +{ + public BooleanConstructorInspection() + { + } + + public void foo() throws IOException + { + final Boolean b1 = new Boolean(true); + final Boolean b2 = new Boolean(false); + final Boolean b3 = new Boolean("true"); + final Boolean b4 = new Boolean("false"); + } +} \ No newline at end of file diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/performance/CollectionsMustHaveInitialCapacityInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/performance/CollectionsMustHaveInitialCapacityInspection.java new file mode 100644 index 000000000000..56e19ae5e399 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/performance/CollectionsMustHaveInitialCapacityInspection.java @@ -0,0 +1,40 @@ +package com.siyeh.igtest.performance; + +import java.io.IOException; +import java.util.*; + +public class CollectionsMustHaveInitialCapacityInspection +{ + public CollectionsMustHaveInitialCapacityInspection() + { + } + + public void foo() throws IOException + { + // new HashMap(); + // new HashMap(3); + + new HashMap(); + new HashMap(3); + + new WeakHashMap(); + new WeakHashMap(3); + + new HashSet(); + new HashSet(3); + + new Hashtable(); + new Hashtable(3); + + new BitSet(); + new BitSet(3); + + new Vector(); + new Vector(3); + + new ArrayList(); + new ArrayList(3); + + + } +} \ No newline at end of file diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/performance/FieldMayBeStaticInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/performance/FieldMayBeStaticInspection.java new file mode 100644 index 000000000000..e2048943b578 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/performance/FieldMayBeStaticInspection.java @@ -0,0 +1,11 @@ +package com.siyeh.igtest.performance; + +public class FieldMayBeStaticInspection +{ + private final int m_fooBar = 3; + private final int m_fooBaz = m_fooBar; + + { + System.out.println("m_fooBaz = " + m_fooBaz); + } +} \ No newline at end of file diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/performance/InstanceVariableRepeatedlyAccessedInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/performance/InstanceVariableRepeatedlyAccessedInspection.java new file mode 100644 index 000000000000..6ff01e521846 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/performance/InstanceVariableRepeatedlyAccessedInspection.java @@ -0,0 +1,26 @@ +package com.siyeh.igtest.performance; + +public class InstanceVariableRepeatedlyAccessedInspection +{ + private String m_value; + + public void fooBar() + { + m_value = "0"; + m_value = "0"; + m_value = "0"; + } + public void fooBarangus() + { + m_value.toLowerCase(); + m_value.toLowerCase(); + m_value.toLowerCase(); + } + + public void fooBaz() + { + System.out.println(m_value); + System.out.println(m_value); + System.out.println(m_value); + } +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/performance/JavaLangReflectInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/performance/JavaLangReflectInspection.java new file mode 100644 index 000000000000..e8d473205df2 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/performance/JavaLangReflectInspection.java @@ -0,0 +1,24 @@ +package com.siyeh.igtest.performance; + +import java.io.IOException; +import java.lang.reflect.Field; +import java.lang.reflect.Constructor; + +public class JavaLangReflectInspection +{ + public JavaLangReflectInspection() + { + } + + public void fooBar() throws IOException + { + final Class thisClass = getClass(); + final Field[] fields = thisClass.getFields(); + for(int i = 0; i < fields.length; i++) + { + final Field field = fields[i]; + System.out.println("field = " + field); + } + final Constructor[] constructors = thisClass.getConstructors(); + } +} \ No newline at end of file diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/performance/LengthOneStringInConcatenationInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/performance/LengthOneStringInConcatenationInspection.java new file mode 100644 index 000000000000..67e4e005703d --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/performance/LengthOneStringInConcatenationInspection.java @@ -0,0 +1,23 @@ + +package com.siyeh.igtest.performance; + +import java.io.IOException; + +public class LengthOneStringInConcatenationInspection +{ + public LengthOneStringInConcatenationInspection() + { + } + + public void foo() throws IOException + { + final String s = "foo" + "i" + "bar" + " " + "baz" + "\t"; + System.out.println(s); + final StringBuffer buffer = new StringBuffer(); + buffer.append("foo"); + buffer.append("f"); + final StringBuilder buffer2 = new StringBuilder(); + buffer2.append("foo"); + buffer2.append("f"); + } +} \ No newline at end of file diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/performance/ManualArrayCopyInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/performance/ManualArrayCopyInspection.java new file mode 100644 index 000000000000..4615c4ac6cbc --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/performance/ManualArrayCopyInspection.java @@ -0,0 +1,23 @@ +package com.siyeh.igtest.performance; + +public class ManualArrayCopyInspection +{ + + public void fooBar() + { + final int[] q = new int[3]; + final int[] a = new int[3]; + for(int i = 0; i < a.length; i++) + q[i] = a[i]; + for(int i = 0; i < a.length; i++) + q[i+3] = a[i+4]; + for(int i = 0; i < a.length; i++) + { + q[i] = a[i]; + } + for(int i = 0; i < a.length; i++) + { + q[i+3] = a[i]; + } + } +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/performance/MultiplyOrDivideByPowerOfTwoInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/performance/MultiplyOrDivideByPowerOfTwoInspection.java new file mode 100644 index 000000000000..8f9465c47f2d --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/performance/MultiplyOrDivideByPowerOfTwoInspection.java @@ -0,0 +1,23 @@ +package com.siyeh.igtest.performance; + +import java.io.IOException; +import java.util.*; + +public class MultiplyOrDivideByPowerOfTwoInspection +{ + public MultiplyOrDivideByPowerOfTwoInspection() + { + } + + public void foo() throws IOException + { + final int i = 3 * 8; + final int j = i / 8; + final int k = j / 7; + final int m = j * 7; + System.out.println("i = " + i); + System.out.println("j = " + j); + System.out.println("k = " + k); + System.out.println("m = " + m); + } +} \ No newline at end of file diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/performance/SingleCharacterStartsWithInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/performance/SingleCharacterStartsWithInspection.java new file mode 100644 index 000000000000..76571b9392f6 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/performance/SingleCharacterStartsWithInspection.java @@ -0,0 +1,18 @@ +package com.siyeh.igtest.performance; + +import java.io.IOException; + +public class SingleCharacterStartsWithInspection +{ + public SingleCharacterStartsWithInspection() + { + } + + public void foo() throws IOException + { + "foo".startsWith("f"); + "foo".startsWith("f", 0); + + "foo".endsWith("f"); + } +} \ No newline at end of file diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/performance/StaticCollectionInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/performance/StaticCollectionInspection.java new file mode 100644 index 000000000000..939a27711ceb --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/performance/StaticCollectionInspection.java @@ -0,0 +1,17 @@ +package com.siyeh.igtest.performance; + +import java.util.HashMap; +import java.util.Map; +import java.util.ArrayList; +import java.util.List; + +public class StaticCollectionInspection +{ + private static final Map s_map1 = new HashMap(10); + private static final List s_map2 = new ArrayList(10); + + private StaticCollectionInspection() + { + } + +} \ No newline at end of file diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/performance/StringBufferMustHaveInitialCapacityInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/performance/StringBufferMustHaveInitialCapacityInspection.java new file mode 100644 index 000000000000..7fe4ae3ae367 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/performance/StringBufferMustHaveInitialCapacityInspection.java @@ -0,0 +1,21 @@ +package com.siyeh.igtest.performance; + +import java.io.IOException; + +public class StringBufferMustHaveInitialCapacityInspection +{ + public StringBufferMustHaveInitialCapacityInspection() + { + } + + public void foo() throws IOException + { + new StringBuffer(); + new StringBuffer(3); + new StringBuffer("foo"); + new StringBuilder(); + new StringBuilder(3); + new StringBuilder("foo"); + + } +} \ No newline at end of file diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/performance/StringBufferReplaceableByStringBuilderInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/performance/StringBufferReplaceableByStringBuilderInspection.java new file mode 100644 index 000000000000..77d63cee9c19 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/performance/StringBufferReplaceableByStringBuilderInspection.java @@ -0,0 +1,20 @@ +package com.siyeh.igtest.performance; + +public class StringBufferReplaceableByStringBuilderInspection { + public void foo() + { + final StringBuffer buffer = new StringBuffer(); + buffer.append("bar"); + buffer.append("bar"); + System.out.println(buffer.toString()); + } + + public StringBuffer foo2() + { + final StringBuffer buffer = new StringBuffer(); + buffer.append("bar"); + buffer.append("bar"); + System.out.println(buffer.toString()); + return buffer; + } +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/performance/StringBufferReplaceableByStringInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/performance/StringBufferReplaceableByStringInspection.java new file mode 100644 index 000000000000..085519f5c4ab --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/performance/StringBufferReplaceableByStringInspection.java @@ -0,0 +1,15 @@ +package com.siyeh.igtest.performance; + +public class StringBufferReplaceableByStringInspection { + public void foo() + { + final StringBuffer buffer = new StringBuffer(); + System.out.println(buffer.toString()); + } + + public void foo2() + { + final StringBuffer buffer = new StringBuffer("foo").append("bar"); + System.out.println(buffer.toString()); + } +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/performance/StringBufferToStringInConcatenatinInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/performance/StringBufferToStringInConcatenatinInspection.java new file mode 100644 index 000000000000..9b2c051bac12 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/performance/StringBufferToStringInConcatenatinInspection.java @@ -0,0 +1,20 @@ +package com.siyeh.igtest.performance; + +import java.io.IOException; +import java.util.*; + +public class StringBufferToStringInConcatenatinInspection +{ + public StringBufferToStringInConcatenatinInspection() + { + } + + public void foo() throws IOException + { + final StringBuffer buffer = new StringBuffer(3); + String out = "foo" + buffer.toString(); + System.out.println("out = " + out); + Object i = null; + i.toString(); + } +} \ No newline at end of file diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/performance/StringConcatenationInLoopInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/performance/StringConcatenationInLoopInspection.java new file mode 100644 index 000000000000..0b172da9bcab --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/performance/StringConcatenationInLoopInspection.java @@ -0,0 +1,40 @@ +package com.siyeh.igtest.performance; + +public class + StringConcatenationInLoopInspection +{ + public StringConcatenationInLoopInspection() + { + } + + public String foo() + { + String foo = ""; + for(int i = 0; i < 5; i++) + { + foo = foo + " " + i; + foo += foo + " " + i; + baz( foo + " " + i); + if(bar()) + { + return baz("foo" + "bar"); + } + if(bar()) + { + throw new OutOfMemoryError("foo" + i); + } + } + System.out.println(foo); + return foo; + } + + private boolean bar() + { + return true; + } + + private String baz(String s) + { + return s; + } +} \ No newline at end of file diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/performance/StringConstructorInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/performance/StringConstructorInspection.java new file mode 100644 index 000000000000..ba6c3c9881c1 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/performance/StringConstructorInspection.java @@ -0,0 +1,15 @@ +package com.siyeh.igtest.performance; + +import java.io.IOException; + +public class StringConstructorInspection +{ + public StringConstructorInspection() + { + } + + public void foo() throws IOException + { + new String("true"); + } +} \ No newline at end of file diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/performance/StringEqualsEmptyStringInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/performance/StringEqualsEmptyStringInspection.java new file mode 100644 index 000000000000..561006ebfdaf --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/performance/StringEqualsEmptyStringInspection.java @@ -0,0 +1,16 @@ +package com.siyeh.igtest.performance; + +import java.io.IOException; + +public class StringEqualsEmptyStringInspection { + public StringEqualsEmptyStringInspection() { + } + + public void foo() throws IOException { + "foo".equals("f"); + "foo".equals(""); + if ("foo".equals("")) { + System.out.println(""); + } + } +} \ No newline at end of file diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/performance/StringReplaceableByStringBufferInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/performance/StringReplaceableByStringBufferInspection.java new file mode 100644 index 000000000000..6a2e7fab5f5b --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/performance/StringReplaceableByStringBufferInspection.java @@ -0,0 +1,23 @@ +package com.siyeh.igtest.performance; + +public class StringReplaceableByStringBufferInspection { + public void foo() + { + String buffer = "bar"; + buffer += "foo"; + System.out.println(buffer); + } + + public void foobar() + { + String buffer = "bar"; + buffer = buffer + "foo"; + System.out.println(buffer); + } + + public void foobaz() + { + final String buffer = "bar"; + System.out.println(buffer); + } +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/performance/StringToStringInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/performance/StringToStringInspection.java new file mode 100644 index 000000000000..c758d663d18b --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/performance/StringToStringInspection.java @@ -0,0 +1,15 @@ +package com.siyeh.igtest.performance; + +import java.io.IOException; + +public class StringToStringInspection +{ + public StringToStringInspection() + { + } + + public void foo() throws IOException + { + "true".toString(); + } +} \ No newline at end of file diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/performance/SystemGCInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/performance/SystemGCInspection.java new file mode 100644 index 000000000000..3e8bd07c5d47 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/performance/SystemGCInspection.java @@ -0,0 +1,14 @@ +package com.siyeh.igtest.performance; + +public class SystemGCInspection +{ + public SystemGCInspection() + { + } + + public void foo() + { + System.gc(); + Runtime.getRuntime().gc(); + } +} \ No newline at end of file diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/performance/TailRecursionInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/performance/TailRecursionInspection.java new file mode 100644 index 000000000000..63667e450b49 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/performance/TailRecursionInspection.java @@ -0,0 +1,32 @@ +package com.siyeh.igtest.performance; + +import java.io.IOException; + +public class TailRecursionInspection +{ + public TailRecursionInspection() + { + } + + public int foo() throws IOException + { + return foo(); + } + + public int factorial(int val) + { + return factorial(val, 1); + } + + public int factorial(int val, int runningVal) + { + if(val == 1) + { + return runningVal; + } + else + { + return factorial(val-1, runningVal * val); + } + } +} \ No newline at end of file diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/performance/UnnecessaryTemporaryObjectInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/performance/UnnecessaryTemporaryObjectInspection.java new file mode 100644 index 000000000000..ee169bcb97a6 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/performance/UnnecessaryTemporaryObjectInspection.java @@ -0,0 +1,27 @@ +package com.siyeh.igtest.performance; + +import java.io.IOException; + +public class UnnecessaryTemporaryObjectInspection +{ + public UnnecessaryTemporaryObjectInspection() + { + } + + public void foo() throws IOException + { + final String s = new Integer(3).toString(); + final String s2 = new Double(3).toString(); + final String s3 = new Short((short) 3).toString(); + final String s4 = new Long(3).toString(); + final String s5 = new Float(3).toString(); + final String s6 = new Boolean(true).toString(); + + final int i = new Integer("3").intValue(); + final double d = new Double("3").doubleValue(); + final short sh = new Short("3").shortValue(); + final long lo = new Long("3").longValue(); + final float f = new Float("3").floatValue(); + final boolean b = new Boolean("3").booleanValue(); + } +} \ No newline at end of file diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/performance/ZeroLengthArrayInitializationInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/performance/ZeroLengthArrayInitializationInspection.java new file mode 100644 index 000000000000..57b3114c667f --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/performance/ZeroLengthArrayInitializationInspection.java @@ -0,0 +1,11 @@ +package com.siyeh.igtest.performance; + +public class ZeroLengthArrayInitializationInspection +{ + public static final int[] EMPTY_INT_ARRAY = new int[0]; + + public void getTabName() + { + final int[] ints = new int[0]; + } +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/portability/Annotation.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/portability/Annotation.java new file mode 100644 index 000000000000..ee750baf967f --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/portability/Annotation.java @@ -0,0 +1,12 @@ +package com.siyeh.igtest.portability; + +public @AnnotationClass class Annotation { + private Annotation() { + super(); + } + + public static void main(String[] args) { + + + } +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/portability/AnnotationClass.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/portability/AnnotationClass.java new file mode 100644 index 000000000000..8c7a9e1605ef --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/portability/AnnotationClass.java @@ -0,0 +1,5 @@ +package com.siyeh.igtest.portability; + +public @interface AnnotationClass { + +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/portability/AssertAsNameInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/portability/AssertAsNameInspection.java new file mode 100644 index 000000000000..30dbff074007 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/portability/AssertAsNameInspection.java @@ -0,0 +1,16 @@ +package com.siyeh.igtest.portability; + +public class AssertAsNameInspection +{ + private int assert = 3; + + public void assert() + { + + } + + private interface assert + { + + } +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/portability/AssertStatementInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/portability/AssertStatementInspection.java new file mode 100644 index 000000000000..af5cd9d4dfbe --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/portability/AssertStatementInspection.java @@ -0,0 +1,11 @@ +package com.siyeh.igtest.portability; + +public class AssertStatementInspection +{ + + public void foo() + { + assert(true); + } + +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/portability/DollarSignInNameInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/portability/DollarSignInNameInspection.java new file mode 100644 index 000000000000..28847b9e476b --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/portability/DollarSignInNameInspection.java @@ -0,0 +1,16 @@ +package com.siyeh.igtest.portability; + +public class DollarSignInNameInspection +{ + private int ass$ert = 3; + + public void ass$ert() + { + + } + + private interface as$sert + { + + } +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/portability/EnumClass.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/portability/EnumClass.java new file mode 100644 index 000000000000..16f94ae043bd --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/portability/EnumClass.java @@ -0,0 +1,5 @@ +package com.siyeh.igtest.portability; + +public enum EnumClass { + foo, bar, baz; +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/portability/ForeachStatement.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/portability/ForeachStatement.java new file mode 100644 index 000000000000..f632f0d95841 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/portability/ForeachStatement.java @@ -0,0 +1,17 @@ +package com.siyeh.igtest.portability; + +public class ForeachStatement { + + public static void main(String[] args) { + + } + + public int sum(int... var) { + int total = 0; + for (int i:var) { + total += var[i]; + } + return total; + } + +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/portability/HardcodedFileSeparatorsInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/portability/HardcodedFileSeparatorsInspection.java new file mode 100644 index 000000000000..0f9bf3e47187 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/portability/HardcodedFileSeparatorsInspection.java @@ -0,0 +1,18 @@ +package com.siyeh.igtest.portability; + +public class HardcodedFileSeparatorsInspection +{ + public HardcodedFileSeparatorsInspection() + { + } + + public static void foo() + { + final String backSlash = "\\"; + final String slash = "/"; + final String date = "dd/MM/yy"; + final String date2 = "sdd/MM/yy"; + final String tag1 = ""; + final String tag2 = ""; + } +} \ No newline at end of file diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/portability/HardcodedLineSeparatorsInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/portability/HardcodedLineSeparatorsInspection.java new file mode 100644 index 000000000000..227d0b848dda --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/portability/HardcodedLineSeparatorsInspection.java @@ -0,0 +1,16 @@ +package com.siyeh.igtest.portability; + +import java.io.IOException; + +public class HardcodedLineSeparatorsInspection +{ + public HardcodedLineSeparatorsInspection() + { + } + + public void foo() throws IOException + { + final String newlineString = "\n"; + final String returnString = "\r"; + } +} \ No newline at end of file diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/portability/NativeMethodInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/portability/NativeMethodInspection.java new file mode 100644 index 000000000000..51cda59d49ef --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/portability/NativeMethodInspection.java @@ -0,0 +1,11 @@ +package com.siyeh.igtest.portability; + + +public class NativeMethodInspection +{ + public NativeMethodInspection() + { + } + + public native void foo(); +} \ No newline at end of file diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/portability/RuntimeExecInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/portability/RuntimeExecInspection.java new file mode 100644 index 000000000000..ba42e9152586 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/portability/RuntimeExecInspection.java @@ -0,0 +1,16 @@ +package com.siyeh.igtest.portability; + +import java.io.IOException; + +public class RuntimeExecInspection +{ + public RuntimeExecInspection() + { + } + + public void foo() throws IOException + { + final Runtime runtime = Runtime.getRuntime(); + runtime.exec("foo"); + } +} \ No newline at end of file diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/portability/StaticImport.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/portability/StaticImport.java new file mode 100644 index 000000000000..29ddf5b6cb06 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/portability/StaticImport.java @@ -0,0 +1,10 @@ +package com.siyeh.igtest.portability; + +import static Math; + +public class StaticImport { + + public static void main(String[] args) { + Math.abs(3.0); + } +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/portability/SystemExitInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/portability/SystemExitInspection.java new file mode 100644 index 000000000000..1850e2f5c2d3 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/portability/SystemExitInspection.java @@ -0,0 +1,17 @@ +package com.siyeh.igtest.portability; + +import java.io.IOException; + +public class SystemExitInspection +{ + public SystemExitInspection() + { + } + + public void foo() throws IOException + { + System.exit(0); + Runtime.getRuntime().exit(0); + Runtime.getRuntime().halt(0); + } +} \ No newline at end of file diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/portability/SystemGetEnvInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/portability/SystemGetEnvInspection.java new file mode 100644 index 000000000000..99825a649fb3 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/portability/SystemGetEnvInspection.java @@ -0,0 +1,15 @@ +package com.siyeh.igtest.portability; + +import java.io.IOException; + +public class SystemGetEnvInspection +{ + public SystemGetEnvInspection() + { + } + + public void foo() throws IOException + { + System.getenv("foo"); + } +} \ No newline at end of file diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/portability/VarargMethod.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/portability/VarargMethod.java new file mode 100644 index 000000000000..e35c6babc6a9 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/portability/VarargMethod.java @@ -0,0 +1,18 @@ +package com.siyeh.igtest.portability; + +public class VarargMethod { + + public static void main(String[] args) { + + } + + public int sum(int... var) + { + int total = 0; + for (int i = 0; i < var.length; i++) { + total+= var[i]; + } + return total; + } + +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/serialization/ExternalizableWithSerializationMethods.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/serialization/ExternalizableWithSerializationMethods.java new file mode 100644 index 000000000000..938698123300 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/serialization/ExternalizableWithSerializationMethods.java @@ -0,0 +1,24 @@ +package com.siyeh.igtest.serialization; + +import java.io.*; + +public class ExternalizableWithSerializationMethods implements Externalizable +{ + private static final long serialVersionUID = 1; + + private void readObject(ObjectInputStream str) + { + + } + + private void writeObject(ObjectOutputStream str) + { + + } + + public void writeExternal(ObjectOutput out) throws IOException { + } + + public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { + } +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/serialization/NonSerializableFieldInSerializableClass.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/serialization/NonSerializableFieldInSerializableClass.java new file mode 100644 index 000000000000..2aef46583d6b --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/serialization/NonSerializableFieldInSerializableClass.java @@ -0,0 +1,14 @@ +package com.siyeh.igtest.serialization; + +import com.siyeh.ig.fixes.RenameFix; +import com.siyeh.ig.fixes.RenameFix; + +import java.io.Serializable; + +public class NonSerializableFieldInSerializableClass implements Serializable{ + private int foo; + private int[] fooArray; + private RenameFix fix; + private RenameFix[] fixArray; + private transient RenameFix fix2; +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/serialization/NonSerializableWithSerializationMethods.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/serialization/NonSerializableWithSerializationMethods.java new file mode 100644 index 000000000000..28f1dce520bb --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/serialization/NonSerializableWithSerializationMethods.java @@ -0,0 +1,18 @@ +package com.siyeh.igtest.serialization; + +import java.io.*; + +public class NonSerializableWithSerializationMethods +{ + private static final long serialVersionUID = 1; + + private void readObject(ObjectInputStream str) + { + + } + + private void writeObject(ObjectOutputStream str) + { + + } +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/serialization/NonserializableGrandarent.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/serialization/NonserializableGrandarent.java new file mode 100644 index 000000000000..9d1de6f796ea --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/serialization/NonserializableGrandarent.java @@ -0,0 +1,16 @@ +package com.siyeh.igtest.serialization; + +public class NonserializableGrandarent +{ + private int m_arg; + public NonserializableGrandarent(int arg) + { + super(); + m_arg = arg; + bar(m_arg); + } + + private void bar(int arg) + { + } +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/serialization/ReadObjectAndWriteObjectPrivateInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/serialization/ReadObjectAndWriteObjectPrivateInspection.java new file mode 100644 index 000000000000..8241514b5c85 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/serialization/ReadObjectAndWriteObjectPrivateInspection.java @@ -0,0 +1,23 @@ +package com.siyeh.igtest.serialization; + +import java.io.*; + +public class ReadObjectAndWriteObjectPrivateInspection implements Serializable +{ + private static final long serialVersionUID = 1; + + public ReadObjectAndWriteObjectPrivateInspection() + { + } + + void readObject(ObjectInputStream str) + { + + } + + public void writeObject(ObjectOutputStream str) + { + + } +} + diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/serialization/ReadResolveAndWriteReplaceProtectedInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/serialization/ReadResolveAndWriteReplaceProtectedInspection.java new file mode 100644 index 000000000000..ffac423f2694 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/serialization/ReadResolveAndWriteReplaceProtectedInspection.java @@ -0,0 +1,33 @@ +package com.siyeh.igtest.serialization; + +import java.io.*; + +public class ReadResolveAndWriteReplaceProtectedInspection implements Serializable +{ + private static final long serialVersionUID = 1; + + public ReadResolveAndWriteReplaceProtectedInspection() + { + } + + private void readObject(ObjectInputStream str) + { + + } + + private void writeObject(ObjectOutputStream str) + { + + } + + Object writeReplace() throws ObjectStreamException + { + return null; + } + + public Object readResolve() throws ObjectStreamException + { + return null; + } +} + diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/serialization/SerialVersionUIDNotStaticFinalInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/serialization/SerialVersionUIDNotStaticFinalInspection.java new file mode 100644 index 000000000000..8464b46b53ed --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/serialization/SerialVersionUIDNotStaticFinalInspection.java @@ -0,0 +1,24 @@ +package com.siyeh.igtest.serialization; + +import java.io.*; + +public class SerialVersionUIDNotStaticFinalInspection implements Serializable +{ + private long serialVersionUID = 1; + + public SerialVersionUIDNotStaticFinalInspection() + { + System.out.println(serialVersionUID); + } + + private void readObject(ObjectInputStream str) + { + + } + + private void writeObject(ObjectOutputStream str) + { + + } +} + diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/serialization/SerializableHasSerialVersionUIDInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/serialization/SerializableHasSerialVersionUIDInspection.java new file mode 100644 index 000000000000..08cdd2057a14 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/serialization/SerializableHasSerialVersionUIDInspection.java @@ -0,0 +1,24 @@ +package com.siyeh.igtest.serialization; + +import java.io.*; + +public class SerializableHasSerialVersionUIDInspection implements Serializable +{ + public static void main(String[] args) + { + new SerializableHasSerialVersionUIDInspection(); + } + public SerializableHasSerialVersionUIDInspection() + { + } + + private void readObject(ObjectInputStream str) + { + + } + + private void writeObject(ObjectOutputStream str) + { + + } +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/serialization/SerializableHasSerializationMethodsInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/serialization/SerializableHasSerializationMethodsInspection.java new file mode 100644 index 000000000000..11f8424617a5 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/serialization/SerializableHasSerializationMethodsInspection.java @@ -0,0 +1,16 @@ +package com.siyeh.igtest.serialization; + +import java.io.Serializable; + +public class SerializableHasSerializationMethodsInspection implements Serializable +{ + private static final long serialVersionUID = 1; + + public static void main(String[] args) + { + new SerializableHasSerializationMethodsInspection(); + } + public SerializableHasSerializationMethodsInspection() + { + } +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/serialization/SerializableInnerClassHasSerialVersionUIDInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/serialization/SerializableInnerClassHasSerialVersionUIDInspection.java new file mode 100644 index 000000000000..3d3c15e50f0e --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/serialization/SerializableInnerClassHasSerialVersionUIDInspection.java @@ -0,0 +1,14 @@ +package com.siyeh.igtest.serialization; + +import java.io.Serializable; + + +public class SerializableInnerClassHasSerialVersionUIDInspection +{ + static class InnerStatic implements Serializable{ + + } + class InnerNonStatic implements Serializable{ + + } +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/serialization/SerializableParent.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/serialization/SerializableParent.java new file mode 100644 index 000000000000..74e3d60ab8ca --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/serialization/SerializableParent.java @@ -0,0 +1,15 @@ +package com.siyeh.igtest.serialization; + +import java.io.Serializable; + +public class SerializableParent + extends NonserializableGrandarent implements Serializable +{ + private int m_foo; + + public SerializableParent(int arg, int foo) + { + super(arg); + m_foo = foo; + } +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/serialization/SerializableWithUnconstructableAncestorInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/serialization/SerializableWithUnconstructableAncestorInspection.java new file mode 100644 index 000000000000..68e213a9c82d --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/serialization/SerializableWithUnconstructableAncestorInspection.java @@ -0,0 +1,14 @@ +package com.siyeh.igtest.serialization; + + +import java.io.*; + +public class SerializableWithUnconstructableAncestorInspection extends SerializableParent implements Serializable +{ + public SerializableWithUnconstructableAncestorInspection(int arg, int foo) + { + super(arg, foo); + } + +} + diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/serialization/TransientFieldInNonSerializableClass.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/serialization/TransientFieldInNonSerializableClass.java new file mode 100644 index 000000000000..f9c6578f8a8d --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/serialization/TransientFieldInNonSerializableClass.java @@ -0,0 +1,6 @@ +package com.siyeh.igtest.serialization; + +public class TransientFieldInNonSerializableClass +{ + public transient int m_var; +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/serialization/TransientFieldInSerializabeByInheritance.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/serialization/TransientFieldInSerializabeByInheritance.java new file mode 100644 index 000000000000..de5816ecbed8 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/serialization/TransientFieldInSerializabeByInheritance.java @@ -0,0 +1,6 @@ +package com.siyeh.igtest.serialization; + +public class TransientFieldInSerializabeByInheritance extends Exception +{ + public transient int m_var; +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/style/CStyleArrayDeclarationInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/style/CStyleArrayDeclarationInspection.java new file mode 100644 index 000000000000..00d3e0ec97d4 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/style/CStyleArrayDeclarationInspection.java @@ -0,0 +1,34 @@ +package com.siyeh.igtest.style; + +public class CStyleArrayDeclarationInspection +{ + private int[] m_foo; + private int m_bar[]; + + public CStyleArrayDeclarationInspection(int[] bar, int[] foo) + { + m_bar = bar; + m_foo = foo; + for(int i = 0; i < bar.length; i++) + { + m_foo[i] = m_bar[i]; + } + + } + + public void foo() + { + final int foo[] = new int[3]; + final int[] bar = new int[3]; + + for(int i = 0; i < bar.length; i++) + { + foo[i] = bar[i]; + } + } + + public void bar(int foo[], int[] bar) + { + + } +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/style/ConstantOnLHSInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/style/ConstantOnLHSInspection.java new file mode 100644 index 000000000000..8243dbbe4582 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/style/ConstantOnLHSInspection.java @@ -0,0 +1,15 @@ +package com.siyeh.igtest.style; + +public class ConstantOnLHSInspection +{ + private int m_bar = 4; + private boolean m_foo = (3 == m_bar); + + public void foo() + { + if(3 == m_bar) + { + + } + } +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/style/ConstantOnRHSInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/style/ConstantOnRHSInspection.java new file mode 100644 index 000000000000..379b49c6d688 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/style/ConstantOnRHSInspection.java @@ -0,0 +1,15 @@ +package com.siyeh.igtest.style; + +public class ConstantOnRHSInspection +{ + private int m_bar = 4; + private boolean m_foo = (m_bar == 3); + + public void foo() + { + if(m_bar == 3) + { + + } + } +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/style/MissortedModifiersInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/style/MissortedModifiersInspection.java new file mode 100644 index 000000000000..795978b44bea --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/style/MissortedModifiersInspection.java @@ -0,0 +1,17 @@ +package com.siyeh.igtest.style; + +final public class MissortedModifiersInspection +{ + static private int m_bar = 4; + static public int m_baz = 4; + static final public int m_baz2 = 4; + static final int m_baz3 = 4; + + static public void foo(){} + + static public class Foo + { + + } + +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/style/MultipleVariableDeclarationInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/style/MultipleVariableDeclarationInspection.java new file mode 100644 index 000000000000..ba0fe2ab715f --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/style/MultipleVariableDeclarationInspection.java @@ -0,0 +1,21 @@ +package com.siyeh.igtest.style; + +public class MultipleVariableDeclarationInspection +{ + private int foo; + private int m_fooBaz, m_fooBar; + private int m_fooBaz2; + private int m_fooBar2; + + public void fooBar() + { + int fooBaz, fooBar; + int fooBaz2; + int fooBar2; + + for(int i =0, j=0;i<100;i++,j++) + { + + } + } +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/style/MultipleVariableTypeDeclarationInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/style/MultipleVariableTypeDeclarationInspection.java new file mode 100644 index 000000000000..03efe57fe44b --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/style/MultipleVariableTypeDeclarationInspection.java @@ -0,0 +1,12 @@ +package com.siyeh.igtest.style; + +public class MultipleVariableTypeDeclarationInspection +{ + private int m_fooBaz, m_fooBar[]; + + public void fooBar() + { + int fooBaz, // comment1 + fooBar[]; //comment2 + } +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/style/OverloadedMethodsWithSameNumberOfParametersInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/style/OverloadedMethodsWithSameNumberOfParametersInspection.java new file mode 100644 index 000000000000..9e6ae40ee065 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/style/OverloadedMethodsWithSameNumberOfParametersInspection.java @@ -0,0 +1,14 @@ +package com.siyeh.igtest.style; + +public class OverloadedMethodsWithSameNumberOfParametersInspection +{ + public void fooBar(int i) + { + + } + + public void fooBar(double d) + { + + } +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/style/ReturnThis.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/style/ReturnThis.java new file mode 100644 index 000000000000..aef869e7bc6c --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/style/ReturnThis.java @@ -0,0 +1,9 @@ +package com.siyeh.igtest.style; + +public class ReturnThis +{ + public ReturnThis foo() + { + return this; + } +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/style/StringLiteralAsArgToEqualsInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/style/StringLiteralAsArgToEqualsInspection.java new file mode 100644 index 000000000000..ffc54b5d091e --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/style/StringLiteralAsArgToEqualsInspection.java @@ -0,0 +1,19 @@ +package com.siyeh.igtest.style; + +public class StringLiteralAsArgToEqualsInspection +{ + private String m_bar = "4"; + private boolean m_foo = m_bar.equals("3"); + + public void foo() + { + if(m_bar.equals("3")) + { + + } + if(m_bar.equalsIgnoreCase("3")) + { + + } + } +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/threading/BusyWaitInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/threading/BusyWaitInspection.java new file mode 100644 index 000000000000..fb9b020922f5 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/threading/BusyWaitInspection.java @@ -0,0 +1,19 @@ +package com.siyeh.igtest.threading; + +public class BusyWaitInspection +{ + public void fooBar() + { + while(true) + { + try + { + Thread.sleep(1L); + } + catch(InterruptedException e) + { + e.printStackTrace(); + } + } + } +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/threading/DoubleCheckedLockingInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/threading/DoubleCheckedLockingInspection.java new file mode 100644 index 000000000000..81d655258b24 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/threading/DoubleCheckedLockingInspection.java @@ -0,0 +1,21 @@ +package com.siyeh.igtest.threading; + +public class DoubleCheckedLockingInspection +{ + private static Object s_instance; + + public static Object foo() + { + if(s_instance == null) + { + synchronized(DoubleCheckedLockingInspection.class) + { + if(s_instance == null) + { + s_instance = new Object(); + } + } + } + return s_instance; + } +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/threading/FieldAccessedSynchronizedAndUnsynchronized.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/threading/FieldAccessedSynchronizedAndUnsynchronized.java new file mode 100644 index 000000000000..51199469919e --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/threading/FieldAccessedSynchronizedAndUnsynchronized.java @@ -0,0 +1,21 @@ +package com.siyeh.igtest.threading; + +public class FieldAccessedSynchronizedAndUnsynchronized +{ + private final Object m_lock = new Object(); + private Object m_contents = new Object(); + + public void foo() + { + synchronized(m_lock) + { + m_contents = new Object(); + } + } + + public Object getContents() + { + return m_contents; + } + +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/threading/MyThread.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/threading/MyThread.java new file mode 100644 index 000000000000..4a9e63d5efa8 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/threading/MyThread.java @@ -0,0 +1,9 @@ +package com.siyeh.igtest.threading; + +public class MyThread extends Thread +{ + public MyThread(Runnable runnable) + { + super(runnable); + } +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/threading/NakedNotifyInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/threading/NakedNotifyInspection.java new file mode 100644 index 000000000000..d23eb118701f --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/threading/NakedNotifyInspection.java @@ -0,0 +1,24 @@ +package com.siyeh.igtest.threading; + +public class NakedNotifyInspection +{ + public void foo() + { + final Object bar = new Object(); + synchronized (this) { + bar.toString(); + bar.notify(); + } + synchronized (this) { + notifyAll(); + } + synchronized (this) { + notify(); + } + } + + public synchronized void bar() + { + notifyAll(); + } +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/threading/NestedSynchroneInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/threading/NestedSynchroneInspection.java new file mode 100644 index 000000000000..4aaa17953f2e --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/threading/NestedSynchroneInspection.java @@ -0,0 +1,16 @@ +package com.siyeh.igtest.threading; + +public class NestedSynchroneInspection +{ + + public void foo() + { + synchronized(this) + { + synchronized(this) + { + + } + } + } +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/threading/NonSynchronizedMethodOverridesSynchronizedMethodInspection1.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/threading/NonSynchronizedMethodOverridesSynchronizedMethodInspection1.java new file mode 100644 index 000000000000..3c4cf2569e19 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/threading/NonSynchronizedMethodOverridesSynchronizedMethodInspection1.java @@ -0,0 +1,24 @@ +package com.siyeh.igtest.threading; + +public class NonSynchronizedMethodOverridesSynchronizedMethodInspection1 +{ + public synchronized void fooBar() + { + + } + + public synchronized void fooBang() + { + + } + + public void fooBaz() + { + + } + + public void fooBarangus() + { + + } +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/threading/NonSynchronizedMethodOverridesSynchronizedMethodInspection2.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/threading/NonSynchronizedMethodOverridesSynchronizedMethodInspection2.java new file mode 100644 index 000000000000..bfde5771487a --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/threading/NonSynchronizedMethodOverridesSynchronizedMethodInspection2.java @@ -0,0 +1,25 @@ +package com.siyeh.igtest.threading; + +public class NonSynchronizedMethodOverridesSynchronizedMethodInspection2 + extends NonSynchronizedMethodOverridesSynchronizedMethodInspection1 +{ + public synchronized void fooBar() + { + + } + + public void fooBang() + { + + } + + public synchronized void fooBaz() + { + + } + + public void fooBarangus() + { + + } +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/threading/NotifyNotInSynchronizedContextInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/threading/NotifyNotInSynchronizedContextInspection.java new file mode 100644 index 000000000000..5f48ad7f7c13 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/threading/NotifyNotInSynchronizedContextInspection.java @@ -0,0 +1,36 @@ +package com.siyeh.igtest.threading; + +public class NotifyNotInSynchronizedContextInspection +{ + private final Object lock = new Object(); + + public void foo() + { + lock.notify(); + } + public synchronized void bar() + { + lock.notify(); + } + + public void barzoomb() { + synchronized (lock) { + lock.notify(); + } + } + + public void fooAll() + { + lock.notifyAll(); + } + public synchronized void barAll() + { + lock.notifyAll(); + } + + public void barzoombAll() { + synchronized (lock) { + lock.notifyAll(); + } + } +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/threading/ObjectNotifyInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/threading/ObjectNotifyInspection.java new file mode 100644 index 000000000000..4d877c657a79 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/threading/ObjectNotifyInspection.java @@ -0,0 +1,11 @@ +package com.siyeh.igtest.threading; + +public class ObjectNotifyInspection +{ + public void foo() + { + final Object bar = new Object(); + bar.notify(); + notify(); + } +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/threading/PublicFieldAccessedInSynchronizedContextInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/threading/PublicFieldAccessedInSynchronizedContextInspection.java new file mode 100644 index 000000000000..c71858895390 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/threading/PublicFieldAccessedInSynchronizedContextInspection.java @@ -0,0 +1,29 @@ +package com.siyeh.igtest.threading; + +public class PublicFieldAccessedInSynchronizedContextInspection +{ + public int foo = 0; + protected int baz = 0; + private int bar = 0; + final int barangus = 0; + + public void bar() + { + synchronized(this) + { + foo++; + bar++; + baz++; + System.out.println(barangus); + } + } + + public synchronized void bar2() + { + foo++; + bar++; + baz++; + System.out.println(baz); + System.out.println(barangus); + } +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/threading/SynchronizationOnLockObjectInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/threading/SynchronizationOnLockObjectInspection.java new file mode 100644 index 000000000000..8fb4cfdbcbc4 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/threading/SynchronizationOnLockObjectInspection.java @@ -0,0 +1,16 @@ +package com.siyeh.igtest.threading; + +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantLock; + +public class SynchronizationOnLockObjectInspection +{ + private final Lock lock = new ReentrantLock(); + + + + public void barzoomb() throws InterruptedException { + synchronized (lock) { + } + } +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/threading/SynchronizeOnNonFinalFieldInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/threading/SynchronizeOnNonFinalFieldInspection.java new file mode 100644 index 000000000000..791a705908e0 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/threading/SynchronizeOnNonFinalFieldInspection.java @@ -0,0 +1,14 @@ +package com.siyeh.igtest.threading; + +public class SynchronizeOnNonFinalFieldInspection +{ + private Object m_lock = new Object(); + + public void fooBar() + { + synchronized(m_lock) + { + System.out.println(""); + } + } +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/threading/SynchronizedMethodInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/threading/SynchronizedMethodInspection.java new file mode 100644 index 000000000000..ce5993af82f3 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/threading/SynchronizedMethodInspection.java @@ -0,0 +1,11 @@ +package com.siyeh.igtest.threading; + +public class SynchronizedMethodInspection +{ + public synchronized void fooBar() + { + + } + + public synchronized native void fooBaz(); +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/threading/ThreadRunInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/threading/ThreadRunInspection.java new file mode 100644 index 000000000000..9c546cbe1e0b --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/threading/ThreadRunInspection.java @@ -0,0 +1,20 @@ +package com.siyeh.igtest.threading; + +public class ThreadRunInspection +{ + public void foo() + { + final Runnable runnable = new Runnable() + { + public void run() + { + + } + }; + final Thread thread = new Thread(runnable); + thread.run(); + + final MyThread thread2 = new MyThread(runnable); + thread2.run(); + } +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/threading/ThreadStartInConstructionInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/threading/ThreadStartInConstructionInspection.java new file mode 100644 index 000000000000..35cc7acec5e7 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/threading/ThreadStartInConstructionInspection.java @@ -0,0 +1,16 @@ +package com.siyeh.igtest.threading; + +public class ThreadStartInConstructionInspection +{ + private final Object lock = new Object(); + + { + new MyThread(new Runnable(){ + public void run() { + } + }).start(); + } + public ThreadStartInConstructionInspection() { + new Thread().start(); + } +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/threading/UnconditionalWaitInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/threading/UnconditionalWaitInspection.java new file mode 100644 index 000000000000..3830561ec368 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/threading/UnconditionalWaitInspection.java @@ -0,0 +1,31 @@ +package com.siyeh.igtest.threading; + +public class UnconditionalWaitInspection +{ + public void foo() throws InterruptedException { + final Object bar = new Object(); + synchronized (this) { + bar.toString(); + bar.wait(); + } + synchronized (this) { + if(foobar()) + { + + } + bar.wait(); + } + synchronized (this) { + wait(); + } + } + + private boolean foobar() { + return false; + } + + public synchronized void bar() + { + notifyAll(); + } +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/threading/VolatileLongOrDoubleInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/threading/VolatileLongOrDoubleInspection.java new file mode 100644 index 000000000000..0a6199e11c5b --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/threading/VolatileLongOrDoubleInspection.java @@ -0,0 +1,7 @@ +package com.siyeh.igtest.threading; + +public class VolatileLongOrDoubleInspection +{ + private volatile long foo =4L; + private volatile double bar =4L; +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/threading/WaitNotInLoopInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/threading/WaitNotInLoopInspection.java new file mode 100644 index 000000000000..b506496857fe --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/threading/WaitNotInLoopInspection.java @@ -0,0 +1,17 @@ +package com.siyeh.igtest.threading; + +public class WaitNotInLoopInspection +{ + private Object lock; + + public void foo() + { + try + { + lock.wait(); + } + catch(InterruptedException e) + { + } + } +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/threading/WaitNotInSynchronizedContextInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/threading/WaitNotInSynchronizedContextInspection.java new file mode 100644 index 000000000000..c213b875c7c6 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/threading/WaitNotInSynchronizedContextInspection.java @@ -0,0 +1,33 @@ +package com.siyeh.igtest.threading; + +public class WaitNotInSynchronizedContextInspection +{ + private final Object lock = new Object(); + + public void foo() + { + try + { + lock.wait(); + } + catch(InterruptedException e) + { + } + } + public synchronized void bar() + { + try + { + lock.wait(); + } + catch(InterruptedException e) + { + } + } + + public void barzoomb() throws InterruptedException { + synchronized (lock) { + lock.wait(); + } + } +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/threading/WaitWhileHoldingTwoLocksInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/threading/WaitWhileHoldingTwoLocksInspection.java new file mode 100644 index 000000000000..5fef8a7f8243 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/threading/WaitWhileHoldingTwoLocksInspection.java @@ -0,0 +1,27 @@ +package com.siyeh.igtest.threading; + +public class WaitWhileHoldingTwoLocksInspection +{ + private final Object lock = new Object(); + private final Object lock2 = new Object(); + + public void foo() throws InterruptedException { + synchronized (lock2) { + synchronized (lock) { + lock.wait(); + } + } + + } + public synchronized void bar() throws InterruptedException { + synchronized (lock) { + lock.wait(); + } + } + + public void barzoomb() throws InterruptedException { + synchronized (lock) { + lock.wait(); + } + } +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/threading/WhileLoopSpinsOnFieldInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/threading/WhileLoopSpinsOnFieldInspection.java new file mode 100644 index 000000000000..138fff1c2a89 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/threading/WhileLoopSpinsOnFieldInspection.java @@ -0,0 +1,23 @@ +package com.siyeh.igtest.threading; + +public class WhileLoopSpinsOnFieldInspection +{ + private Object test = null; + private int testInt = 3; + private volatile int testVolatileInt = 3; + + public void foo() + { + while(test!=null); + while(test!=null) + { + System.out.println(""); + } + while(testInt!=3) + { + + } + while(testVolatileInt!=3); + + } +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/verbose/BooleanComparisonInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/verbose/BooleanComparisonInspection.java new file mode 100644 index 000000000000..d9d4eaae32c2 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/verbose/BooleanComparisonInspection.java @@ -0,0 +1,52 @@ +package com.siyeh.igtest.verbose; + +public class BooleanComparisonInspection +{ + private boolean m_foo; + private boolean m_bar; + + public BooleanComparisonInspection(boolean foo) + { + this.m_foo = foo; + } + + public void foo() + { + if(m_foo == true) + { + + } + if(m_foo == false) + { + + } + if(true == m_foo) + { + + } + if(false == m_foo) + { + + } + if(m_foo != true) + { + + } + if(m_foo != false) + { + + } + if(true != m_foo) + { + + } + if(false != m_foo) + { + + } + if(m_bar == m_foo) + { + + } + } +} \ No newline at end of file diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/verbose/ExtendsObjectInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/verbose/ExtendsObjectInspection.java new file mode 100644 index 000000000000..ce741d7ae1ab --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/verbose/ExtendsObjectInspection.java @@ -0,0 +1,5 @@ +package com.siyeh.igtest.verbose; + +public class ExtendsObjectInspection extends Object +{ +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/verbose/FinalMethodInFinalClassInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/verbose/FinalMethodInFinalClassInspection.java new file mode 100644 index 000000000000..843974058172 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/verbose/FinalMethodInFinalClassInspection.java @@ -0,0 +1,9 @@ +package com.siyeh.igtest.verbose; + +public final class FinalMethodInFinalClassInspection +{ + public final void foo() + { + + } +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/verbose/ForCanBeForEachInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/verbose/ForCanBeForEachInspection.java new file mode 100644 index 000000000000..a31edf170060 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/verbose/ForCanBeForEachInspection.java @@ -0,0 +1,83 @@ +package com.siyeh.igtest.verbose; + +import java.util.*; + +public class ForCanBeForEachInspection { + + public int foo() { + final int[] ints = new int[3]; + int total = 0; + for (int i = 0; i < ints.length; i++) { + final int j = ints[i]; + total += j; + } + return total; + } + + public int bar() { + final int[] ints = new int[3]; + int total = 0; + for (int i = 0; i < ints.length; i++) { + total += ints[i]; + } + return total; + } + + public int baz() { + int total = 0; + final List ints = new ArrayList(); + for (Iterator iterator = ints.iterator(); iterator.hasNext();) { + final Integer value = (Integer) iterator.next(); + total += value.intValue(); + } + return total; + } + + public int bazoom() { + int total = 0; + final List ints = new ArrayList(); + for (Iterator iterator = ints.iterator(); iterator.hasNext();) { + final Integer value = iterator.next(); + total += value.intValue(); + } + return total; + } + + + public static String[] getAttributes(){ + final String[] result = new String[3]; + for(int j = 0; j < result.length; j++){ + result[j] = "3"; + } + return result; + } + + + public void test() { + Map m = new HashMap(); + m.put("123", 123); + m.put("456", 456); + for (Iterator> iterator = m.entrySet().iterator(); iterator.hasNext();) { + Map.Entry entry = iterator.next(); + System.out.println(entry.getKey() + "=" + entry.getValue()); + } + } + + public void boom() + { + Map map = null; + + final Set> entries = map.entrySet(); + for(Iterator> it = entries.iterator(); + it.hasNext();){ + boolean wouldFit = it.next().getValue(); + if(wouldFit){ + // if it would fit before, it might not now + it.remove(); + } + } + + } + + +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/verbose/PointlessArithmeticExpressionInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/verbose/PointlessArithmeticExpressionInspection.java new file mode 100644 index 000000000000..aebd12584b8b --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/verbose/PointlessArithmeticExpressionInspection.java @@ -0,0 +1,30 @@ +package com.siyeh.igtest.verbose; + +public class PointlessArithmeticExpressionInspection +{ + private static final int ZERO_CONSTANT = 0; + private static final int ONE_CONSTANT = 1; + + public static void main(String[] args) + { + final int i = 2; + final int j = i + 0; + System.out.println(j); + int k = 0+j; + System.out.println(k); + k = j - 0; + System.out.println(k); + k = 0 - j; + System.out.println(k); + k = j * ZERO_CONSTANT; + System.out.println(k); + k = j * ONE_CONSTANT; + System.out.println(k); + k = j / 1; + System.out.println(k); + String string = "foo" + 0; + + + + } +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/verbose/PointlessBitwiseExpressionInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/verbose/PointlessBitwiseExpressionInspection.java new file mode 100644 index 000000000000..dbe22615599a --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/verbose/PointlessBitwiseExpressionInspection.java @@ -0,0 +1,60 @@ +package com.siyeh.igtest.verbose; + +public class PointlessBitwiseExpressionInspection { + public static void main(String[] args) { + final int i = 1; + int j = i & 0; + System.out.println(j); + j = 3; + int k = j | 0; + System.out.println(k); + k = j ^ 0; + System.out.println(k); + k = j << 0; + System.out.println(k); + k = j >> 0; + System.out.println(k); + k = j >>> 0; + System.out.println(k); + } + + public static void main3(String[] args) { + final int i = 1; + int j = 0 & i; + System.out.println(j); + j = 3; + int k = 0 | j; + System.out.println(k); + k = 0 ^ j; + System.out.println(k); + + } + + public static void main2(String[] args) { + final int i = 1; + int j = i & 0xffffffff; + System.out.println(j); + j = 3; + int k = j | 0xffffffff; + System.out.println(k); + j = 6; + k = j ^ 0xffffffff; + System.out.println(k); + + + } + + public static void main4(String[] args) { + final int i = 1; + int j = 0xffffffff & i; + System.out.println(j); + j = 3; + int k = 0xffffffff | j; + System.out.println(k); + j = 6; + k = 0xffffffff ^ j; + System.out.println(k); + + + } +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/verbose/PointlessBooleanInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/verbose/PointlessBooleanInspection.java new file mode 100644 index 000000000000..45d2c5650231 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/verbose/PointlessBooleanInspection.java @@ -0,0 +1,66 @@ +package com.siyeh.igtest.verbose; + +public class PointlessBooleanInspection +{ + private boolean m_foo; + private boolean m_bar; + + public PointlessBooleanInspection(boolean foo) + { + this.m_foo = foo; + } + + public void foo() + { + if(m_foo == true) + { + + } + if(m_foo == false) + { + + } + if(true == m_foo) + { + + } + if(false == m_foo) + { + + } + if(m_foo != true) + { + + } + if(m_foo != false) + { + + } + if(true != m_foo) + { + + } + if(false != m_foo) + { + + } + if(m_bar == m_foo) + { + + } + + if (m_foo || false) { + + } + if (false || m_foo) { + + } + + if (m_foo && true) { + + } + if (true && m_foo) { + + } + } +} \ No newline at end of file diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/verbose/RedundantImplementsInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/verbose/RedundantImplementsInspection.java new file mode 100644 index 000000000000..1005ee7535f4 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/verbose/RedundantImplementsInspection.java @@ -0,0 +1,8 @@ +package com.siyeh.igtest.verbose; + +import java.util.ArrayList; +import java.util.List; +import java.io.Serializable; + +public class RedundantImplementsInspection extends ArrayList implements List, Serializable{ +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/verbose/RedundantImplementsInspection2.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/verbose/RedundantImplementsInspection2.java new file mode 100644 index 000000000000..3473f3033b10 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/verbose/RedundantImplementsInspection2.java @@ -0,0 +1,98 @@ +package com.siyeh.igtest.verbose; + +import java.util.Collection; +import java.util.Iterator; +import java.util.List; +import java.util.ListIterator; + +public class RedundantImplementsInspection2 implements List, Collection{ + public int size() { + return 0; + } + + public boolean isEmpty() { + return false; + } + + public boolean contains(Object o) { + return false; + } + + public Iterator iterator() { + return null; + } + + public Object[] toArray() { + return new Object[0]; + } + + public Object[] toArray(Object[] ts) { + return new Object[0]; + } + + public boolean add(Object o) { + return false; + } + + public boolean remove(Object o) { + return false; + } + + public boolean containsAll(Collection c) { + return false; + } + + public boolean addAll(Collection collection) { + return false; + } + + public boolean addAll(int index, Collection collection) { + return false; + } + + public boolean removeAll(Collection c) { + return false; + } + + public boolean retainAll(Collection c) { + return false; + } + + public void clear() { + } + + public Object get(int index) { + return null; + } + + public Object set(int index, Object o) { + return null; + } + + public void add(int index, Object o) { + } + + public Object remove(int index) { + return null; + } + + public int indexOf(Object o) { + return 0; + } + + public int lastIndexOf(Object o) { + return 0; + } + + public ListIterator listIterator() { + return null; + } + + public ListIterator listIterator(int index) { + return null; + } + + public List subList(int fromIndex, int toIndex) { + return null; + } +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/verbose/RedundantImplementsInspection3.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/verbose/RedundantImplementsInspection3.java new file mode 100644 index 000000000000..2609937073c7 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/verbose/RedundantImplementsInspection3.java @@ -0,0 +1,7 @@ +package com.siyeh.igtest.verbose; + +import java.util.Collection; +import java.util.List; + +public interface RedundantImplementsInspection3 extends List, Collection{ +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/verbose/ReplaceAssignmentWithOperatorAssignmentInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/verbose/ReplaceAssignmentWithOperatorAssignmentInspection.java new file mode 100644 index 000000000000..7f743bca8ce5 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/verbose/ReplaceAssignmentWithOperatorAssignmentInspection.java @@ -0,0 +1,22 @@ +package com.siyeh.igtest.verbose; + +public class ReplaceAssignmentWithOperatorAssignmentInspection +{ + + public ReplaceAssignmentWithOperatorAssignmentInspection() + { + + } + + public void foo() + { + int x = 0; + x = x + 3; + x = x * 3; + x = x / 3; + x = x - 3; + + System.out.println("x = " + x); + + } +} \ No newline at end of file diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/verbose/TrivialIfInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/verbose/TrivialIfInspection.java new file mode 100644 index 000000000000..134908084d29 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/verbose/TrivialIfInspection.java @@ -0,0 +1,41 @@ +package com.siyeh.igtest.verbose; + +public class TrivialIfInspection +{ + public boolean foo() + { + boolean x; + if(bar()) + { + x = true; + } + else + { + x = false; + } + System.out.println("x = " + x); + if(bar()) + { + x = false; + } + else + { + x = true; + } + System.out.println("x = " + x); + + if(bar()) + { + return true; + } + else + { + return false; + } + } + + private boolean bar() + { + return true; + } +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/verbose/TrivialStringConcatenationInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/verbose/TrivialStringConcatenationInspection.java new file mode 100644 index 000000000000..2411dc9afc77 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/verbose/TrivialStringConcatenationInspection.java @@ -0,0 +1,8 @@ +package com.siyeh.igtest.verbose; + +public class TrivialStringConcatenationInspection { + + public void foo() { + final String foo = "" + 4 + "" + 3; + } +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/verbose/TypeParameterExtendsObjectInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/verbose/TypeParameterExtendsObjectInspection.java new file mode 100644 index 000000000000..73680ebca312 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/verbose/TypeParameterExtendsObjectInspection.java @@ -0,0 +1,15 @@ +package com.siyeh.igtest.verbose; + +import java.util.List; + +public class TypeParameterExtendsObjectInspection { + + public void foo(E e) + { + + } + public void foo2(E e) + { + + } +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/verbose/UnnecessaryContinueInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/verbose/UnnecessaryContinueInspection.java new file mode 100644 index 000000000000..e2b6928663bb --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/verbose/UnnecessaryContinueInspection.java @@ -0,0 +1,20 @@ +package com.siyeh.igtest.verbose; + +public class UnnecessaryContinueInspection +{ + + public UnnecessaryContinueInspection() + { + for(;;) + { + continue; + } + } + public void foo() + { + while(true) + continue; + } + + +} \ No newline at end of file diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/verbose/UnnecessaryDefault.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/verbose/UnnecessaryDefault.java new file mode 100644 index 000000000000..a9f4e176c1a6 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/verbose/UnnecessaryDefault.java @@ -0,0 +1,16 @@ +package com.siyeh.igtest.verbose; + +import com.siyeh.igtest.bugs.MyEnum; + +public class UnnecessaryDefault{ + void foo(){ + MyEnum var = MyEnum.foo; + switch(var){ + case foo: + case bar: + case baz: + default: + break; + } + } +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/verbose/UnnecessaryEnumSemicolonInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/verbose/UnnecessaryEnumSemicolonInspection.java new file mode 100644 index 000000000000..e3dc74f4667d --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/verbose/UnnecessaryEnumSemicolonInspection.java @@ -0,0 +1,7 @@ +package com.siyeh.igtest.verbose; + +public enum UnnecessaryEnumSemicolonInspection +{ + foo, bar, baz; + +} \ No newline at end of file diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/verbose/UnnecessaryFinalOnAbstractMethodParameter.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/verbose/UnnecessaryFinalOnAbstractMethodParameter.java new file mode 100644 index 000000000000..22643a00e7c1 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/verbose/UnnecessaryFinalOnAbstractMethodParameter.java @@ -0,0 +1,6 @@ +package com.siyeh.igtest.verbose; + +public abstract class UnnecessaryFinalOnAbstractMethodParameter +{ + public abstract void foo(final int bar); +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/verbose/UnnecessaryFinalOnInterfaceParameter.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/verbose/UnnecessaryFinalOnInterfaceParameter.java new file mode 100644 index 000000000000..049ef74d7eb4 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/verbose/UnnecessaryFinalOnInterfaceParameter.java @@ -0,0 +1,6 @@ +package com.siyeh.igtest.verbose; + +public interface UnnecessaryFinalOnInterfaceParameter +{ + void foo(final int bar); +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/verbose/UnnecessaryFinalOnMethodParameter.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/verbose/UnnecessaryFinalOnMethodParameter.java new file mode 100644 index 000000000000..065e9c56df0a --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/verbose/UnnecessaryFinalOnMethodParameter.java @@ -0,0 +1,46 @@ +package com.siyeh.igtest.verbose; + +public class UnnecessaryFinalOnMethodParameter +{ + public void foo(final int bar) + { + int baz = bar; + + } + + public void foo2(final int bar) + { + Runnable runnable = new Runnable() + { + public void run() + { + int baz = bar; + } + }; + + } + + public void foo3(final int bar) + { + Runnable runnable = new Runnable() + { + public void run() + { + } + }; + + } + + + public void foo3(final Runnable bar) + { + Runnable runnable = new Runnable() + { + public void run() + { + bar.run(); + } + }; + + } +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/verbose/UnnecessaryFullyQualifiedNameInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/verbose/UnnecessaryFullyQualifiedNameInspection.java new file mode 100644 index 000000000000..4a8ebd24bc90 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/verbose/UnnecessaryFullyQualifiedNameInspection.java @@ -0,0 +1,12 @@ +package com.siyeh.igtest.verbose; + +public class UnnecessaryFullyQualifiedNameInspection +{ + private String m_string1; + private java.lang.String m_string; + private java.util.StringTokenizer m_map; + private java.util.List m_list; + private java.util.Map.Entry m_mapEntry; + private java.awt.List m_awtList; + +} \ No newline at end of file diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/verbose/UnnecessaryLabelInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/verbose/UnnecessaryLabelInspection.java new file mode 100644 index 000000000000..b1af019cc47c --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/verbose/UnnecessaryLabelInspection.java @@ -0,0 +1,18 @@ +package com.siyeh.igtest.verbose; + +public class UnnecessaryLabelInspection +{ + + public UnnecessaryLabelInspection() + { + + } + + public void foo() + { + int x = 0; + Label: + foo(); + + } +} \ No newline at end of file diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/verbose/UnnecessaryLabelOnBreakStatementInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/verbose/UnnecessaryLabelOnBreakStatementInspection.java new file mode 100644 index 000000000000..d69072a0bb5a --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/verbose/UnnecessaryLabelOnBreakStatementInspection.java @@ -0,0 +1,12 @@ +package com.siyeh.igtest.verbose; + +public class UnnecessaryLabelOnBreakStatementInspection { + public void foo() + { + label: + while(true) + { + break label; + } + } +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/verbose/UnnecessaryLabelOnContinueStatementInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/verbose/UnnecessaryLabelOnContinueStatementInspection.java new file mode 100644 index 000000000000..746252330135 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/verbose/UnnecessaryLabelOnContinueStatementInspection.java @@ -0,0 +1,12 @@ +package com.siyeh.igtest.verbose; + +public class UnnecessaryLabelOnContinueStatementInspection { + public void foo() + { + label: + while(true) + { + continue; + } + } +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/verbose/UnnecessaryParenthesesInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/verbose/UnnecessaryParenthesesInspection.java new file mode 100644 index 000000000000..5fbb6c2c81a0 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/verbose/UnnecessaryParenthesesInspection.java @@ -0,0 +1,27 @@ +package com.siyeh.igtest.verbose; + +public class UnnecessaryParenthesesInspection +{ + + public int foo() + { + final String s = "foo" + (3 + 4); + final String t = ("foo" + 3) + 4; + return (3); + } + + public void bar() + { + final int x = (3 + 4)*5; + final int q = (3 + 4)-5; + final int y = 3 + (4*5); + final int z = 3 + (4*(3*5)); + final int k = 4 * (3 * 5); + System.out.println("q = " + q); + System.out.println("x = " + x); + System.out.println("y = " + y); + System.out.println("z = " + z); + System.out.println("k = " + k); + } + +} \ No newline at end of file diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/verbose/UnnecessaryQualifierForThisInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/verbose/UnnecessaryQualifierForThisInspection.java new file mode 100644 index 000000000000..d3ec6fc7fffd --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/verbose/UnnecessaryQualifierForThisInspection.java @@ -0,0 +1,16 @@ +package com.siyeh.igtest.verbose; + +public class UnnecessaryQualifierForThisInspection { + public void foo() + { + System.out.println(UnnecessaryQualifierForThisInspection.this); + } + + public class Inner + { + public void foo() { + System.out.println(Inner.this); + System.out.println(UnnecessaryQualifierForThisInspection.this); + } + } +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/verbose/UnnecessaryReturnInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/verbose/UnnecessaryReturnInspection.java new file mode 100644 index 000000000000..cc9622d6717c --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/verbose/UnnecessaryReturnInspection.java @@ -0,0 +1,24 @@ +package com.siyeh.igtest.verbose; + +public class UnnecessaryReturnInspection +{ + + public UnnecessaryReturnInspection() + { + return; + } + + public void foo() + { + return; + } + + public void bar() + { + if(true) + { + return; + } + } + +} \ No newline at end of file diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/verbose/UnnecessaryThisInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/verbose/UnnecessaryThisInspection.java new file mode 100644 index 000000000000..df3d3c8d3963 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/verbose/UnnecessaryThisInspection.java @@ -0,0 +1,32 @@ +package com.siyeh.igtest.verbose; + +public class UnnecessaryThisInspection +{ + private int m_foo; + + public void fooBar() + { + this.m_foo = 3; + } + + public void fooBaz( int m_foo) + { + this.m_foo = 3; + } + + public void fooBarangus() + { + int m_foo; + this.m_foo = 3; + } + + public void fooBarzoom() + { + for(int m_foo = 0;m_foo<4; m_foo++) + { + this.m_foo = 3; + } + this.fooBar(); + } + +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/visibility/FieldHidesSuperclassFieldInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/visibility/FieldHidesSuperclassFieldInspection.java new file mode 100644 index 000000000000..ffcf0445b7cf --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/visibility/FieldHidesSuperclassFieldInspection.java @@ -0,0 +1,19 @@ +package com.siyeh.igtest.visibility; + +import java.util.Set; +import java.util.HashSet; + +public class FieldHidesSuperclassFieldInspection extends LocalVariableHidingMemberVariableInspection +{ + private int m_barangus = -1; + + public FieldHidesSuperclassFieldInspection(int barangus) + { + super(barangus); + } + + public void foo() + { + System.out.println("bar" + m_barangus); + } +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/visibility/InnerClassVariableHidesOuterClassVariableInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/visibility/InnerClassVariableHidesOuterClassVariableInspection.java new file mode 100644 index 000000000000..ae86f11df061 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/visibility/InnerClassVariableHidesOuterClassVariableInspection.java @@ -0,0 +1,25 @@ +package com.siyeh.igtest.visibility; + +import java.util.Set; +import java.util.HashSet; + +public class InnerClassVariableHidesOuterClassVariableInspection +{ + private int m_barangus = -1; + + public void foo() + { + System.out.println(m_barangus); + } + + private static class InnerClass + { + private int m_barangus = 3; + + public void foo() + { + System.out.println(m_barangus); + } + + } +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/visibility/LocalVariableHidingMemberVariableInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/visibility/LocalVariableHidingMemberVariableInspection.java new file mode 100644 index 000000000000..4d5527c51414 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/visibility/LocalVariableHidingMemberVariableInspection.java @@ -0,0 +1,27 @@ +package com.siyeh.igtest.visibility; + +import com.siyeh.igtest.visibility2.DifferentPackageClass; + + +public class LocalVariableHidingMemberVariableInspection extends DifferentPackageClass +{ + private int m_barangus = -1; + + public LocalVariableHidingMemberVariableInspection(int barangus) + { + m_barangus = barangus; + } + + public void foo() + { + int fooBar; + final Object m_barangus = new Object(); + System.out.println("bar" + m_barangus); + } + + public void setBarangus(int barangus) + { + m_barangus = barangus; + System.out.println(m_barangus); + } +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/visibility/MethodOverloadsChild.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/visibility/MethodOverloadsChild.java new file mode 100644 index 000000000000..18f92a485033 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/visibility/MethodOverloadsChild.java @@ -0,0 +1,12 @@ +package com.siyeh.igtest.visibility; + +import java.util.ArrayList; +import java.util.List; + +public class MethodOverloadsChild extends MethodOverloadsParent +{ + public void reverse(ArrayList l) + { + + } +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/visibility/MethodOverloadsParent.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/visibility/MethodOverloadsParent.java new file mode 100644 index 000000000000..cbfd6fb63ef0 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/visibility/MethodOverloadsParent.java @@ -0,0 +1,12 @@ +package com.siyeh.igtest.visibility; + +import java.util.List; +import java.util.ArrayList; + +public class MethodOverloadsParent +{ + public void reverse(List l) + { + + } +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/visibility/ParameterHidingMemberVariableInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/visibility/ParameterHidingMemberVariableInspection.java new file mode 100644 index 000000000000..c33ce8f54197 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/visibility/ParameterHidingMemberVariableInspection.java @@ -0,0 +1,24 @@ +package com.siyeh.igtest.visibility; + +import java.util.Set; +import java.util.HashSet; + +public class ParameterHidingMemberVariableInspection +{ + private int bar = -1; + + public ParameterHidingMemberVariableInspection(int bar) + { + this.bar = bar; + } + + public void setBar(int bar) + { + this.bar = bar; + } + + public void foo(Object bar) + { + System.out.println("bar" + bar); + } +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/visibility/PrivateMethodOverriddenClass.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/visibility/PrivateMethodOverriddenClass.java new file mode 100644 index 000000000000..708186d09f80 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/visibility/PrivateMethodOverriddenClass.java @@ -0,0 +1,9 @@ +package com.siyeh.igtest.visibility; + +public class PrivateMethodOverriddenClass extends PrivateMethodToOverrideClass +{ + public void fooBar() + { + + } +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/visibility/PrivateMethodToOverrideClass.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/visibility/PrivateMethodToOverrideClass.java new file mode 100644 index 000000000000..87141033037d --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/visibility/PrivateMethodToOverrideClass.java @@ -0,0 +1,9 @@ +package com.siyeh.igtest.visibility; + +public class PrivateMethodToOverrideClass +{ + private void fooBar() + { + + } +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/visibility/StaticMethodOverridenClass.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/visibility/StaticMethodOverridenClass.java new file mode 100644 index 000000000000..d7efcc005648 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/visibility/StaticMethodOverridenClass.java @@ -0,0 +1,9 @@ +package com.siyeh.igtest.visibility; + +public class StaticMethodOverridenClass extends StaticMethodToOverrideClass +{ + public static void fooBar() + { + + } +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/visibility/StaticMethodParamOverridesInstanceVariableClass.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/visibility/StaticMethodParamOverridesInstanceVariableClass.java new file mode 100644 index 000000000000..b30b32cc96ae --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/visibility/StaticMethodParamOverridesInstanceVariableClass.java @@ -0,0 +1,11 @@ +package com.siyeh.igtest.visibility; + +public class StaticMethodParamOverridesInstanceVariableClass extends StaticMethodToOverrideClass +{ + private int bar; + + public static void fooBar(int bar) + { + System.out.println("bar = " + bar); + } +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/visibility/StaticMethodToOverrideClass.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/visibility/StaticMethodToOverrideClass.java new file mode 100644 index 000000000000..2ae972ca4cfc --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/visibility/StaticMethodToOverrideClass.java @@ -0,0 +1,9 @@ +package com.siyeh.igtest.visibility; + +public class StaticMethodToOverrideClass +{ + public static void fooBar() + { + + } +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/visibility2/DifferentPackageClass.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/visibility2/DifferentPackageClass.java new file mode 100644 index 000000000000..75c8ef39d64a --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/visibility2/DifferentPackageClass.java @@ -0,0 +1,6 @@ +package com.siyeh.igtest.visibility2; + +public class DifferentPackageClass +{ + int fooBar; +} diff --git a/plugins/IntentionPowerPak/IntentionPowerPackPlugin.iml b/plugins/IntentionPowerPak/IntentionPowerPackPlugin.iml new file mode 100644 index 000000000000..6207677653ac --- /dev/null +++ b/plugins/IntentionPowerPak/IntentionPowerPackPlugin.iml @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/IntentionPowerPak/IntentionPowerPak.iml b/plugins/IntentionPowerPak/IntentionPowerPak.iml new file mode 100644 index 000000000000..1d1fcf4ca119 --- /dev/null +++ b/plugins/IntentionPowerPak/IntentionPowerPak.iml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/IntentionPowerPak/IntentionPowerPak.ipr b/plugins/IntentionPowerPak/IntentionPowerPak.ipr new file mode 100644 index 000000000000..40eed5d55feb --- /dev/null +++ b/plugins/IntentionPowerPak/IntentionPowerPak.ipr @@ -0,0 +1,212 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/IntentionPowerPak/IntentionPowerPak.iws b/plugins/IntentionPowerPak/IntentionPowerPak.iws new file mode 100644 index 000000000000..45a3c025bcdf --- /dev/null +++ b/plugins/IntentionPowerPak/IntentionPowerPak.iws @@ -0,0 +1,675 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/IntentionPowerPak/META-INF/plugin.xml b/plugins/IntentionPowerPak/META-INF/plugin.xml new file mode 100644 index 000000000000..cca677ecfc57 --- /dev/null +++ b/plugins/IntentionPowerPak/META-INF/plugin.xml @@ -0,0 +1,12 @@ + + Intention Power Pack + Over thirty new intention actions for IDEA + 0.9 + InspectionGadgets Software + + + + com.siyeh.ipp.IntentionPowerPack + + + diff --git a/plugins/IntentionPowerPak/build.xml b/plugins/IntentionPowerPak/build.xml new file mode 100644 index 000000000000..39a8eab6a8af --- /dev/null +++ b/plugins/IntentionPowerPak/build.xml @@ -0,0 +1,80 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/IntentionPowerPak/src/IPPIcon.png b/plugins/IntentionPowerPak/src/IPPIcon.png new file mode 100644 index 000000000000..0fac1a727c14 Binary files /dev/null and b/plugins/IntentionPowerPak/src/IPPIcon.png differ diff --git a/plugins/IntentionPowerPak/src/IPPIconold.png b/plugins/IntentionPowerPak/src/IPPIconold.png new file mode 100644 index 000000000000..2bb994cfecfa Binary files /dev/null and b/plugins/IntentionPowerPak/src/IPPIconold.png differ diff --git a/plugins/IntentionPowerPak/src/com/siyeh/ipp/bool/BooleanLiteralEqualityPredicate.java b/plugins/IntentionPowerPak/src/com/siyeh/ipp/bool/BooleanLiteralEqualityPredicate.java new file mode 100644 index 000000000000..7b0cdfd17c17 --- /dev/null +++ b/plugins/IntentionPowerPak/src/com/siyeh/ipp/bool/BooleanLiteralEqualityPredicate.java @@ -0,0 +1,33 @@ +package com.siyeh.ipp.bool; + +import com.intellij.psi.*; +import com.intellij.psi.tree.IElementType; +import com.siyeh.ipp.PsiElementPredicate; +import com.siyeh.ipp.psiutils.BoolUtils; + +class BooleanLiteralEqualityPredicate implements PsiElementPredicate +{ + public boolean satisfiedBy(PsiElement element) + { + if(!(element instanceof PsiBinaryExpression)) + { + return false; + } + final PsiBinaryExpression expression = (PsiBinaryExpression) element; + final PsiJavaToken sign = expression.getOperationSign(); + final IElementType tokenType = sign.getTokenType(); + if(!tokenType.equals(JavaTokenType.EQEQ) && + !tokenType.equals(JavaTokenType.NE)) + { + return false; + } + final PsiExpression lhs = expression.getLOperand(); + final PsiExpression rhs = expression.getROperand(); + if(lhs == null || rhs == null) + { + return false; + } + return BoolUtils.isBooleanLiteral(lhs) || + BoolUtils.isBooleanLiteral(rhs); + } +} diff --git a/plugins/IntentionPowerPak/src/com/siyeh/ipp/bool/ComparisonPredicate.java b/plugins/IntentionPowerPak/src/com/siyeh/ipp/bool/ComparisonPredicate.java new file mode 100644 index 000000000000..ca4371bbee2f --- /dev/null +++ b/plugins/IntentionPowerPak/src/com/siyeh/ipp/bool/ComparisonPredicate.java @@ -0,0 +1,25 @@ +package com.siyeh.ipp.bool; + +import com.intellij.psi.*; +import com.siyeh.ipp.PsiElementPredicate; +import com.siyeh.ipp.psiutils.ComparisonUtils; + +class ComparisonPredicate implements PsiElementPredicate +{ + public boolean satisfiedBy(PsiElement element) + { + if(!(element instanceof PsiBinaryExpression)) + { + return false; + } + final PsiBinaryExpression expression = (PsiBinaryExpression) element; + + final PsiExpression lhs = expression.getLOperand(); + final PsiExpression rhs = expression.getROperand(); + if(lhs == null || rhs == null) + { + return false; + } + return ComparisonUtils.isComparison((PsiExpression) element); + } +} diff --git a/plugins/IntentionPowerPak/src/com/siyeh/ipp/bool/ConjunctionPredicate.java b/plugins/IntentionPowerPak/src/com/siyeh/ipp/bool/ConjunctionPredicate.java new file mode 100644 index 000000000000..b6bd3fcaa9ab --- /dev/null +++ b/plugins/IntentionPowerPak/src/com/siyeh/ipp/bool/ConjunctionPredicate.java @@ -0,0 +1,21 @@ +package com.siyeh.ipp.bool; + +import com.intellij.psi.*; +import com.intellij.psi.tree.IElementType; +import com.siyeh.ipp.PsiElementPredicate; + +class ConjunctionPredicate implements PsiElementPredicate +{ + public boolean satisfiedBy(PsiElement exp) + { + if(!(exp instanceof PsiBinaryExpression)) + { + return false; + } + final PsiBinaryExpression expression = (PsiBinaryExpression) exp; + final PsiJavaToken sign = expression.getOperationSign(); + final IElementType tokenType = sign.getTokenType(); + return tokenType.equals(JavaTokenType.ANDAND) || + tokenType.equals(JavaTokenType.OROR); + } +} diff --git a/plugins/IntentionPowerPak/src/com/siyeh/ipp/bool/DemorgansIntention.java b/plugins/IntentionPowerPak/src/com/siyeh/ipp/bool/DemorgansIntention.java new file mode 100644 index 000000000000..e5846acb56b8 --- /dev/null +++ b/plugins/IntentionPowerPak/src/com/siyeh/ipp/bool/DemorgansIntention.java @@ -0,0 +1,140 @@ +package com.siyeh.ipp.bool; + +import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.project.Project; +import com.intellij.psi.*; +import com.intellij.psi.tree.IElementType; +import com.intellij.util.IncorrectOperationException; +import com.siyeh.ipp.*; +import com.siyeh.ipp.psiutils.*; + +public class DemorgansIntention extends MutablyNamedIntention +{ + public DemorgansIntention(Project project) + { + super(project); + } + + protected String getTextForElement(PsiElement element) + { + final PsiBinaryExpression binaryExpression = (PsiBinaryExpression) element; + final PsiJavaToken sign = binaryExpression.getOperationSign(); + final IElementType tokenType = sign.getTokenType(); + if(tokenType.equals(JavaTokenType.ANDAND)) + { + return "Replace && with ||"; + } + else + { + return "Replace || with &&"; + } + } + + public String getFamilyName() + { + return "DeMorgan Law"; + } + + public PsiElementPredicate getElementPredicate() + { + return new ConjunctionPredicate(); + } + + + public void invoke(Project project, Editor editor, PsiFile file) throws IncorrectOperationException + { + PsiBinaryExpression exp = (PsiBinaryExpression) findMatchingElement(file, editor); + final PsiJavaToken sign = exp.getOperationSign(); + final IElementType tokenType = sign.getTokenType(); + PsiElement parent = exp.getParent(); + while(isConjunctionExpression(parent, tokenType)) + { + exp = (PsiBinaryExpression) parent; + parent = exp.getParent(); + } + final String newExpression = convertConjunctionExpression(exp, tokenType); + replaceExpressionWithNegatedExpressionString(project, newExpression, exp); + } + + private String convertConjunctionExpression(PsiBinaryExpression exp, IElementType tokenType) + { + final String lhsText; + final PsiExpression lhs = exp.getLOperand(); + if(isConjunctionExpression(lhs, tokenType)) + { + lhsText = convertConjunctionExpression((PsiBinaryExpression) lhs, tokenType); + } + else + { + lhsText = convertLeafExpression(lhs); + } + final String rhsText; + final PsiExpression rhs = exp.getROperand(); + if(isConjunctionExpression(rhs, tokenType)) + { + rhsText = convertConjunctionExpression((PsiBinaryExpression) rhs, tokenType); + } + else + { + rhsText = convertLeafExpression(rhs); + } + + final String flippedConjunction; + if(tokenType.equals(JavaTokenType.ANDAND)) + { + flippedConjunction = "||"; + } + else + { + flippedConjunction = "&&"; + } + + return lhsText + flippedConjunction + rhsText; + + } + + private static String convertLeafExpression(PsiExpression condition) + { + if(BoolUtils.isNegation(condition)) + { + final PsiExpression negated = BoolUtils.getNegated(condition); + if(ParenthesesUtils.getPrecendence(negated) > ParenthesesUtils.OR_PRECEDENCE) + { + return '(' + negated.getText() + ')'; + } + return negated.getText(); + } + else if(ComparisonUtils.isComparison(condition)) + { + final PsiBinaryExpression binaryExpression = (PsiBinaryExpression) condition; + final PsiJavaToken sign = binaryExpression.getOperationSign(); + final String operator = sign.getText(); + final String negatedComparison = ComparisonUtils.getNegatedComparison(operator); + final PsiExpression lhs = binaryExpression.getLOperand(); + final PsiExpression rhs = binaryExpression.getROperand(); + return lhs.getText() + negatedComparison + rhs.getText(); + } + else if(ParenthesesUtils.getPrecendence(condition) > + ParenthesesUtils.PREFIX_PRECEDENCE) + { + return "!(" + condition.getText() + ')'; + } + else + { + return '!' + condition.getText(); + } + + } + + private static boolean isConjunctionExpression(PsiElement exp, IElementType conjunctionType) + { + if(!(exp instanceof PsiBinaryExpression)) + { + return false; + } + final PsiBinaryExpression binExp = (PsiBinaryExpression) exp; + final PsiJavaToken sign = binExp.getOperationSign(); + final IElementType tokenType = sign.getTokenType(); + return tokenType.equals(conjunctionType); + } +} diff --git a/plugins/IntentionPowerPak/src/com/siyeh/ipp/bool/FlipComparisonIntention.java b/plugins/IntentionPowerPak/src/com/siyeh/ipp/bool/FlipComparisonIntention.java new file mode 100644 index 000000000000..077f88e7f22b --- /dev/null +++ b/plugins/IntentionPowerPak/src/com/siyeh/ipp/bool/FlipComparisonIntention.java @@ -0,0 +1,58 @@ +package com.siyeh.ipp.bool; + +import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.project.Project; +import com.intellij.psi.*; +import com.intellij.util.IncorrectOperationException; +import com.siyeh.ipp.*; +import com.siyeh.ipp.psiutils.ComparisonUtils; + +public class FlipComparisonIntention extends MutablyNamedIntention +{ + public FlipComparisonIntention(Project project) + { + super(project); + } + + public String getTextForElement(PsiElement element) + { + String operatorText = ""; + String flippedOperatorText = ""; + final PsiBinaryExpression exp = (PsiBinaryExpression) element; + if(exp != null) + { + final PsiJavaToken sign = exp.getOperationSign(); + operatorText = sign.getText(); + flippedOperatorText = ComparisonUtils.getFlippedComparison(operatorText); + } + if(operatorText.equals(flippedOperatorText)) + { + return "Flip " + operatorText; + } + else + { + return "Flip " + operatorText + " to " + flippedOperatorText; + } + } + + public String getFamilyName() + { + return "Flip Comparison"; + } + + public PsiElementPredicate getElementPredicate() + { + return new ComparisonPredicate(); + } + + public void invoke(Project project, Editor editor, PsiFile file) throws IncorrectOperationException + { + final PsiBinaryExpression exp = (PsiBinaryExpression) findMatchingElement(file, editor); + final PsiExpression lhs = exp.getLOperand(); + final PsiExpression rhs = exp.getROperand(); + final PsiJavaToken sign = exp.getOperationSign(); + final String operand = sign.getText(); + final String expString = rhs.getText() + ComparisonUtils.getFlippedComparison(operand) + lhs.getText(); + replaceExpression(project, expString, exp); + } +} diff --git a/plugins/IntentionPowerPak/src/com/siyeh/ipp/bool/FlipConjunctionIntention.java b/plugins/IntentionPowerPak/src/com/siyeh/ipp/bool/FlipConjunctionIntention.java new file mode 100644 index 000000000000..e0afb708116f --- /dev/null +++ b/plugins/IntentionPowerPak/src/com/siyeh/ipp/bool/FlipConjunctionIntention.java @@ -0,0 +1,87 @@ +package com.siyeh.ipp.bool; + +import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.project.Project; +import com.intellij.psi.*; +import com.intellij.psi.tree.IElementType; +import com.intellij.util.IncorrectOperationException; +import com.siyeh.ipp.*; + +public class FlipConjunctionIntention extends MutablyNamedIntention +{ + public FlipConjunctionIntention(Project project) + { + super(project); + } + + protected String getTextForElement(PsiElement element) + { + final PsiBinaryExpression binaryExpression = (PsiBinaryExpression) element; + final PsiJavaToken sign = binaryExpression.getOperationSign(); + return "Flip " + sign.getText(); + } + + public String getFamilyName() + { + return "Flip Conjunction Operands"; + } + + public PsiElementPredicate getElementPredicate() + { + return new ConjunctionPredicate(); + } + + public void invoke(Project project, Editor editor, PsiFile file) throws IncorrectOperationException + { + PsiExpression exp = (PsiExpression) findMatchingElement(file, editor); + final PsiBinaryExpression binaryExpression = (PsiBinaryExpression) exp; + final PsiJavaToken sign = binaryExpression.getOperationSign(); + final IElementType conjunctionType = sign.getTokenType(); + PsiElement parent = exp.getParent(); + while(isConjunctionExpression(parent, conjunctionType)) + { + exp = (PsiExpression) parent; + parent = exp.getParent(); + } + final String newExpression = flipExpression(exp, conjunctionType); + replaceExpression(project, newExpression, exp); + } + + private String flipExpression(PsiExpression exp, IElementType conjunctionType) + { + if(isConjunctionExpression(exp, conjunctionType)) + { + final PsiBinaryExpression andExpression = (PsiBinaryExpression) exp; + + final PsiExpression rhs = andExpression.getROperand(); + final PsiExpression lhs = andExpression.getLOperand(); + final String conjunctionSign; + if(conjunctionType.equals(JavaTokenType.ANDAND)) + { + conjunctionSign = "&&"; + } + else + { + conjunctionSign = "||"; + + } + return flipExpression(rhs, conjunctionType) + ' ' + conjunctionSign + ' ' + flipExpression(lhs, conjunctionType); + } + else + { + return exp.getText(); + } + } + + private static boolean isConjunctionExpression(PsiElement exp, IElementType conjunctionType) + { + if(!(exp instanceof PsiBinaryExpression)) + { + return false; + } + final PsiBinaryExpression binExp = (PsiBinaryExpression) exp; + final PsiJavaToken sign = binExp.getOperationSign(); + final IElementType tokenType = sign.getTokenType(); + return tokenType.equals(conjunctionType); + } +} diff --git a/plugins/IntentionPowerPak/src/com/siyeh/ipp/bool/NegateComparisonIntention.java b/plugins/IntentionPowerPak/src/com/siyeh/ipp/bool/NegateComparisonIntention.java new file mode 100644 index 000000000000..548485a01ed1 --- /dev/null +++ b/plugins/IntentionPowerPak/src/com/siyeh/ipp/bool/NegateComparisonIntention.java @@ -0,0 +1,60 @@ +package com.siyeh.ipp.bool; + +import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.project.Project; +import com.intellij.psi.*; +import com.intellij.util.IncorrectOperationException; +import com.siyeh.ipp.*; +import com.siyeh.ipp.psiutils.ComparisonUtils; + +public class NegateComparisonIntention extends MutablyNamedIntention +{ + public NegateComparisonIntention(Project project) + { + super(project); + } + + public String getTextForElement(PsiElement element) + { + String operatorText = ""; + String negatedOperatorText = ""; + final PsiBinaryExpression exp = (PsiBinaryExpression) element; + if(exp != null) + { + final PsiJavaToken sign = exp.getOperationSign(); + operatorText = sign.getText(); + negatedOperatorText = ComparisonUtils.getNegatedComparison(operatorText); + } + if(operatorText.equals(negatedOperatorText)) + { + return "Negate " + operatorText; + } + else + { + return "Negate " + operatorText + " to " + negatedOperatorText; + } + } + + public String getFamilyName() + { + return "Negate Comparison"; + } + + public PsiElementPredicate getElementPredicate() + { + return new ComparisonPredicate(); + } + + public void invoke(Project project, Editor editor, PsiFile file) throws IncorrectOperationException + { + final PsiBinaryExpression exp = (PsiBinaryExpression) findMatchingElement(file, editor); + final PsiExpression lhs = exp.getLOperand(); + final PsiExpression rhs = exp.getROperand(); + final PsiJavaToken sign = exp.getOperationSign(); + final String operator = sign.getText(); + final String negatedOperator = ComparisonUtils.getNegatedComparison(operator); + replaceExpressionWithNegatedExpressionString(project, + lhs.getText() + negatedOperator + rhs.getText(), exp); + + } +} diff --git a/plugins/IntentionPowerPak/src/com/siyeh/ipp/bool/RemoveBooleanEqualityIntention.java b/plugins/IntentionPowerPak/src/com/siyeh/ipp/bool/RemoveBooleanEqualityIntention.java new file mode 100644 index 000000000000..75825527af2f --- /dev/null +++ b/plugins/IntentionPowerPak/src/com/siyeh/ipp/bool/RemoveBooleanEqualityIntention.java @@ -0,0 +1,89 @@ +package com.siyeh.ipp.bool; + +import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.project.Project; +import com.intellij.psi.*; +import com.intellij.util.IncorrectOperationException; +import com.siyeh.ipp.*; + +public class RemoveBooleanEqualityIntention extends MutablyNamedIntention +{ + public RemoveBooleanEqualityIntention(Project project) + { + super(project); + } + + protected String getTextForElement(PsiElement element) + { + final PsiBinaryExpression binaryExpression = (PsiBinaryExpression) element; + final PsiJavaToken sign = binaryExpression.getOperationSign(); + return "Simplify " + sign.getText(); + } + + public String getFamilyName() + { + return "Remove Boolean Equality"; + } + + public PsiElementPredicate getElementPredicate() + { + return new BooleanLiteralEqualityPredicate(); + } + + public void invoke(Project project, Editor editor, PsiFile file) throws IncorrectOperationException + { + final PsiBinaryExpression exp = + (PsiBinaryExpression) findMatchingElement(file, editor); + final PsiJavaToken sign = exp.getOperationSign(); + final boolean isEquals = sign.getTokenType() == JavaTokenType.EQEQ; + final PsiExpression lhs = exp.getLOperand(); + final String lhsText = lhs.getText(); + final PsiExpression rhs = exp.getROperand(); + final String rhsText = rhs.getText(); + if("true".equals(lhsText)) + { + if(isEquals) + { + replaceExpression(project, rhsText, exp); + } + else + { + replaceExpressionWithNegatedExpression(project, rhs, exp); + } + } + else if("false".equals(lhsText)) + { + if(isEquals) + { + replaceExpressionWithNegatedExpression(project, rhs, exp); + } + else + { + replaceExpression(project, rhsText, exp); + } + } + else if("true".equals(rhsText)) + { + if(isEquals) + { + replaceExpression(project, lhsText, exp); + } + else + { + replaceExpressionWithNegatedExpression(project, lhs, exp); + } + } + else + { + if(isEquals) + { + replaceExpressionWithNegatedExpression(project, lhs, exp); + } + else + { + replaceExpression(project, lhsText, exp); + } + } + + } +} diff --git a/plugins/IntentionPowerPak/src/com/siyeh/ipp/commutative/FlipCommutativeMethodCallIntention.java b/plugins/IntentionPowerPak/src/com/siyeh/ipp/commutative/FlipCommutativeMethodCallIntention.java new file mode 100644 index 000000000000..86b74ad6a95e --- /dev/null +++ b/plugins/IntentionPowerPak/src/com/siyeh/ipp/commutative/FlipCommutativeMethodCallIntention.java @@ -0,0 +1,58 @@ +package com.siyeh.ipp.commutative; + +import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.project.Project; +import com.intellij.psi.*; +import com.intellij.util.IncorrectOperationException; +import com.siyeh.ipp.*; +import com.siyeh.ipp.psiutils.ParenthesesUtils; + +public class FlipCommutativeMethodCallIntention extends MutablyNamedIntention +{ + public FlipCommutativeMethodCallIntention(Project project) + { + super(project); + } + + protected String getTextForElement(PsiElement element) + { + final PsiMethodCallExpression call = (PsiMethodCallExpression) element; + final PsiReferenceExpression methodExpression = call.getMethodExpression(); + final String methodName = methodExpression.getReferenceName(); + return "Flip ." + methodName + "()"; + } + + public String getFamilyName() + { + return "Flip Commutative Method Call"; + } + + public PsiElementPredicate getElementPredicate() + { + return new FlipCommutativeMethodCallPredicate(); + } + + public void invoke(Project project, Editor editor, PsiFile file) throws IncorrectOperationException + { + final PsiMethodCallExpression call = (PsiMethodCallExpression) findMatchingElement(file, editor); + final PsiReferenceExpression methodExpression = call.getMethodExpression(); + final String methodName = methodExpression.getReferenceName(); + final PsiExpression target = methodExpression.getQualifierExpression(); + final PsiExpressionList argumentList = call.getArgumentList(); + final PsiExpression arg = argumentList.getExpressions()[0]; + final PsiExpression strippedTarget = ParenthesesUtils.stripParentheses(target); + final PsiExpression strippedArg = ParenthesesUtils.stripParentheses(arg); + final String callString; + if(ParenthesesUtils.getPrecendence(strippedArg) > + ParenthesesUtils.METHOD_CALL_PRECEDENCE) + { + callString = '(' + strippedArg.getText() + ")." + methodName + '(' + strippedTarget.getText() + ')'; + } + else + { + callString = strippedArg.getText() + '.' + methodName + '(' + strippedTarget.getText() + ')'; + } + replaceExpression(project, callString, call); + + } +} diff --git a/plugins/IntentionPowerPak/src/com/siyeh/ipp/commutative/FlipCommutativeMethodCallPredicate.java b/plugins/IntentionPowerPak/src/com/siyeh/ipp/commutative/FlipCommutativeMethodCallPredicate.java new file mode 100644 index 000000000000..bcd64b1af7af --- /dev/null +++ b/plugins/IntentionPowerPak/src/com/siyeh/ipp/commutative/FlipCommutativeMethodCallPredicate.java @@ -0,0 +1,71 @@ +package com.siyeh.ipp.commutative; + +import com.intellij.psi.*; +import com.siyeh.ipp.PsiElementPredicate; + +class FlipCommutativeMethodCallPredicate implements PsiElementPredicate { + public boolean satisfiedBy(PsiElement element) { + if (!(element instanceof PsiMethodCallExpression)) { + return false; + } + final PsiMethodCallExpression expression = (PsiMethodCallExpression) element; + + if (expression.getArgumentList() == null) { + return false; + } + + // do it only when there is just one argument. + final PsiExpressionList argumentList = expression.getArgumentList(); + final PsiExpression[] args = argumentList.getExpressions(); + if (args.length != 1) { + return false; + } + + final PsiReferenceExpression methodExpression = expression.getMethodExpression(); + final PsiExpression qualifier = methodExpression.getQualifierExpression(); + // make sure that there is a caller and a caller + if (qualifier == null) { + return false; + } + + final String methodName = methodExpression.getReferenceName(); + // the logic is... + // if the argument takes a method of the same name with the caller as parameter + // then we can switch the argument and the caller. + + final PsiType callerType = qualifier.getType(); + final PsiType argumentType = args[0].getType(); + + if (argumentType == null || !(argumentType instanceof PsiClassType)) { + return false; + } + + if (callerType == null || !(callerType instanceof PsiClassType)) { + return false; + } + + final PsiClass argumentClass = ((PsiClassType) argumentType).resolve(); + if (argumentClass == null) { + return false; + } + final PsiMethod[] methods = argumentClass.findMethodsByName(methodName, true); + for (int i = 0; i < methods.length; i++) { + final PsiMethod testMethod = methods[i]; + + final String testMethodName = testMethod.getName(); + if (testMethodName.equals(methodName)) { + final PsiParameterList parameterList = testMethod.getParameterList(); + final PsiParameter[] parameters = parameterList.getParameters(); + if (parameters.length == 1) { + final PsiParameter parameter = parameters[0]; + final PsiType type = parameter.getType(); + if (!(type == null || !type.isAssignableFrom(callerType))) { + return true; + } + } + } + } + return false; + } + +} diff --git a/plugins/IntentionPowerPak/src/com/siyeh/ipp/concatenation/ConcatenationUtils.java b/plugins/IntentionPowerPak/src/com/siyeh/ipp/concatenation/ConcatenationUtils.java new file mode 100644 index 000000000000..cf28bf39253a --- /dev/null +++ b/plugins/IntentionPowerPak/src/com/siyeh/ipp/concatenation/ConcatenationUtils.java @@ -0,0 +1,52 @@ +package com.siyeh.ipp.concatenation; + +import com.intellij.psi.*; +import com.intellij.psi.tree.IElementType; + +class ConcatenationUtils +{ + private ConcatenationUtils() + { + super(); + } + + public static boolean isConcatenation(PsiElement element) + { + if(!(element instanceof PsiBinaryExpression)) + { + return false; + } + final PsiBinaryExpression expression = (PsiBinaryExpression) element; + final PsiJavaToken sign = expression.getOperationSign(); + if(sign == null) + { + return false; + } + final IElementType tokenType = sign.getTokenType(); + if(!tokenType.equals(JavaTokenType.PLUS)) + { + return false; + } + final PsiExpression lhs = expression.getLOperand(); + if(lhs == null) + { + return false; + } + final PsiType lhsType = lhs.getType(); + if(lhsType == null) + { + return false; + } + final PsiExpression rhs = expression.getROperand(); + if(rhs == null) + { + return false; + } + final String typeName = lhsType.getCanonicalText(); + if(!"java.lang.String".equals(typeName)) + { + return false; + } + return true; + } +} diff --git a/plugins/IntentionPowerPak/src/com/siyeh/ipp/concatenation/JoinConcatenatedStringLiteralsIntention.java b/plugins/IntentionPowerPak/src/com/siyeh/ipp/concatenation/JoinConcatenatedStringLiteralsIntention.java new file mode 100644 index 000000000000..edcb5fb6bbe5 --- /dev/null +++ b/plugins/IntentionPowerPak/src/com/siyeh/ipp/concatenation/JoinConcatenatedStringLiteralsIntention.java @@ -0,0 +1,63 @@ +package com.siyeh.ipp.concatenation; + +import com.siyeh.ipp.Intention; +import com.siyeh.ipp.PsiElementPredicate; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.editor.Editor; +import com.intellij.psi.*; +import com.intellij.util.IncorrectOperationException; + +public class JoinConcatenatedStringLiteralsIntention extends Intention { + public JoinConcatenatedStringLiteralsIntention(Project project) { + super(project); + } + + protected PsiElementPredicate getElementPredicate() { + return new StringConcatPredicate(); + } + + public String getText() { + return "Join concatenated string literals"; + } + + public String getFamilyName() { + return "Join Concatenated String Literals"; + } + + public void invoke(Project project, Editor editor, PsiFile file) + throws IncorrectOperationException { + final PsiElement element = findMatchingElement(file, editor); + final PsiBinaryExpression binaryExpression = (PsiBinaryExpression) element.getParent(); + final PsiExpression lOperand = binaryExpression.getLOperand(); + final PsiLiteralExpression leftLiteral = getLeftLiteralOperand(lOperand); + final PsiLiteralExpression rightLiteral = (PsiLiteralExpression) binaryExpression.getROperand(); + final String leftText; + if (leftLiteral.getText().charAt(0) == '"') { + leftText = leftLiteral.getText().substring(0, leftLiteral.getTextLength() - 1); + } else { + leftText = '"' + leftLiteral.getText(); + } + final String rightText; + if (rightLiteral.getText().charAt(0) == '"') { + rightText = rightLiteral.getText().substring(1); + } else { + rightText = rightLiteral.getText() + '"'; + } + final String newExpression; + if (lOperand instanceof PsiBinaryExpression) { + final PsiBinaryExpression lBinaryExpression = (PsiBinaryExpression) lOperand; + newExpression = lBinaryExpression.getLOperand().getText() + " + " + leftText + rightText; + } else { + newExpression = leftText + rightText; + } + replaceExpression(project, newExpression, binaryExpression); + } + + private PsiLiteralExpression getLeftLiteralOperand(PsiExpression expression) { + if (expression instanceof PsiBinaryExpression) { + final PsiBinaryExpression binaryExpression = (PsiBinaryExpression) expression; + return getLeftLiteralOperand(binaryExpression.getROperand()); + } + return (PsiLiteralExpression) expression; + } +} diff --git a/plugins/IntentionPowerPak/src/com/siyeh/ipp/concatenation/ReplaceConcatenationWithStringBufferIntention.java b/plugins/IntentionPowerPak/src/com/siyeh/ipp/concatenation/ReplaceConcatenationWithStringBufferIntention.java new file mode 100644 index 000000000000..90a6e714d0ea --- /dev/null +++ b/plugins/IntentionPowerPak/src/com/siyeh/ipp/concatenation/ReplaceConcatenationWithStringBufferIntention.java @@ -0,0 +1,108 @@ +package com.siyeh.ipp.concatenation; + +import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.project.Project; +import com.intellij.psi.*; +import com.intellij.util.IncorrectOperationException; +import com.siyeh.ipp.*; +import com.siyeh.ipp.psiutils.ParenthesesUtils; + +public class ReplaceConcatenationWithStringBufferIntention extends Intention +{ + public ReplaceConcatenationWithStringBufferIntention(Project project) + { + super(project); + } + + public String getText() + { + return "Replace + with .append()"; + } + + public String getFamilyName() + { + return "Replace + with StringBuffer.append()"; + } + + public PsiElementPredicate getElementPredicate() + { + return new ReplaceConcatenationWithStringBufferPredicate(); + } + + public void invoke(Project project, Editor editor, PsiFile file) throws IncorrectOperationException + { + PsiBinaryExpression exp = + (PsiBinaryExpression) findMatchingElement(file, editor); + PsiElement parent = exp.getParent(); + while(ConcatenationUtils.isConcatenation(parent)) + { + exp = (PsiBinaryExpression) parent; + parent = exp.getParent(); + } + final String text = exp.getText(); + final StringBuffer expString = new StringBuffer(text.length() * 3); + if (isPartOfStringBufferAppend(exp)) { + final PsiMethodCallExpression methodCallExpression = + (PsiMethodCallExpression)parent.getParent(); + final PsiExpression qualifierExpression = + methodCallExpression.getMethodExpression().getQualifierExpression(); + final String qualifierText = qualifierExpression.getText(); + expString.append(qualifierText); + turnExpressionIntoChainedAppends(exp, expString); + final String newExpression = expString.toString(); + replaceExpression(project, newExpression, methodCallExpression); + } else { + expString.append("new StringBuffer()"); + turnExpressionIntoChainedAppends(exp, expString); + expString.append(".toString()"); + final String newExpression = expString.toString(); + replaceExpression(project, newExpression, exp); + } + } + + private static boolean isPartOfStringBufferAppend(PsiExpression exp) + { + PsiElement parent = exp.getParent(); + if (!(parent instanceof PsiExpressionList)) + { + return false; + } + parent = parent.getParent(); + if (!(parent instanceof PsiMethodCallExpression)) + { + return false; + } + final PsiMethodCallExpression methodCall = (PsiMethodCallExpression)parent; + final PsiReferenceExpression methodExpression = methodCall.getMethodExpression(); + final PsiType type = methodExpression.getType(); + final String className = type.getCanonicalText(); + if (!"java.lang.StringBuffer".equals(className) && + !"java.lang.StringBuilder".equals(className)) + { + return false; + } + final String methodName = methodExpression.getReferenceName(); + if (!"append".equals(methodName)) + { + return false; + } + return true; + } + + private static void turnExpressionIntoChainedAppends(PsiExpression exp, StringBuffer expString) + { + if(ConcatenationUtils.isConcatenation(exp)) + { + final PsiBinaryExpression concat = (PsiBinaryExpression) exp; + final PsiExpression lhs = concat.getLOperand(); + turnExpressionIntoChainedAppends(lhs, expString); + final PsiExpression rhs = concat.getROperand(); + turnExpressionIntoChainedAppends(rhs, expString); + } + else + { + final PsiExpression strippedExpression = ParenthesesUtils.stripParentheses(exp); + expString.append(".append(" + strippedExpression.getText() + ')'); + } + } +} diff --git a/plugins/IntentionPowerPak/src/com/siyeh/ipp/concatenation/ReplaceConcatenationWithStringBufferPredicate.java b/plugins/IntentionPowerPak/src/com/siyeh/ipp/concatenation/ReplaceConcatenationWithStringBufferPredicate.java new file mode 100644 index 000000000000..17ae48b121ea --- /dev/null +++ b/plugins/IntentionPowerPak/src/com/siyeh/ipp/concatenation/ReplaceConcatenationWithStringBufferPredicate.java @@ -0,0 +1,13 @@ +package com.siyeh.ipp.concatenation; + +import com.intellij.psi.PsiElement; +import com.siyeh.ipp.PsiElementPredicate; + +class ReplaceConcatenationWithStringBufferPredicate implements PsiElementPredicate +{ + public boolean satisfiedBy(PsiElement element) + { + return ConcatenationUtils.isConcatenation(element); + } + +} diff --git a/plugins/IntentionPowerPak/src/com/siyeh/ipp/concatenation/StringConcatPredicate.java b/plugins/IntentionPowerPak/src/com/siyeh/ipp/concatenation/StringConcatPredicate.java new file mode 100644 index 000000000000..2ff7e9b0b3ce --- /dev/null +++ b/plugins/IntentionPowerPak/src/com/siyeh/ipp/concatenation/StringConcatPredicate.java @@ -0,0 +1,50 @@ +package com.siyeh.ipp.concatenation; + +import com.intellij.psi.*; +import com.intellij.psi.tree.IElementType; +import com.siyeh.ipp.PsiElementPredicate; + +class StringConcatPredicate implements PsiElementPredicate { + public boolean satisfiedBy(PsiElement element) { + if (element instanceof PsiJavaToken) { + final PsiJavaToken token = (PsiJavaToken) element; + final IElementType tokenType = token.getTokenType(); + if (!tokenType.equals(JavaTokenType.PLUS)) { + return false; + } + } else if (!(element instanceof PsiWhiteSpace)) { + return false; + } + final PsiElement parent = element.getParent(); + if (!(parent instanceof PsiBinaryExpression)) { + return false; + } + final PsiBinaryExpression binaryExpression = (PsiBinaryExpression) parent; + final PsiJavaToken sign = binaryExpression.getOperationSign(); + if (sign == null) { + return false; + } + final IElementType tokenType = sign.getTokenType(); + if (!tokenType.equals(JavaTokenType.PLUS)) { + return false; + } + final PsiExpression rOperand = binaryExpression.getROperand(); + if (!(rOperand instanceof PsiLiteralExpression)) { + return false; + } + final PsiExpression lhs = binaryExpression.getLOperand(); + if (!isLeftSideLiteral(lhs)) { + return false; + } + return true; + } + + private boolean isLeftSideLiteral(PsiExpression expression) { + if (expression instanceof PsiBinaryExpression) { + final PsiBinaryExpression binaryExpression = (PsiBinaryExpression) expression; + final PsiExpression rhs = binaryExpression.getROperand(); + return isLeftSideLiteral(rhs); + } + return expression instanceof PsiLiteralExpression; + } +} diff --git a/plugins/IntentionPowerPak/src/com/siyeh/ipp/conditional/FlipConditionalIntention.java b/plugins/IntentionPowerPak/src/com/siyeh/ipp/conditional/FlipConditionalIntention.java new file mode 100644 index 000000000000..73eea06c993c --- /dev/null +++ b/plugins/IntentionPowerPak/src/com/siyeh/ipp/conditional/FlipConditionalIntention.java @@ -0,0 +1,47 @@ +package com.siyeh.ipp.conditional; + +import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.project.Project; +import com.intellij.psi.*; +import com.intellij.util.IncorrectOperationException; +import com.siyeh.ipp.*; +import com.siyeh.ipp.psiutils.BoolUtils; + +public class FlipConditionalIntention extends Intention +{ + public FlipConditionalIntention(Project project) + { + super(project); + } + + public String getText() + { + return "Flip ?:"; + } + + public String getFamilyName() + { + return "Flip Conditional"; + } + + + public PsiElementPredicate getElementPredicate() + { + return new FlipConditionalPredicate(); + } + + public void invoke(Project project, Editor editor, PsiFile file) throws IncorrectOperationException + { + final PsiConditionalExpression exp = (PsiConditionalExpression) findMatchingElement(file, editor); + + final PsiExpression condition = exp.getCondition(); + final PsiExpression elseExpression = exp.getElseExpression(); + final PsiExpression thenExpression = exp.getThenExpression(); + final String newExpression = BoolUtils.getNegatedExpressionText(condition) + '?' + + elseExpression.getText() + + ':' + + thenExpression.getText(); + replaceExpression(project, newExpression, exp); + } + +} diff --git a/plugins/IntentionPowerPak/src/com/siyeh/ipp/conditional/FlipConditionalPredicate.java b/plugins/IntentionPowerPak/src/com/siyeh/ipp/conditional/FlipConditionalPredicate.java new file mode 100644 index 000000000000..0643963daaf7 --- /dev/null +++ b/plugins/IntentionPowerPak/src/com/siyeh/ipp/conditional/FlipConditionalPredicate.java @@ -0,0 +1,22 @@ +package com.siyeh.ipp.conditional; + +import com.intellij.psi.PsiConditionalExpression; +import com.intellij.psi.PsiElement; +import com.siyeh.ipp.PsiElementPredicate; + +class FlipConditionalPredicate implements PsiElementPredicate +{ + public boolean satisfiedBy(PsiElement element) + { + if(!(element instanceof PsiConditionalExpression)) + { + return false; + } + final PsiConditionalExpression condition = (PsiConditionalExpression) element; + + return condition.getCondition() != null && + condition.getThenExpression() != null && + condition.getElseExpression() != null; + + } +} diff --git a/plugins/IntentionPowerPak/src/com/siyeh/ipp/conditional/RemoveConditionalIntention.java b/plugins/IntentionPowerPak/src/com/siyeh/ipp/conditional/RemoveConditionalIntention.java new file mode 100644 index 000000000000..271988722a1c --- /dev/null +++ b/plugins/IntentionPowerPak/src/com/siyeh/ipp/conditional/RemoveConditionalIntention.java @@ -0,0 +1,53 @@ +package com.siyeh.ipp.conditional; + +import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.project.Project; +import com.intellij.psi.PsiConditionalExpression; +import com.intellij.psi.PsiExpression; +import com.intellij.psi.PsiFile; +import com.intellij.util.IncorrectOperationException; +import com.siyeh.ipp.Intention; +import com.siyeh.ipp.PsiElementPredicate; +import com.siyeh.ipp.psiutils.BoolUtils; + +public class RemoveConditionalIntention extends Intention +{ + public RemoveConditionalIntention(Project project) + { + super(project); + } + + public String getText() + { + return "Simplify ?:"; + } + + public String getFamilyName() + { + return "Remove Pointless Conditional"; + } + + public PsiElementPredicate getElementPredicate() + { + return new RemoveConditionalPredicate(); + } + + public void invoke(Project project, Editor editor, PsiFile file) throws IncorrectOperationException + { + final PsiConditionalExpression exp = (PsiConditionalExpression) findMatchingElement(file, editor); + final PsiExpression condition = exp.getCondition(); + final PsiExpression thenExpression = exp.getThenExpression(); + final String thenExpressionText = thenExpression.getText(); + if("true".equals(thenExpressionText)) + { + final String newExpression = condition.getText(); + replaceExpression(project, newExpression, exp); + } + else + { + final String newExpression = BoolUtils.getNegatedExpressionText(condition); + replaceExpression(project, newExpression, exp); + } + } + +} diff --git a/plugins/IntentionPowerPak/src/com/siyeh/ipp/conditional/RemoveConditionalPredicate.java b/plugins/IntentionPowerPak/src/com/siyeh/ipp/conditional/RemoveConditionalPredicate.java new file mode 100644 index 000000000000..41152f0f3e18 --- /dev/null +++ b/plugins/IntentionPowerPak/src/com/siyeh/ipp/conditional/RemoveConditionalPredicate.java @@ -0,0 +1,38 @@ +package com.siyeh.ipp.conditional; + +import com.intellij.psi.*; +import com.siyeh.ipp.PsiElementPredicate; +import com.siyeh.ipp.psiutils.ParenthesesUtils; + +class RemoveConditionalPredicate implements PsiElementPredicate { + public boolean satisfiedBy(PsiElement element) { + if (!(element instanceof PsiConditionalExpression)) { + return false; + } + final PsiConditionalExpression condition = (PsiConditionalExpression) element; + + PsiExpression thenExpression = condition.getThenExpression(); + PsiExpression elseExpression = condition.getElseExpression(); + if (condition.getCondition() == null || + thenExpression == null || + elseExpression == null) { + return false; + } + + thenExpression = ParenthesesUtils.stripParentheses(thenExpression); + elseExpression = ParenthesesUtils.stripParentheses(elseExpression); + if (thenExpression == null || + elseExpression == null) { + return false; + } + final String thenText = thenExpression.getText(); + final String elseText = elseExpression.getText(); + if ("true".equals(elseText) && "false".equals(thenText)) { + return true; + } else if ("true".equals(thenText) && "false".equals(elseText)) { + return true; + } + return false; + + } +} diff --git a/plugins/IntentionPowerPak/src/com/siyeh/ipp/conditional/ReplaceConditionalWithIfIntention.java b/plugins/IntentionPowerPak/src/com/siyeh/ipp/conditional/ReplaceConditionalWithIfIntention.java new file mode 100644 index 000000000000..8af384728bdc --- /dev/null +++ b/plugins/IntentionPowerPak/src/com/siyeh/ipp/conditional/ReplaceConditionalWithIfIntention.java @@ -0,0 +1,102 @@ +package com.siyeh.ipp.conditional; + +import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.project.Project; +import com.intellij.psi.*; +import com.intellij.psi.codeStyle.CodeStyleManager; +import com.intellij.util.IncorrectOperationException; +import com.siyeh.ipp.*; + +public class ReplaceConditionalWithIfIntention extends Intention { + public ReplaceConditionalWithIfIntention(Project project) { + super(project); + } + + public String getText() { + return "Replace ?: with if-else"; + } + + public String getFamilyName() { + return "Replace Conditional With If Else"; + } + + public PsiElementPredicate getElementPredicate() { + return new ReplaceConditionalWithIfPredicate(); + } + + public void invoke(Project project, Editor editor, PsiFile file) throws IncorrectOperationException { + final PsiElement element = findMatchingElement(file, editor); + if (element instanceof PsiReturnStatement) { + final PsiReturnStatement returnStatement = (PsiReturnStatement) element; + final PsiConditionalExpression returnValue = + (PsiConditionalExpression) returnStatement.getReturnValue(); + final PsiExpression condition = returnValue.getCondition(); + final PsiExpression thenExpression = returnValue.getThenExpression(); + final PsiExpression elseExpression = returnValue.getElseExpression(); + final String ifStatementString = "if(" + condition.getText() + ')' + + '{' + + "return " + thenExpression.getText() + ';' + + '}' + + "else" + + '{' + + "return " + elseExpression.getText() + ';' + + '}'; + replaceStatement(project, ifStatementString, returnStatement); + } + else if (element instanceof PsiDeclarationStatement) + { + final PsiManager mgr = PsiManager.getInstance(project); + final PsiElementFactory factory = mgr.getElementFactory(); + final PsiDeclarationStatement statement = (PsiDeclarationStatement) findMatchingElement(file, editor); + final PsiVariable var = (PsiVariable) statement.getDeclaredElements()[0]; + final PsiConditionalExpression rhs = (PsiConditionalExpression) var.getInitializer(); + final String lhsText = var.getName(); + final String str = statement.getText(); + final int equalsIndex = str.indexOf((int) '='); + final String declarationString = str.substring(0, equalsIndex) + ';'; + final PsiExpression condition = rhs.getCondition(); + final PsiExpression thenExpression = rhs.getThenExpression(); + final PsiExpression elseExpression = rhs.getElseExpression(); + final String ifStatementString = "if(" + condition.getText() + ')' + + '{' + + lhsText + '=' + thenExpression.getText() + ';' + + '}' + + "else" + + '{' + + lhsText + '=' + elseExpression.getText() + ';' + + '}'; + final PsiStatement declarationStatement = factory.createStatementFromText(declarationString, null); + final PsiStatement ifStatement = factory.createStatementFromText(ifStatementString, null); + PsiElement ifElement = statement.replace(ifStatement); + final CodeStyleManager styleManager = mgr.getCodeStyleManager(); + ifElement = styleManager.reformat(ifElement); + final PsiElement parent = ifElement.getParent(); + final PsiElement declarationElement = parent.addBefore(declarationStatement, ifElement); + styleManager.reformat(declarationElement); + styleManager.reformat(parent); + } + else + { + final PsiExpressionStatement statement = (PsiExpressionStatement) findMatchingElement(file, editor); + final PsiAssignmentExpression assigmentExpression = (PsiAssignmentExpression) statement.getExpression(); + final PsiConditionalExpression rhs = + (PsiConditionalExpression) assigmentExpression.getRExpression(); + final PsiExpression lhs = assigmentExpression.getLExpression(); + final String lhsText = lhs.getText(); + final PsiJavaToken sign = assigmentExpression.getOperationSign(); + final String operator = sign.getText(); + final PsiExpression condition = rhs.getCondition(); + final PsiExpression thenExpression = rhs.getThenExpression(); + final PsiExpression elseExpression = rhs.getElseExpression(); + final String ifStatementString = "if(" + condition.getText() + ')' + + '{' + + lhsText + operator + thenExpression.getText() + ';' + + '}' + + "else" + + '{' + + lhsText + operator + elseExpression.getText() + ';' + + '}'; + replaceStatement(project, ifStatementString, statement); + } + } +} diff --git a/plugins/IntentionPowerPak/src/com/siyeh/ipp/conditional/ReplaceConditionalWithIfPredicate.java b/plugins/IntentionPowerPak/src/com/siyeh/ipp/conditional/ReplaceConditionalWithIfPredicate.java new file mode 100644 index 000000000000..ba69ddf74378 --- /dev/null +++ b/plugins/IntentionPowerPak/src/com/siyeh/ipp/conditional/ReplaceConditionalWithIfPredicate.java @@ -0,0 +1,86 @@ +package com.siyeh.ipp.conditional; + +import com.intellij.psi.*; +import com.siyeh.ipp.PsiElementPredicate; + +class ReplaceConditionalWithIfPredicate implements PsiElementPredicate { + public boolean satisfiedBy(PsiElement element) { + if (element instanceof PsiReturnStatement) { + return isReturnOfConditional((PsiReturnStatement) element); + + } + if (element instanceof PsiExpressionStatement) { + return isAssignmentToConditional((PsiExpressionStatement) element); + + } + if (element instanceof PsiDeclarationStatement) { + return isDeclarationOfConditional((PsiDeclarationStatement) element); + } else { + return false; + } + } + + private static boolean isDeclarationOfConditional(PsiDeclarationStatement declStatement) { + final PsiElement[] variables = declStatement.getDeclaredElements(); + if (variables.length != 1) { + return false; + } + if (!(variables[0] instanceof PsiLocalVariable)) { + return false; + } + final PsiLocalVariable var = (PsiLocalVariable) variables[0]; + final PsiExpression initializer = var.getInitializer(); + if (initializer == null) { + return false; + } + if (!(initializer instanceof PsiConditionalExpression)) { + return false; + } + final PsiConditionalExpression condition = (PsiConditionalExpression) initializer; + + if (condition.getCondition() == null || + condition.getThenExpression() == null || + condition.getElseExpression() == null) { + return false; + } + return true; + } + + private static boolean isAssignmentToConditional(PsiExpressionStatement expressionStatement) { + if (!(expressionStatement.getExpression() instanceof PsiAssignmentExpression)) { + return false; + } + final PsiAssignmentExpression assignmentExpression = (PsiAssignmentExpression) expressionStatement.getExpression(); + final PsiExpression lhs = assignmentExpression.getLExpression(); + final PsiExpression rhs = assignmentExpression.getRExpression(); + if (lhs == null || rhs == null) { + return false; + } + if (!(rhs instanceof PsiConditionalExpression)) { + return false; + } + final PsiConditionalExpression condition = (PsiConditionalExpression) rhs; + + if (condition.getCondition() == null || + condition.getThenExpression() == null || + condition.getElseExpression() == null) { + return false; + } + return true; + } + + private static boolean isReturnOfConditional(PsiReturnStatement returnStatement) { + final PsiExpression returnValue = returnStatement.getReturnValue(); + if (returnValue == null) { + return false; + } + if (!(returnValue instanceof PsiConditionalExpression)) { + return false; + } + final PsiConditionalExpression condition = (PsiConditionalExpression) returnValue; + + return condition.getCondition() != null && + condition.getThenExpression() != null && + condition.getElseExpression() != null; + } +} diff --git a/plugins/IntentionPowerPak/src/com/siyeh/ipp/decls/SimplifyVariableIntention.java b/plugins/IntentionPowerPak/src/com/siyeh/ipp/decls/SimplifyVariableIntention.java new file mode 100644 index 000000000000..41b92e93a5d0 --- /dev/null +++ b/plugins/IntentionPowerPak/src/com/siyeh/ipp/decls/SimplifyVariableIntention.java @@ -0,0 +1,37 @@ +package com.siyeh.ipp.decls; + +import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.project.Project; +import com.intellij.psi.PsiFile; +import com.intellij.psi.PsiVariable; +import com.intellij.util.IncorrectOperationException; +import com.siyeh.ipp.*; + +public class SimplifyVariableIntention extends Intention +{ + public SimplifyVariableIntention(Project project) + { + super(project); + } + + public String getText() + { + return "Replace with Java-style array declaration"; + } + + public String getFamilyName() + { + return "Replace With Java Style Array Declaration"; + } + + public PsiElementPredicate getElementPredicate() + { + return new SimplifyVariablePredicate(); + } + + public void invoke(Project project, Editor editor, PsiFile file) throws IncorrectOperationException + { + final PsiVariable var = (PsiVariable) findMatchingElement(file, editor); + var.normalizeDeclaration(); + } +} diff --git a/plugins/IntentionPowerPak/src/com/siyeh/ipp/decls/SimplifyVariablePredicate.java b/plugins/IntentionPowerPak/src/com/siyeh/ipp/decls/SimplifyVariablePredicate.java new file mode 100644 index 000000000000..5845e7bf404a --- /dev/null +++ b/plugins/IntentionPowerPak/src/com/siyeh/ipp/decls/SimplifyVariablePredicate.java @@ -0,0 +1,29 @@ +package com.siyeh.ipp.decls; + +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiType; +import com.intellij.psi.PsiTypeElement; +import com.intellij.psi.PsiVariable; +import com.siyeh.ipp.PsiElementPredicate; + +class SimplifyVariablePredicate implements PsiElementPredicate +{ + public boolean satisfiedBy(PsiElement element) + { + if(!(element instanceof PsiVariable)) + { + return false; + } + + final PsiVariable var = (PsiVariable) element; + final PsiTypeElement typeElement = var.getTypeElement(); + if (typeElement == null) + { + return false; // Could be true for enum constants. + } + + final PsiType elementType = typeElement.getType(); + final PsiType type = var.getType(); + return elementType.getArrayDimensions() != type.getArrayDimensions(); + } +} diff --git a/plugins/IntentionPowerPak/src/com/siyeh/ipp/equality/EqualsPredicate.java b/plugins/IntentionPowerPak/src/com/siyeh/ipp/equality/EqualsPredicate.java new file mode 100644 index 000000000000..d2aee5be68dd --- /dev/null +++ b/plugins/IntentionPowerPak/src/com/siyeh/ipp/equality/EqualsPredicate.java @@ -0,0 +1,34 @@ +package com.siyeh.ipp.equality; + +import com.intellij.psi.*; +import com.siyeh.ipp.PsiElementPredicate; + +class EqualsPredicate implements PsiElementPredicate +{ + public boolean satisfiedBy(PsiElement element) + { + if(!(element instanceof PsiMethodCallExpression)) + { + return false; + } + final PsiMethodCallExpression expression = (PsiMethodCallExpression) element; + final PsiExpressionList argumentList = expression.getArgumentList(); + if(argumentList == null) + { + return false; + } + final PsiExpression[] args = argumentList.getExpressions(); + if(args.length != 1) + { + return false; + } + final PsiReferenceExpression methodExpression = expression.getMethodExpression(); + if(methodExpression == null) + { + return false; + } + final String methodName = methodExpression.getReferenceName(); + return "equals".equals(methodName); + } + +} diff --git a/plugins/IntentionPowerPak/src/com/siyeh/ipp/equality/ObjectEqualityPredicate.java b/plugins/IntentionPowerPak/src/com/siyeh/ipp/equality/ObjectEqualityPredicate.java new file mode 100644 index 000000000000..2c5f3a86c135 --- /dev/null +++ b/plugins/IntentionPowerPak/src/com/siyeh/ipp/equality/ObjectEqualityPredicate.java @@ -0,0 +1,53 @@ +package com.siyeh.ipp.equality; + +import com.intellij.psi.*; +import com.intellij.psi.util.TypeConversionUtil; +import com.intellij.psi.tree.IElementType; +import com.siyeh.ipp.PsiElementPredicate; + +class ObjectEqualityPredicate implements PsiElementPredicate +{ + public boolean satisfiedBy(PsiElement element) + { + if (!(element instanceof PsiBinaryExpression)) { + return false; + } + final PsiBinaryExpression expression = (PsiBinaryExpression) element; + final PsiJavaToken sign = expression.getOperationSign(); + final IElementType tokenType = sign.getTokenType(); + if (!tokenType.equals(JavaTokenType.NE) && + !tokenType.equals(JavaTokenType.EQEQ)) { + return false; + } + final PsiExpression lhs = expression.getLOperand(); + if (lhs == null) { + return false; + } + final PsiType lhsType = lhs.getType(); + if (lhsType == null) { + return false; + } + final PsiExpression rhs = expression.getROperand(); + if (rhs == null) { + return false; + } + final PsiType rhsType = rhs.getType(); + if (rhsType == null) { + return false; + } + return !TypeConversionUtil.isPrimitiveAndNotNull(lhsType) && + !TypeConversionUtil.isPrimitiveAndNotNull(rhsType); + } + + private static boolean isPrimitive(final PsiType lhsType) + { + return lhsType.equals(PsiType.INT) + || lhsType.equals(PsiType.SHORT) + || lhsType.equals(PsiType.LONG) + || lhsType.equals(PsiType.DOUBLE) + || lhsType.equals(PsiType.FLOAT) + || lhsType.equals(PsiType.CHAR) + || lhsType.equals(PsiType.BOOLEAN) + || lhsType.equals(PsiType.BYTE); + } +} diff --git a/plugins/IntentionPowerPak/src/com/siyeh/ipp/equality/ReplaceEqualityWithEqualsIntention.java b/plugins/IntentionPowerPak/src/com/siyeh/ipp/equality/ReplaceEqualityWithEqualsIntention.java new file mode 100644 index 000000000000..e90acdbfbca7 --- /dev/null +++ b/plugins/IntentionPowerPak/src/com/siyeh/ipp/equality/ReplaceEqualityWithEqualsIntention.java @@ -0,0 +1,52 @@ +package com.siyeh.ipp.equality; + +import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.project.Project; +import com.intellij.psi.*; +import com.intellij.psi.tree.IElementType; +import com.intellij.util.IncorrectOperationException; +import com.siyeh.ipp.*; +import com.siyeh.ipp.psiutils.ParenthesesUtils; + +public class ReplaceEqualityWithEqualsIntention extends Intention { + public ReplaceEqualityWithEqualsIntention(Project project) { + super(project); + } + + public String getText() { + return "Replace == with .equals()"; + } + + public String getFamilyName() { + return "Replace Equality With Equals"; + } + + public PsiElementPredicate getElementPredicate() { + return new ObjectEqualityPredicate(); + } + + public void invoke(Project project, Editor editor, PsiFile file) throws IncorrectOperationException { + final PsiBinaryExpression exp = (PsiBinaryExpression) findMatchingElement(file, editor); + final PsiExpression lhs = exp.getLOperand(); + final PsiExpression rhs = exp.getROperand(); + final PsiExpression strippedLhs = ParenthesesUtils.stripParentheses(lhs); + final PsiExpression strippedRhs = ParenthesesUtils.stripParentheses(rhs); + final PsiJavaToken operationSign = exp.getOperationSign(); + final IElementType tokenType = operationSign.getTokenType(); + final String expString; + if (tokenType.equals(JavaTokenType.EQEQ)) { + if (ParenthesesUtils.getPrecendence(strippedLhs) > ParenthesesUtils.METHOD_CALL_PRECEDENCE) { + expString = '(' + strippedLhs.getText() + ").equals(" + strippedRhs.getText() + ')'; + } else { + expString = strippedLhs.getText() + ".equals(" + strippedRhs.getText() + ')'; + } + } else { + if (ParenthesesUtils.getPrecendence(strippedLhs) > ParenthesesUtils.METHOD_CALL_PRECEDENCE) { + expString = "!(" + strippedLhs.getText() + ").equals(" + strippedRhs.getText() + ')'; + } else { + expString = '!' + strippedLhs.getText() + ".equals(" + strippedRhs.getText() + ')'; + } + } + replaceExpression(project, expString, exp); + } +} diff --git a/plugins/IntentionPowerPak/src/com/siyeh/ipp/equality/ReplaceEqualityWithSafeEqualsIntention.java b/plugins/IntentionPowerPak/src/com/siyeh/ipp/equality/ReplaceEqualityWithSafeEqualsIntention.java new file mode 100644 index 000000000000..ac268a5369af --- /dev/null +++ b/plugins/IntentionPowerPak/src/com/siyeh/ipp/equality/ReplaceEqualityWithSafeEqualsIntention.java @@ -0,0 +1,53 @@ +package com.siyeh.ipp.equality; + +import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.project.Project; +import com.intellij.psi.*; +import com.intellij.util.IncorrectOperationException; +import com.siyeh.ipp.*; +import com.siyeh.ipp.psiutils.ParenthesesUtils; + +public class ReplaceEqualityWithSafeEqualsIntention extends Intention +{ + public ReplaceEqualityWithSafeEqualsIntention(Project project) + { + super(project); + } + + public String getText() + { + return "Replace == with safe .equals()"; + } + + public String getFamilyName() + { + return "Replace Equality With Safe Equals"; + } + + public PsiElementPredicate getElementPredicate() + { + return new ObjectEqualityPredicate(); + } + + public void invoke(Project project, Editor editor, PsiFile file) throws IncorrectOperationException + { + //TODO: create reasonable semantics for this for negated equality + final PsiBinaryExpression exp = (PsiBinaryExpression) findMatchingElement(file, editor); + final PsiExpression lhs = exp.getLOperand(); + final PsiExpression rhs = exp.getROperand(); + final PsiExpression strippedLhs = ParenthesesUtils.stripParentheses(lhs); + final PsiExpression strippedRhs = ParenthesesUtils.stripParentheses(rhs); + final String expString; + final String lhsText = strippedLhs.getText(); + final String rhsText = strippedRhs.getText(); + if(ParenthesesUtils.getPrecendence(strippedLhs) > ParenthesesUtils.METHOD_CALL_PRECEDENCE) + { + expString = lhsText + "==null?" + rhsText + " == null:(" + lhsText + ").equals(" + rhsText + ')'; + } + else + { + expString = lhsText + "==null?" + rhsText + " == null:" + lhsText + ".equals(" + rhsText + ')'; + } + replaceExpression(project, expString, exp); + } +} diff --git a/plugins/IntentionPowerPak/src/com/siyeh/ipp/equality/ReplaceEqualsWithEqualityIntention.java b/plugins/IntentionPowerPak/src/com/siyeh/ipp/equality/ReplaceEqualsWithEqualityIntention.java new file mode 100644 index 000000000000..6b702483fa38 --- /dev/null +++ b/plugins/IntentionPowerPak/src/com/siyeh/ipp/equality/ReplaceEqualsWithEqualityIntention.java @@ -0,0 +1,65 @@ +package com.siyeh.ipp.equality; + +import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.project.Project; +import com.intellij.psi.*; +import com.intellij.util.IncorrectOperationException; +import com.siyeh.ipp.*; +import com.siyeh.ipp.psiutils.ParenthesesUtils; + +public class ReplaceEqualsWithEqualityIntention extends Intention +{ + public ReplaceEqualsWithEqualityIntention(Project project) + { + super(project); + } + + public String getText() + { + return "Replace .equals() with =="; + } + + public String getFamilyName() + { + return "Replace Equals With Equality"; + } + + public PsiElementPredicate getElementPredicate() + { + return new EqualsPredicate(); + } + + public void invoke(Project project, Editor editor, PsiFile file) throws IncorrectOperationException + { + final PsiMethodCallExpression call = (PsiMethodCallExpression) findMatchingElement(file, editor); + final PsiReferenceExpression methodExpression = call.getMethodExpression(); + final PsiExpression target = methodExpression.getQualifierExpression(); + final PsiExpressionList argumentList = call.getArgumentList(); + final PsiExpression arg = argumentList.getExpressions()[0]; + final PsiExpression strippedTarget = ParenthesesUtils.stripParentheses(target); + final PsiExpression strippedArg = ParenthesesUtils.stripParentheses(arg); + + final String strippedArgText; + if(ParenthesesUtils.getPrecendence(strippedArg) > + ParenthesesUtils.EQUALITY_PRECEDENCE) + { + strippedArgText = '(' + strippedArg.getText() + ')'; + } + else + { + strippedArgText = strippedArg.getText(); + } + final String strippedTargetText; + if(ParenthesesUtils.getPrecendence(strippedTarget) > + ParenthesesUtils.EQUALITY_PRECEDENCE) + { + strippedTargetText = '(' + strippedTarget.getText() + ')'; + } + else + { + strippedTargetText = strippedTarget.getText(); + } + + replaceExpression(project, strippedTargetText + "==" + strippedArgText, call); + } +} diff --git a/plugins/IntentionPowerPak/src/com/siyeh/ipp/exceptions/DetailExceptionsIntention.java b/plugins/IntentionPowerPak/src/com/siyeh/ipp/exceptions/DetailExceptionsIntention.java new file mode 100644 index 000000000000..6ec8e28585c8 --- /dev/null +++ b/plugins/IntentionPowerPak/src/com/siyeh/ipp/exceptions/DetailExceptionsIntention.java @@ -0,0 +1,96 @@ +package com.siyeh.ipp.exceptions; + +import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.project.Project; +import com.intellij.psi.*; +import com.intellij.util.IncorrectOperationException; +import com.siyeh.ipp.*; + +import java.util.*; + +public class DetailExceptionsIntention extends Intention +{ + public DetailExceptionsIntention(Project project) + { + super(project); + } + + public String getText() + { + return "Detail exceptions"; + } + + public String getFamilyName() + { + return "Detail Exceptions"; + } + + public PsiElementPredicate getElementPredicate() + { + final Project project = getProject(); + return new DetailExceptionsPredicate(project); + } + + public void invoke(Project project, Editor editor, PsiFile file) throws IncorrectOperationException + { + final PsiJavaToken token = (PsiJavaToken) findMatchingElement(file, editor); + final PsiTryStatement tryStatement = (PsiTryStatement) token.getParent(); + + final String text = tryStatement.getText(); + final int length = text.length(); + final StringBuffer newTryStatement = new StringBuffer(length); + newTryStatement.append("try"); + final PsiCodeBlock tryBlock = tryStatement.getTryBlock(); + final String tryBlockText = tryBlock.getText(); + newTryStatement.append(tryBlockText); + + final Set exceptionsThrown = new HashSet(10); + + final PsiManager mgr = PsiManager.getInstance(project); + final PsiElementFactory factory = mgr.getElementFactory(); + ExceptionUtils.calculateExceptionsThrownForCodeBlock(tryBlock, exceptionsThrown, factory); + + final PsiParameter[] params = tryStatement.getCatchBlockParameters(); + final PsiCodeBlock[] catchBlocks = tryStatement.getCatchBlocks(); + final HeirarchicalTypeComparator comparator = new HeirarchicalTypeComparator(); + + for(int i = 0; i < catchBlocks.length; i++) + { + final PsiParameter param = params[i]; + final PsiCodeBlock block = catchBlocks[i]; + final PsiType caughtType = param.getType(); + final List exceptionsToExpand = new ArrayList(10); + for(Iterator iterator = exceptionsThrown.iterator(); iterator.hasNext();) + { + final PsiType thrownType = (PsiType) iterator.next(); + if(caughtType.isAssignableFrom(thrownType)) + { + exceptionsToExpand.add(thrownType); + } + } + Collections.sort(exceptionsToExpand, comparator); + for(Iterator iterator = exceptionsToExpand.iterator(); iterator.hasNext();) + { + final PsiType thrownType = (PsiType) iterator.next(); + newTryStatement.append("catch("); + final String exceptionType = thrownType.getPresentableText(); + newTryStatement.append(exceptionType); + newTryStatement.append(' '); + final String parameterName = param.getName(); + newTryStatement.append(parameterName); + newTryStatement.append(')'); + final String blockText = block.getText(); + newTryStatement.append(blockText); + } + } + final PsiCodeBlock finallyBlock = tryStatement.getFinallyBlock(); + if(finallyBlock != null) + { + newTryStatement.append("finally"); + final String finallyBlockText = finallyBlock.getText(); + newTryStatement.append(finallyBlockText); + } + final String newStatement = newTryStatement.toString(); + replaceStatement(project, newStatement, tryStatement); + } +} diff --git a/plugins/IntentionPowerPak/src/com/siyeh/ipp/exceptions/DetailExceptionsPredicate.java b/plugins/IntentionPowerPak/src/com/siyeh/ipp/exceptions/DetailExceptionsPredicate.java new file mode 100644 index 000000000000..eb923b3471cc --- /dev/null +++ b/plugins/IntentionPowerPak/src/com/siyeh/ipp/exceptions/DetailExceptionsPredicate.java @@ -0,0 +1,60 @@ +package com.siyeh.ipp.exceptions; + +import com.intellij.openapi.project.Project; +import com.intellij.psi.*; +import com.intellij.psi.tree.IElementType; +import com.siyeh.ipp.PsiElementPredicate; + +import java.util.*; + +class DetailExceptionsPredicate implements PsiElementPredicate +{ + private final Project m_project; + + DetailExceptionsPredicate(Project project) + { + super(); + m_project = project; + } + + public boolean satisfiedBy(PsiElement element) + { + if(!(element instanceof PsiJavaToken)) + { + return false; + } + final IElementType tokenType = ((PsiJavaToken)element).getTokenType(); + if(tokenType!=JavaTokenType.TRY_KEYWORD) + { + return false; + } + if(!(element.getParent() instanceof PsiTryStatement)) + { + return false; + } + final PsiTryStatement tryStatement = (PsiTryStatement) element.getParent(); + final Set exceptionsThrown = new HashSet(10); + final PsiManager mgr = PsiManager.getInstance(m_project); + final PsiElementFactory factory = mgr.getElementFactory(); + final PsiCodeBlock tryBlock = tryStatement.getTryBlock(); + ExceptionUtils.calculateExceptionsThrownForCodeBlock(tryBlock, exceptionsThrown, factory); + final Set exceptionsCaught = ExceptionUtils.getExceptionTypesHandled(tryStatement); + for(Iterator iterator = exceptionsThrown.iterator(); iterator.hasNext();) + { + final PsiType typeThrown = (PsiType) iterator.next(); + if(!exceptionsCaught.contains(typeThrown)) + { + for(Iterator caught = exceptionsCaught.iterator(); caught.hasNext();) + { + final PsiType typeCaught = (PsiType) caught.next(); + if(typeCaught.isAssignableFrom(typeThrown)) + { + return true; + } + } + } + } + return false; + } + +} diff --git a/plugins/IntentionPowerPak/src/com/siyeh/ipp/exceptions/ExceptionUtils.java b/plugins/IntentionPowerPak/src/com/siyeh/ipp/exceptions/ExceptionUtils.java new file mode 100644 index 000000000000..ef27b1a0d325 --- /dev/null +++ b/plugins/IntentionPowerPak/src/com/siyeh/ipp/exceptions/ExceptionUtils.java @@ -0,0 +1,472 @@ +package com.siyeh.ipp.exceptions; + +import com.intellij.psi.*; + +import java.util.*; + +class ExceptionUtils +{ + private ExceptionUtils() + { + super(); + + } + + public static Set getExceptionTypesHandled(PsiTryStatement statement) + { + final Set out = new HashSet(10); + final PsiParameter[] params = statement.getCatchBlockParameters(); + for(int i = 0; i < params.length; i++) + { + final PsiType type = params[i].getType(); + out.add(type); + } + return out; + } + + private static void calculateExceptionsThrownForStatement(PsiStatement statement, Set exceptionTypes, + PsiElementFactory factory) + { + if(statement == null) + { + return; + } + if(statement instanceof PsiBreakStatement || + statement instanceof PsiContinueStatement) + { + // don't do anything + } + else if(statement instanceof PsiReturnStatement) + { + final PsiReturnStatement returnStatement = (PsiReturnStatement) statement; + final PsiExpression returnValue = returnStatement.getReturnValue(); + if(returnValue != null) + { + calculateExceptionsThrown(returnValue, exceptionTypes, factory); + } + } + else if(statement instanceof PsiThrowStatement) + { + calculateExceptionsThrownForThrowStatement((PsiThrowStatement) statement, + exceptionTypes, factory); + } + else if(statement instanceof PsiExpressionListStatement) + { + final PsiExpressionListStatement listStatement = (PsiExpressionListStatement) statement; + calculateExceptionsThrownForExpressionListStatement(listStatement, exceptionTypes, factory); + } + else if(statement instanceof PsiExpressionStatement) + { + final PsiExpressionStatement expStatement = (PsiExpressionStatement) statement; + final PsiExpression expression = expStatement.getExpression(); + calculateExceptionsThrown(expression, exceptionTypes, factory); + } + else if(statement instanceof PsiAssertStatement) + { + final PsiAssertStatement assertStatement = (PsiAssertStatement) statement; + calculateExceptionsThrownForAssertStatement(assertStatement, exceptionTypes, factory); + } + else if(statement instanceof PsiDeclarationStatement) + { + final PsiDeclarationStatement declStatement = (PsiDeclarationStatement) statement; + calculateExceptionsThrownForDeclarationStatemt(declStatement, exceptionTypes, factory); + } + else if(statement instanceof PsiForStatement) + { + calculateExceptionsThrownForForExpression((PsiForStatement) statement, + exceptionTypes, factory); + } + else if(statement instanceof PsiWhileStatement) + { + calculateExceptionsThrownForWhileStatement((PsiWhileStatement) statement, + exceptionTypes, factory); + } + else if(statement instanceof PsiDoWhileStatement) + { + calculateExceptionsThrownForDoWhileStatement((PsiDoWhileStatement) statement, + exceptionTypes, factory); + } + else if(statement instanceof PsiSynchronizedStatement) + { + calculateExceptionsThrownForSynchronizedStatement((PsiSynchronizedStatement) statement, + exceptionTypes, factory); + } + else if(statement instanceof PsiBlockStatement) + { + final PsiBlockStatement block = (PsiBlockStatement) statement; + calculateExceptionsThrownForBlockStatement(block, exceptionTypes, factory); + } + else if(statement instanceof PsiLabeledStatement) + { + final PsiLabeledStatement labeledStatement = (PsiLabeledStatement) statement; + calculateExceptionsThrownForLabeledStatement(labeledStatement, exceptionTypes, factory); + } + else if(statement instanceof PsiIfStatement) + { + final PsiIfStatement ifStatement = (PsiIfStatement) statement; + calculateExceptionsThrownForIfStatement(ifStatement, exceptionTypes, factory); + } + else if(statement instanceof PsiTryStatement) + { + final PsiTryStatement tryStatement = (PsiTryStatement) statement; + calculateExceptionsThrownForTryStatement(tryStatement, factory, exceptionTypes); + + } + else if(statement instanceof PsiSwitchStatement) + { + final PsiSwitchStatement switchStatement = (PsiSwitchStatement) statement; + calculateExceptionsThrownForSwitchStatement(switchStatement, exceptionTypes, factory); + } + } + + private static void calculateExceptionsThrownForLabeledStatement(final PsiLabeledStatement labeledStatement, Set exceptionTypes, PsiElementFactory factory) + { + final PsiStatement statement = labeledStatement.getStatement(); + calculateExceptionsThrownForStatement(statement, exceptionTypes, factory); + } + + private static void calculateExceptionsThrownForExpressionListStatement(final PsiExpressionListStatement listStatement, Set exceptionTypes, PsiElementFactory factory) + { + final PsiExpressionList expressionList = listStatement.getExpressionList(); + final PsiExpression[] expressions = expressionList.getExpressions(); + for(int i = 0; i < expressions.length; i++) + { + calculateExceptionsThrown(expressions[i], exceptionTypes, factory); + } + } + + private static void calculateExceptionsThrownForDeclarationStatemt(final PsiDeclarationStatement declStatement, Set exceptionTypes, PsiElementFactory factory) + { + final PsiElement[] elements = declStatement.getDeclaredElements(); + for(int i = 0; i < elements.length; i++) + { + final PsiVariable var = (PsiVariable) elements[i]; + final PsiExpression initializer = var.getInitializer(); + if(initializer != null) + { + calculateExceptionsThrown(initializer, exceptionTypes, factory); + } + } + } + + private static void calculateExceptionsThrownForAssertStatement(final PsiAssertStatement assertStatement, Set exceptionTypes, PsiElementFactory factory) + { + final PsiExpression assertCondition = assertStatement.getAssertCondition(); + calculateExceptionsThrown(assertCondition, exceptionTypes, factory); + final PsiExpression assertDescription = assertStatement.getAssertDescription(); + calculateExceptionsThrown(assertDescription, exceptionTypes, factory); + } + + private static void calculateExceptionsThrownForThrowStatement(final PsiThrowStatement throwStatement, Set exceptionTypes, PsiElementFactory factory) + { + final PsiExpression exception = throwStatement.getException(); + final PsiType type = exception.getType(); + exceptionTypes.add(type); + calculateExceptionsThrown(exception, exceptionTypes, factory); + } + + private static void calculateExceptionsThrownForSwitchStatement(final PsiSwitchStatement switchStatement, Set exceptionTypes, PsiElementFactory factory) + { + final PsiExpression switchExpression = switchStatement.getExpression(); + calculateExceptionsThrown(switchExpression, exceptionTypes, factory); + final PsiCodeBlock body = switchStatement.getBody(); + calculateExceptionsThrownForCodeBlock(body, exceptionTypes, factory); + } + + private static void calculateExceptionsThrownForTryStatement(final PsiTryStatement tryStatement, PsiElementFactory factory, Set exceptionTypes) + { + final Set exceptionThrown = new HashSet(10); + final PsiCodeBlock tryBlock = tryStatement.getTryBlock(); + calculateExceptionsThrownForCodeBlock(tryBlock, exceptionThrown, factory); + final Set exceptionHandled = ExceptionUtils.getExceptionTypesHandled(tryStatement); + for(Iterator thrown = exceptionThrown.iterator(); thrown.hasNext();) + { + final PsiType thrownType = (PsiType) thrown.next(); + boolean found = false; + for(Iterator handled = exceptionHandled.iterator(); handled.hasNext();) + { + final PsiType handledType = (PsiType) handled.next(); + if(handledType.isAssignableFrom(thrownType)) + { + found = true; + break; + } + } + if(!found) + { + exceptionTypes.add(thrownType); + } + } + final PsiCodeBlock finallyBlock = tryStatement.getFinallyBlock(); + if(finallyBlock != null) + { + calculateExceptionsThrownForCodeBlock(finallyBlock, exceptionTypes, factory); + } + + final PsiCodeBlock[] catchBlocks = tryStatement.getCatchBlocks(); + for(int i = 0; i < catchBlocks.length; i++) + { + calculateExceptionsThrownForCodeBlock(catchBlocks[i], exceptionTypes, factory); + } + } + + private static void calculateExceptionsThrownForIfStatement(final PsiIfStatement ifStatement, Set exceptionTypes, PsiElementFactory factory) + { + final PsiExpression condition = ifStatement.getCondition(); + final PsiStatement thenBranch = ifStatement.getThenBranch(); + final PsiStatement elseBranch = ifStatement.getElseBranch(); + calculateExceptionsThrown(condition, exceptionTypes, factory); + calculateExceptionsThrownForStatement(thenBranch, exceptionTypes, factory); + calculateExceptionsThrownForStatement(elseBranch, exceptionTypes, factory); + } + + private static void calculateExceptionsThrownForBlockStatement(final PsiBlockStatement block, Set exceptionTypes, PsiElementFactory factory) + { + final PsiCodeBlock codeBlock = block.getCodeBlock(); + calculateExceptionsThrownForCodeBlock(codeBlock, exceptionTypes, factory); + } + + private static void calculateExceptionsThrownForSynchronizedStatement(final PsiSynchronizedStatement syncStatement, Set exceptionTypes, PsiElementFactory factory) + { + final PsiExpression lockExpression = syncStatement.getLockExpression(); + if(lockExpression != null) + { + calculateExceptionsThrown(lockExpression, exceptionTypes, factory); + } + final PsiCodeBlock body = syncStatement.getBody(); + calculateExceptionsThrownForCodeBlock(body, exceptionTypes, factory); + } + + private static void calculateExceptionsThrownForDoWhileStatement(final PsiDoWhileStatement loopStatement, Set exceptionTypes, PsiElementFactory factory) + { + final PsiExpression condition = loopStatement.getCondition(); + calculateExceptionsThrown(condition, exceptionTypes, factory); + final PsiStatement body = loopStatement.getBody(); + calculateExceptionsThrownForStatement(body, exceptionTypes, factory); + } + + private static void calculateExceptionsThrownForWhileStatement(final PsiWhileStatement loopStatement, Set exceptionTypes, PsiElementFactory factory) + { + final PsiExpression condition = loopStatement.getCondition(); + calculateExceptionsThrown(condition, exceptionTypes, factory); + final PsiStatement body = loopStatement.getBody(); + calculateExceptionsThrownForStatement(body, exceptionTypes, factory); + } + + private static void calculateExceptionsThrownForForExpression(final PsiForStatement loopStatement, Set exceptionTypes, PsiElementFactory factory) + { + final PsiStatement initialization = loopStatement.getInitialization(); + final PsiExpression condition = loopStatement.getCondition(); + final PsiStatement update = loopStatement.getUpdate(); + final PsiStatement body = loopStatement.getBody(); + calculateExceptionsThrownForStatement(initialization, exceptionTypes, factory); + calculateExceptionsThrown(condition, exceptionTypes, factory); + calculateExceptionsThrownForStatement(update, exceptionTypes, factory); + calculateExceptionsThrownForStatement(body, exceptionTypes, factory); + } + + private static void calculateExceptionsThrown(PsiExpression exp, Set exceptionTypes, PsiElementFactory factory) + { + if(exp == null) + { + return; + } + if(exp instanceof PsiThisExpression || + exp instanceof PsiLiteralExpression || + exp instanceof PsiSuperExpression || + exp instanceof PsiClassObjectAccessExpression) + { + } + else if(exp instanceof PsiTypeCastExpression) + { + calculateExceptionsThrownForTypeCast((PsiTypeCastExpression) exp, + exceptionTypes, factory); + } + else if(exp instanceof PsiInstanceOfExpression) + { + calculateExceptionsThrownForInstanceOf((PsiInstanceOfExpression) exp, + exceptionTypes, factory); + } + else if(exp instanceof PsiReferenceExpression) + { + final PsiReferenceExpression refExp = (PsiReferenceExpression) exp; + final PsiExpression qualifier = refExp.getQualifierExpression(); + if(qualifier != null) + { + calculateExceptionsThrown(qualifier, exceptionTypes, factory); + } + } + else if(exp instanceof PsiMethodCallExpression) + { + calculateExceptionsThrownForMethodCall((PsiMethodCallExpression) exp, + exceptionTypes, factory); + + } + else if(exp instanceof PsiNewExpression) + { + calculateExceptionsThrownForNewExpression((PsiNewExpression) exp, + exceptionTypes, factory); + } + else if(exp instanceof PsiArrayInitializerExpression) + { + calculateExceptionsThrownForArrayInitializerExpression((PsiArrayInitializerExpression) exp, exceptionTypes, factory); + } + else if(exp instanceof PsiArrayAccessExpression) + { + calculateExceptionsThrownForArrayAccessExpression((PsiArrayAccessExpression) exp, exceptionTypes, factory); + } + else if(exp instanceof PsiPrefixExpression) + { + calculateExceptionsThrownForPrefixException((PsiPrefixExpression) exp, exceptionTypes, factory); + } + else if(exp instanceof PsiPostfixExpression) + { + calculateExceptionsThrownForPostixExpression((PsiPostfixExpression) exp, exceptionTypes, factory); + } + else if(exp instanceof PsiBinaryExpression) + { + calculateExceptionsThrownForBinaryExpression((PsiBinaryExpression) exp, exceptionTypes, factory); + } + else if(exp instanceof PsiConditionalExpression) + { + calculateExceptionsThrownForConditionalExcpression((PsiConditionalExpression) exp, + exceptionTypes, factory); + } + } + + private static void calculateExceptionsThrownForTypeCast(final PsiTypeCastExpression typeCast, Set exceptionTypes, PsiElementFactory factory) + { + final PsiExpression operand = typeCast.getOperand(); + calculateExceptionsThrown(operand, exceptionTypes, factory); + } + + private static void calculateExceptionsThrownForInstanceOf(final PsiInstanceOfExpression instExp, Set exceptionTypes, PsiElementFactory factory) + { + final PsiExpression operand = instExp.getOperand(); + calculateExceptionsThrown(operand, exceptionTypes, factory); + } + + private static void calculateExceptionsThrownForNewExpression(final PsiNewExpression newExp, Set exceptionTypes, PsiElementFactory factory) + { + final PsiExpressionList argumentList = newExp.getArgumentList(); + if(argumentList != null) + { + final PsiExpression[] args = argumentList.getExpressions(); + for(int i = 0; i < args.length; i++) + { + calculateExceptionsThrown(args[i], exceptionTypes, factory); + } + } + final PsiExpression[] arrayDims = newExp.getArrayDimensions(); + for(int i = 0; i < arrayDims.length; i++) + { + calculateExceptionsThrown(arrayDims[i], exceptionTypes, factory); + } + final PsiExpression qualifier = newExp.getQualifier(); + calculateExceptionsThrown(qualifier, exceptionTypes, factory); + final PsiArrayInitializerExpression arrayInitializer = newExp.getArrayInitializer(); + calculateExceptionsThrown(arrayInitializer, exceptionTypes, factory); + final PsiMethod method = newExp.resolveMethod(); + if(method != null) + { + final PsiReferenceList throwsList = method.getThrowsList(); + final PsiJavaCodeReferenceElement[] list = throwsList.getReferenceElements(); + for(int i = 0; i < list.length; i++) + { + final PsiJavaCodeReferenceElement referenceElement = list[i]; + final PsiClass exceptionClass = (PsiClass) referenceElement.resolve(); + final PsiClassType exceptionType = factory.createType(exceptionClass); + exceptionTypes.add(exceptionType); + } + } + } + + private static void calculateExceptionsThrownForMethodCall(final PsiMethodCallExpression methExp, Set exceptionTypes, PsiElementFactory factory) + { + final PsiExpressionList argumentList = methExp.getArgumentList(); + if(argumentList != null) + { + final PsiExpression[] expressions = argumentList.getExpressions(); + for(int i = 0; i < expressions.length; i++) + { + calculateExceptionsThrown(expressions[i], exceptionTypes, factory); + } + } + final PsiReferenceExpression methodExpression = methExp.getMethodExpression(); + calculateExceptionsThrown(methodExpression, exceptionTypes, factory); + final PsiMethod method = methExp.resolveMethod(); + + if(method != null) + { + final PsiReferenceList throwsList = method.getThrowsList(); + final PsiJavaCodeReferenceElement[] list = throwsList.getReferenceElements(); + for(int i = 0; i < list.length; i++) + { + final PsiJavaCodeReferenceElement referenceElement = list[i]; + final PsiClass exceptionClass = (PsiClass) referenceElement.resolve(); + final PsiClassType exceptionType = factory.createType(exceptionClass); + exceptionTypes.add(exceptionType); + } + } + } + + private static void calculateExceptionsThrownForConditionalExcpression(final PsiConditionalExpression condExp, Set exceptionTypes, PsiElementFactory factory) + { + final PsiExpression condition = condExp.getCondition(); + final PsiExpression elseExpression = condExp.getElseExpression(); + final PsiExpression thenExpression = condExp.getThenExpression(); + calculateExceptionsThrown(condition, exceptionTypes, factory); + calculateExceptionsThrown(elseExpression, exceptionTypes, factory); + calculateExceptionsThrown(thenExpression, exceptionTypes, factory); + } + + private static void calculateExceptionsThrownForBinaryExpression(final PsiBinaryExpression binaryExp, Set exceptionTypes, PsiElementFactory factory) + { + final PsiExpression lOperand = binaryExp.getLOperand(); + calculateExceptionsThrown(lOperand, exceptionTypes, factory); + final PsiExpression rhs = binaryExp.getROperand(); + calculateExceptionsThrown(rhs, exceptionTypes, factory); + } + + private static void calculateExceptionsThrownForArrayInitializerExpression(final PsiArrayInitializerExpression arrayExp, Set exceptionTypes, PsiElementFactory factory) + { + final PsiExpression[] initializers = arrayExp.getInitializers(); + for(int i = 0; i < initializers.length; i++) + { + calculateExceptionsThrown(initializers[i], exceptionTypes, factory); + } + } + + private static void calculateExceptionsThrownForArrayAccessExpression(final PsiArrayAccessExpression arrayAccessExp, Set exceptionTypes, PsiElementFactory factory) + { + final PsiExpression arrayExpression = arrayAccessExp.getArrayExpression(); + calculateExceptionsThrown(arrayExpression, exceptionTypes, factory); + final PsiExpression indexExpression = arrayAccessExp.getIndexExpression(); + calculateExceptionsThrown(indexExpression, exceptionTypes, factory); + } + + private static void calculateExceptionsThrownForPrefixException(final PsiPrefixExpression prefixExp, Set exceptionTypes, PsiElementFactory factory) + { + final PsiExpression operand = prefixExp.getOperand(); + calculateExceptionsThrown(operand, exceptionTypes, factory); + } + + private static void calculateExceptionsThrownForPostixExpression(final PsiPostfixExpression postfixExp, Set exceptionTypes, PsiElementFactory factory) + { + final PsiExpression operand = postfixExp.getOperand(); + calculateExceptionsThrown(operand, exceptionTypes, factory); + } + + public static void calculateExceptionsThrownForCodeBlock(PsiCodeBlock block, Set exceptionTypes, PsiElementFactory factory) + { + if(block == null) + { + return; + } + final PsiStatement[] statements = block.getStatements(); + for(int i = 0; i < statements.length; i++) + { + calculateExceptionsThrownForStatement(statements[i], exceptionTypes, factory); + } + } +} diff --git a/plugins/IntentionPowerPak/src/com/siyeh/ipp/exceptions/HeirarchicalTypeComparator.java b/plugins/IntentionPowerPak/src/com/siyeh/ipp/exceptions/HeirarchicalTypeComparator.java new file mode 100644 index 000000000000..ccc2f1a2b6c1 --- /dev/null +++ b/plugins/IntentionPowerPak/src/com/siyeh/ipp/exceptions/HeirarchicalTypeComparator.java @@ -0,0 +1,23 @@ +package com.siyeh.ipp.exceptions; + +import com.intellij.psi.PsiType; + +import java.util.Comparator; + +class HeirarchicalTypeComparator implements Comparator +{ + public int compare(Object o1, Object o2) + { + final PsiType type1 = (PsiType) o1; + final PsiType type2 = (PsiType) o2; + if(type1.isAssignableFrom(type2)) + { + return 1; + } + if(type2.isAssignableFrom(type1)) + { + return -1; + } + return 0; + } +} diff --git a/plugins/IntentionPowerPak/src/com/siyeh/ipp/fqnames/FullyQualifiedNamePredicate.java b/plugins/IntentionPowerPak/src/com/siyeh/ipp/fqnames/FullyQualifiedNamePredicate.java new file mode 100644 index 000000000000..4f93658e5a3d --- /dev/null +++ b/plugins/IntentionPowerPak/src/com/siyeh/ipp/fqnames/FullyQualifiedNamePredicate.java @@ -0,0 +1,29 @@ +package com.siyeh.ipp.fqnames; + +import com.intellij.psi.*; +import com.siyeh.ipp.PsiElementPredicate; + +class FullyQualifiedNamePredicate implements PsiElementPredicate +{ + public boolean satisfiedBy(PsiElement element) + { + if(!(element instanceof PsiJavaCodeReferenceElement) + || element instanceof PsiReferenceExpression) + { + return false; + } + + PsiElement parent = element.getParent(); + while(parent instanceof PsiJavaCodeReferenceElement) + { + parent = parent.getParent(); + } + if(parent instanceof PsiPackageStatement || + parent instanceof PsiImportStatement) + { + return false; + } + final String text = element.getText(); + return text.indexOf((int) '.') >= 0; + } +} diff --git a/plugins/IntentionPowerPak/src/com/siyeh/ipp/fqnames/ReplaceFullyQualifiedNameWithImportIntention.java b/plugins/IntentionPowerPak/src/com/siyeh/ipp/fqnames/ReplaceFullyQualifiedNameWithImportIntention.java new file mode 100644 index 000000000000..ca3d63ee1d85 --- /dev/null +++ b/plugins/IntentionPowerPak/src/com/siyeh/ipp/fqnames/ReplaceFullyQualifiedNameWithImportIntention.java @@ -0,0 +1,41 @@ +package com.siyeh.ipp.fqnames; + +import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.project.Project; +import com.intellij.psi.PsiFile; +import com.intellij.psi.PsiJavaCodeReferenceElement; +import com.intellij.psi.PsiManager; +import com.intellij.psi.codeStyle.CodeStyleManager; +import com.intellij.util.IncorrectOperationException; +import com.siyeh.ipp.Intention; +import com.siyeh.ipp.PsiElementPredicate; + +public class ReplaceFullyQualifiedNameWithImportIntention extends Intention { + public ReplaceFullyQualifiedNameWithImportIntention(Project project) { + super(project); + } + + public String getText() { + return "Replace qualified name with import"; + } + + public String getFamilyName() { + return "Replace Qualified Name With Import"; + } + + public PsiElementPredicate getElementPredicate() { + return new FullyQualifiedNamePredicate(); + } + + public void invoke(Project project, Editor editor, PsiFile file) throws IncorrectOperationException { + final PsiManager mgr = PsiManager.getInstance(project); + PsiJavaCodeReferenceElement element = + (PsiJavaCodeReferenceElement) findMatchingElement(file, editor); + while (element.getParent() instanceof PsiJavaCodeReferenceElement) { + element = (PsiJavaCodeReferenceElement) element.getParent(); + } + + final CodeStyleManager styleManager = mgr.getCodeStyleManager(); + styleManager.shortenClassReferences(element); + } +} diff --git a/plugins/IntentionPowerPak/src/com/siyeh/ipp/integer/ConvertIntegerToDecimalIntention.java b/plugins/IntentionPowerPak/src/com/siyeh/ipp/integer/ConvertIntegerToDecimalIntention.java new file mode 100644 index 000000000000..22ef47f79abd --- /dev/null +++ b/plugins/IntentionPowerPak/src/com/siyeh/ipp/integer/ConvertIntegerToDecimalIntention.java @@ -0,0 +1,66 @@ +package com.siyeh.ipp.integer; + +import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.project.Project; +import com.intellij.psi.PsiFile; +import com.intellij.psi.PsiLiteralExpression; +import com.intellij.util.IncorrectOperationException; +import com.siyeh.ipp.*; + +import java.math.BigInteger; + +public class ConvertIntegerToDecimalIntention extends Intention +{ + public ConvertIntegerToDecimalIntention(Project project) + { + super(project); + } + + public String getText() + { + return "Convert to decimal"; + } + + public String getFamilyName() + { + return "Convert To Decimal"; + } + + public PsiElementPredicate getElementPredicate() + { + return new ConvertIntegerToDecimalPredicate(); + } + + + public void invoke(Project project, Editor editor, PsiFile file) throws IncorrectOperationException + { + final PsiLiteralExpression exp = (PsiLiteralExpression) findMatchingElement(file, editor); + String textString = exp.getText(); + + final int textLength = textString.length(); + final char lastChar = textString.charAt(textLength - 1); + final boolean isLong = lastChar == 'l' || lastChar == 'L'; + if(isLong) + { + textString = textString.substring(0, textLength - 1); + } + + final BigInteger val; + if(textString.startsWith("0x")) + { + final String rawIntString = textString.substring(2); + val = new BigInteger(rawIntString, 16); + } + else + { + final String rawIntString = textString.substring(1); + val = new BigInteger(rawIntString, 8); + } + String decimalString = val.toString(10); + if(isLong) + { + decimalString += 'L'; + } + replaceExpression(project, decimalString, exp); + } +} diff --git a/plugins/IntentionPowerPak/src/com/siyeh/ipp/integer/ConvertIntegerToDecimalPredicate.java b/plugins/IntentionPowerPak/src/com/siyeh/ipp/integer/ConvertIntegerToDecimalPredicate.java new file mode 100644 index 000000000000..cc10e0e5bf1a --- /dev/null +++ b/plugins/IntentionPowerPak/src/com/siyeh/ipp/integer/ConvertIntegerToDecimalPredicate.java @@ -0,0 +1,26 @@ +package com.siyeh.ipp.integer; + +import com.intellij.psi.*; +import com.siyeh.ipp.PsiElementPredicate; + +class ConvertIntegerToDecimalPredicate implements PsiElementPredicate { + public boolean satisfiedBy(PsiElement element) { + if (!(element instanceof PsiLiteralExpression)) { + return false; + } + final PsiLiteralExpression expression = (PsiLiteralExpression) element; + final PsiType type = expression.getType(); + if (!(type.equals(PsiType.INT) || type.equals(PsiType.LONG))) { + return false; + } + final String text = expression.getText(); + if (text == null || text.length() < 2) { + return false; + } + + if ("0".equals(text) || "0L".equals(text)) { + return false; + } + return text.charAt(0) == '0'; + } +} diff --git a/plugins/IntentionPowerPak/src/com/siyeh/ipp/integer/ConvertIntegerToHexIntention.java b/plugins/IntentionPowerPak/src/com/siyeh/ipp/integer/ConvertIntegerToHexIntention.java new file mode 100644 index 000000000000..649da27ffb51 --- /dev/null +++ b/plugins/IntentionPowerPak/src/com/siyeh/ipp/integer/ConvertIntegerToHexIntention.java @@ -0,0 +1,63 @@ +package com.siyeh.ipp.integer; + +import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.project.Project; +import com.intellij.psi.PsiFile; +import com.intellij.psi.PsiLiteralExpression; +import com.intellij.util.IncorrectOperationException; +import com.siyeh.ipp.*; + +import java.math.BigInteger; + +public class ConvertIntegerToHexIntention extends Intention +{ + public ConvertIntegerToHexIntention(Project project) + { + super(project); + } + + public String getText() + { + return "Convert to hex"; + } + + public String getFamilyName() + { + return "Convert To Hexadecimal"; + } + + public PsiElementPredicate getElementPredicate() + { + return new ConvertIntegerToHexPredicate(); + } + + + public void invoke(Project project, Editor editor, PsiFile file) throws IncorrectOperationException + { + final PsiLiteralExpression exp = (PsiLiteralExpression) findMatchingElement(file, editor); + String textString = exp.getText(); + final int textLength = textString.length(); + final char lastChar = textString.charAt(textLength - 1); + final boolean isLong = lastChar == 'l' || lastChar == 'L'; + if(isLong) + { + textString = textString.substring(0, textLength - 1); + } + + final BigInteger val; + if(textString.charAt(0) == '0') + { + val = new BigInteger(textString, 8); + } + else + { + val = new BigInteger(textString, 10); + } + String hexString = "0x" + val.toString(16); + if(isLong) + { + hexString += 'L'; + } + replaceExpression(project, hexString, exp); + } +} diff --git a/plugins/IntentionPowerPak/src/com/siyeh/ipp/integer/ConvertIntegerToHexPredicate.java b/plugins/IntentionPowerPak/src/com/siyeh/ipp/integer/ConvertIntegerToHexPredicate.java new file mode 100644 index 000000000000..faf52d7fb840 --- /dev/null +++ b/plugins/IntentionPowerPak/src/com/siyeh/ipp/integer/ConvertIntegerToHexPredicate.java @@ -0,0 +1,25 @@ +package com.siyeh.ipp.integer; + +import com.intellij.psi.*; +import com.siyeh.ipp.PsiElementPredicate; + +class ConvertIntegerToHexPredicate implements PsiElementPredicate +{ + public boolean satisfiedBy(PsiElement element) + { + if(!(element instanceof PsiLiteralExpression)) + { + return false; + } + final PsiLiteralExpression expression = (PsiLiteralExpression) element; + final PsiType type = expression.getType(); + if(!(type.equals(PsiType.INT) || + type.equals(PsiType.LONG))) + { + return false; + } + final String text = expression.getText(); + + return !(text.startsWith("0x") || text.startsWith("0X")); + } +} diff --git a/plugins/IntentionPowerPak/src/com/siyeh/ipp/integer/ConvertIntegerToOctalIntention.java b/plugins/IntentionPowerPak/src/com/siyeh/ipp/integer/ConvertIntegerToOctalIntention.java new file mode 100644 index 000000000000..ff4be194f761 --- /dev/null +++ b/plugins/IntentionPowerPak/src/com/siyeh/ipp/integer/ConvertIntegerToOctalIntention.java @@ -0,0 +1,63 @@ +package com.siyeh.ipp.integer; + +import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.project.Project; +import com.intellij.psi.PsiFile; +import com.intellij.psi.PsiLiteralExpression; +import com.intellij.util.IncorrectOperationException; +import com.siyeh.ipp.*; + +import java.math.BigInteger; + +public class ConvertIntegerToOctalIntention extends Intention +{ + public ConvertIntegerToOctalIntention(Project project) + { + super(project); + } + + public String getText() + { + return "Convert to octal"; + } + + public String getFamilyName() + { + return "Convert To Octal"; + } + + public PsiElementPredicate getElementPredicate() + { + return new ConvertIntegerToOctalPredicate(); + } + + + public void invoke(Project project, Editor editor, PsiFile file) throws IncorrectOperationException + { + final PsiLiteralExpression exp = (PsiLiteralExpression) findMatchingElement(file, editor); + String textString = exp.getText(); + final int textLength = textString.length(); + final char lastChar = textString.charAt(textLength - 1); + final boolean isLong = lastChar == 'l' || lastChar == 'L'; + if(isLong) + { + textString = textString.substring(0, textLength - 1); + } + final BigInteger val; + if(textString.startsWith("0x")) + { + final String rawTextString = textString.substring(2); + val = new BigInteger(rawTextString, 16); + } + else + { + val = new BigInteger(textString, 10); + } + String octString = '0' + val.toString(8); + if(isLong) + { + octString += 'L'; + } + replaceExpression(project, octString, exp); + } +} diff --git a/plugins/IntentionPowerPak/src/com/siyeh/ipp/integer/ConvertIntegerToOctalPredicate.java b/plugins/IntentionPowerPak/src/com/siyeh/ipp/integer/ConvertIntegerToOctalPredicate.java new file mode 100644 index 000000000000..1f0e2bf16037 --- /dev/null +++ b/plugins/IntentionPowerPak/src/com/siyeh/ipp/integer/ConvertIntegerToOctalPredicate.java @@ -0,0 +1,36 @@ +package com.siyeh.ipp.integer; + +import com.intellij.psi.*; +import com.siyeh.ipp.PsiElementPredicate; + +class ConvertIntegerToOctalPredicate implements PsiElementPredicate +{ + public boolean satisfiedBy(PsiElement element) + { + if(!(element instanceof PsiLiteralExpression)) + { + return false; + } + final PsiLiteralExpression expression = (PsiLiteralExpression) element; + final PsiType type = expression.getType(); + if(!(type.equals(PsiType.INT) || + type.equals(PsiType.LONG))) + { + return false; + } + final String text = expression.getText(); + if(text == null || text.length() == 0) + { + return false; + } + if(text.startsWith("0x") || text.startsWith("0X")) + { + return true; + } + if("0".equals(text) || "0L".equals(text)) + { + return false; + } + return text.charAt(0) != '0'; + } +} diff --git a/plugins/IntentionPowerPak/src/com/siyeh/ipp/junit/AssertEqualsLiteralPredicate.java b/plugins/IntentionPowerPak/src/com/siyeh/ipp/junit/AssertEqualsLiteralPredicate.java new file mode 100644 index 000000000000..a97fb6c20a1d --- /dev/null +++ b/plugins/IntentionPowerPak/src/com/siyeh/ipp/junit/AssertEqualsLiteralPredicate.java @@ -0,0 +1,55 @@ +package com.siyeh.ipp.junit; + +import com.intellij.psi.*; +import com.siyeh.ipp.PsiElementPredicate; + +class AssertEqualsLiteralPredicate implements PsiElementPredicate +{ + public boolean satisfiedBy(PsiElement element) + { + if(!(element instanceof PsiMethodCallExpression)) + { + return false; + } + final PsiMethodCallExpression expression = (PsiMethodCallExpression) element; + final PsiExpressionList argumentList = expression.getArgumentList(); + if(argumentList == null) + { + return false; + } + final PsiExpression[] args = argumentList.getExpressions(); + final int numArgs = args.length; + if(numArgs < 2 || numArgs > 3) + { + return false; + } + final PsiReferenceExpression methodExpression = expression.getMethodExpression(); + if(methodExpression == null) + { + return false; + } + final String methodName = methodExpression.getReferenceName(); + if(!"assertEquals".equals(methodName)) + { + return false; + } + if(numArgs == 2) + { + return !isSpecialCase(args[0]) && !isSpecialCase(args[1]); + } + else + { + return !isSpecialCase(args[1]) && !isSpecialCase(args[2]); + } + } + + private static boolean isSpecialCase(PsiExpression exp) + { + if(exp == null) + { + return false; + } + final String text = exp.getText(); + return "true".equals(text) || "false".equals(text) || "null".equals(text); + } +} diff --git a/plugins/IntentionPowerPak/src/com/siyeh/ipp/junit/AssertEqualsWithLiteralPredicate.java b/plugins/IntentionPowerPak/src/com/siyeh/ipp/junit/AssertEqualsWithLiteralPredicate.java new file mode 100644 index 000000000000..67cc3269d3f1 --- /dev/null +++ b/plugins/IntentionPowerPak/src/com/siyeh/ipp/junit/AssertEqualsWithLiteralPredicate.java @@ -0,0 +1,45 @@ +package com.siyeh.ipp.junit; + +import com.intellij.psi.*; +import com.siyeh.ipp.PsiElementPredicate; + +class AssertEqualsWithLiteralPredicate implements PsiElementPredicate { + + public boolean satisfiedBy(PsiElement element) { + if (!(element instanceof PsiMethodCallExpression)) { + return false; + } + final PsiMethodCallExpression expression = (PsiMethodCallExpression) element; + final PsiExpressionList argumentList = expression.getArgumentList(); + if (argumentList == null) { + return false; + } + final PsiExpression[] args = argumentList.getExpressions(); + final int numArgs = args.length; + if (numArgs < 2 || numArgs > 3) { + return false; + } + final PsiReferenceExpression methodExpression = expression.getMethodExpression(); + if (methodExpression == null) { + return false; + } + final String methodName = methodExpression.getReferenceName(); + if (!"assertEquals".equals(methodName)) { + return false; + } + if (numArgs == 2) { + return isSpecialLiteral(args[0]) || isSpecialLiteral(args[1]); + } else { + return isSpecialLiteral(args[1]) || isSpecialLiteral(args[2]); + } + } + + private boolean isSpecialLiteral(PsiExpression arg) { + if (arg == null) { + return false; + } + final String text = arg.getText(); + return "true".equals(text) || + "false".equals(text) || "null".equals(text); + } +} diff --git a/plugins/IntentionPowerPak/src/com/siyeh/ipp/junit/AssertLiteralPredicate.java b/plugins/IntentionPowerPak/src/com/siyeh/ipp/junit/AssertLiteralPredicate.java new file mode 100644 index 000000000000..2e4f0adc00f5 --- /dev/null +++ b/plugins/IntentionPowerPak/src/com/siyeh/ipp/junit/AssertLiteralPredicate.java @@ -0,0 +1,31 @@ +package com.siyeh.ipp.junit; + +import com.intellij.psi.*; +import com.siyeh.ipp.PsiElementPredicate; + +class AssertLiteralPredicate implements PsiElementPredicate { + + AssertLiteralPredicate() { + super(); + } + + public boolean satisfiedBy(PsiElement element) { + if (!(element instanceof PsiMethodCallExpression)) { + return false; + } + final PsiMethodCallExpression expression = (PsiMethodCallExpression) element; + final int numExpressions = expression.getArgumentList().getExpressions().length; + if (numExpressions < 1 || numExpressions > 2) { + return false; + } + final PsiReferenceExpression methodExpression = expression.getMethodExpression(); + if (methodExpression == null) { + return false; + } + final String methodName = methodExpression.getReferenceName(); + + return "assertTrue".equals(methodName) || + "assertFalse".equals(methodName) || + "assertNull".equals(methodName); + } +} diff --git a/plugins/IntentionPowerPak/src/com/siyeh/ipp/junit/AssertTrueEqualsPredicate.java b/plugins/IntentionPowerPak/src/com/siyeh/ipp/junit/AssertTrueEqualsPredicate.java new file mode 100644 index 000000000000..6549b811a22e --- /dev/null +++ b/plugins/IntentionPowerPak/src/com/siyeh/ipp/junit/AssertTrueEqualsPredicate.java @@ -0,0 +1,76 @@ +package com.siyeh.ipp.junit; + +import com.intellij.psi.*; +import com.siyeh.ipp.PsiElementPredicate; + +class AssertTrueEqualsPredicate implements PsiElementPredicate +{ + public boolean satisfiedBy(PsiElement element) + { + if(!(element instanceof PsiMethodCallExpression)) + { + return false; + } + final PsiMethodCallExpression expression = (PsiMethodCallExpression) element; + final PsiExpressionList argumentList = expression.getArgumentList(); + if(argumentList == null) + { + return false; + } + final PsiExpression[] args = argumentList.getExpressions(); + final int numArgs = args.length; + if(numArgs < 1 || numArgs > 2) + { + return false; + } + final PsiReferenceExpression methodExpression = expression.getMethodExpression(); + if(methodExpression == null) + { + return false; + } + final String methodName = methodExpression.getReferenceName(); + if(!"assertTrue".equals(methodName)) + { + return false; + } + if(numArgs == 1) + { + return isEquality(args[0]); + } + else + { + return isEquality(args[1]); + } + } + + private static boolean isEquality(PsiExpression arg) + { + if(arg instanceof PsiBinaryExpression) + { + final PsiBinaryExpression binaryExp = (PsiBinaryExpression) arg; + final PsiJavaToken sign = binaryExp.getOperationSign(); + return sign.getTokenType() == JavaTokenType.EQEQ; + } + else if(arg instanceof PsiMethodCallExpression) + { + final PsiMethodCallExpression expression = (PsiMethodCallExpression) arg; + if(expression.getArgumentList() == null) + { + return false; + } + if(expression.getArgumentList().getExpressions().length != 1) + { + return false; + } + final PsiReferenceExpression methodExpression = expression.getMethodExpression(); + if(methodExpression == null) + { + return false; + } + final String methodName = methodExpression.getReferenceName(); + return "equals".equals(methodName); + } + return false; + } + +} diff --git a/plugins/IntentionPowerPak/src/com/siyeh/ipp/junit/AssertTrueOrFalsePredicate.java b/plugins/IntentionPowerPak/src/com/siyeh/ipp/junit/AssertTrueOrFalsePredicate.java new file mode 100644 index 000000000000..f2e823c3582e --- /dev/null +++ b/plugins/IntentionPowerPak/src/com/siyeh/ipp/junit/AssertTrueOrFalsePredicate.java @@ -0,0 +1,28 @@ +package com.siyeh.ipp.junit; + +import com.intellij.psi.*; +import com.siyeh.ipp.PsiElementPredicate; + +class AssertTrueOrFalsePredicate implements PsiElementPredicate +{ + public boolean satisfiedBy(PsiElement element) + { + if(!(element instanceof PsiMethodCallExpression)) + { + return false; + } + final PsiMethodCallExpression expression = (PsiMethodCallExpression) element; + final int numExpressions = expression.getArgumentList().getExpressions().length; + if(numExpressions < 1 || numExpressions > 2) + { + return false; + } + final PsiReferenceExpression methodExpression = expression.getMethodExpression(); + if(methodExpression == null) + { + return false; + } + final String methodName = methodExpression.getReferenceName(); + return "assertTrue".equals(methodName)||"assertFalse".equals(methodName); + } +} diff --git a/plugins/IntentionPowerPak/src/com/siyeh/ipp/junit/FlipAssertLiteralIntention.java b/plugins/IntentionPowerPak/src/com/siyeh/ipp/junit/FlipAssertLiteralIntention.java new file mode 100644 index 000000000000..c49463ac6c52 --- /dev/null +++ b/plugins/IntentionPowerPak/src/com/siyeh/ipp/junit/FlipAssertLiteralIntention.java @@ -0,0 +1,87 @@ +package com.siyeh.ipp.junit; + +import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.project.Project; +import com.intellij.psi.*; +import com.intellij.util.IncorrectOperationException; +import com.siyeh.ipp.*; +import com.siyeh.ipp.psiutils.BoolUtils; + +public class FlipAssertLiteralIntention extends MutablyNamedIntention +{ + + public FlipAssertLiteralIntention(Project project) + { + super(project); + } + + protected String getTextForElement(PsiElement element) { + final PsiMethodCallExpression call = (PsiMethodCallExpression)element; + final PsiReferenceExpression methodExpression = call.getMethodExpression(); + final String fromMethodName = methodExpression.getReferenceName(); + final String toMethodName; + if("assertTrue".equals(fromMethodName)) + { + toMethodName = "assertFalse"; + } + else + { + toMethodName = "assertTrue"; + } + return "Replace " + fromMethodName + "() with " + toMethodName + "()"; + } + + public String getFamilyName() + { + return "Flip Assert Literal"; + } + + public PsiElementPredicate getElementPredicate() + { + return new AssertTrueOrFalsePredicate(); + } + + public void invoke(Project project, Editor editor, PsiFile file) throws IncorrectOperationException + { + final PsiMethodCallExpression call = + (PsiMethodCallExpression) findMatchingElement(file, editor); + + final PsiReferenceExpression methodExpression = call.getMethodExpression(); + final String fromMethodName = methodExpression.getReferenceName(); + final String toMethodName; + if ("assertTrue".equals(fromMethodName)) { + toMethodName = "assertFalse"; + } else { + toMethodName = "assertTrue"; + } + final PsiExpression qualifierExp = methodExpression.getQualifierExpression(); + + final String qualifier; + if(qualifierExp == null) + { + qualifier = ""; + } + else + { + qualifier = qualifierExp.getText() + '.'; + } + final PsiExpressionList argumentList = call.getArgumentList(); + final PsiExpression[] args = argumentList.getExpressions(); + final String callString; + if(args.length == 1) + { + final PsiExpression arg = args[0]; + callString = qualifier + toMethodName + '(' + BoolUtils.getNegatedExpressionText(arg) + ')'; + } + else + { + final PsiExpression arg = args[1]; + callString = + qualifier + toMethodName + '(' + args[0].getText() + ',' + + BoolUtils.getNegatedExpressionText(arg) + + ')'; + } + replaceExpression(project, callString, call); + } + +} diff --git a/plugins/IntentionPowerPak/src/com/siyeh/ipp/junit/ReplaceAssertEqualsWithAssertLiteralIntention.java b/plugins/IntentionPowerPak/src/com/siyeh/ipp/junit/ReplaceAssertEqualsWithAssertLiteralIntention.java new file mode 100644 index 000000000000..42f54376c043 --- /dev/null +++ b/plugins/IntentionPowerPak/src/com/siyeh/ipp/junit/ReplaceAssertEqualsWithAssertLiteralIntention.java @@ -0,0 +1,90 @@ +package com.siyeh.ipp.junit; + +import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.project.Project; +import com.intellij.psi.*; +import com.intellij.util.IncorrectOperationException; +import com.siyeh.ipp.*; + +public class ReplaceAssertEqualsWithAssertLiteralIntention extends MutablyNamedIntention { + + public ReplaceAssertEqualsWithAssertLiteralIntention(Project project) { + super(project); + } + + protected String getTextForElement(PsiElement element) { + + final PsiMethodCallExpression call = (PsiMethodCallExpression)element; + final PsiExpressionList argumentList = call.getArgumentList(); + final PsiExpression[] args = argumentList.getExpressions(); + final String assertString; + if (args.length == 2) { + final String argText = args[0].getText(); + assertString = getAssertString(argText); + } else { + final String argText = args[1].getText(); + assertString = getAssertString(argText); + } + return "Replace 'assertEquals()' with '" + assertString + "()'"; + } + + public String getFamilyName() { + return "Replace assertEquals with assertTrue, assertFalse, or assertNull"; + } + public PsiElementPredicate getElementPredicate() { + return new AssertEqualsWithLiteralPredicate(); + } + + public void invoke(Project project, Editor editor, PsiFile file) throws IncorrectOperationException { + final PsiMethodCallExpression call = + (PsiMethodCallExpression) findMatchingElement(file, editor); + final PsiReferenceExpression expression = call.getMethodExpression(); + final PsiExpression qualifierExp = expression.getQualifierExpression(); + + final String qualifier; + if (qualifierExp == null) { + qualifier = ""; + } else { + qualifier = qualifierExp.getText() + '.'; + } + + final PsiExpressionList argumentList = call.getArgumentList(); + final PsiExpression[] args = argumentList.getExpressions(); + final String callString; + if (args.length == 2) { + final PsiExpression otherArg; + final String argText = args[0].getText(); + if ("true".equals(argText) || + "false".equals(argText) || + "null".equals(argText)) { + otherArg = args[1]; + } else { + otherArg = args[0]; + } + callString = qualifier + getAssertString(argText) + '(' + otherArg.getText() + ')'; + } else { + final PsiExpression otherArg; + final String argText = args[1].getText(); + if ("true".equals(argText) || + "false".equals(argText) || + "null".equals(argText)) { + otherArg = args[2]; + } else { + otherArg = args[1]; + } + callString = qualifier + getAssertString(argText) + '(' + args[0].getText() + ", " + otherArg.getText() + ')'; + } + replaceExpression(project, callString, call); + + } + + private static String getAssertString(String argText) { + if ("true".equals(argText)) { + return "assertTrue"; + } + if ("false".equals(argText)) { + return "assertFalse"; + } + return "assertNull"; + } +} diff --git a/plugins/IntentionPowerPak/src/com/siyeh/ipp/junit/ReplaceAssertLiteralWithAssertEqualsIntention.java b/plugins/IntentionPowerPak/src/com/siyeh/ipp/junit/ReplaceAssertLiteralWithAssertEqualsIntention.java new file mode 100644 index 000000000000..c02621453ec3 --- /dev/null +++ b/plugins/IntentionPowerPak/src/com/siyeh/ipp/junit/ReplaceAssertLiteralWithAssertEqualsIntention.java @@ -0,0 +1,82 @@ +package com.siyeh.ipp.junit; + +import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.project.Project; +import com.intellij.psi.*; +import com.intellij.util.IncorrectOperationException; +import com.siyeh.ipp.*; + +public class ReplaceAssertLiteralWithAssertEqualsIntention extends MutablyNamedIntention +{ + + public ReplaceAssertLiteralWithAssertEqualsIntention(Project project) + { + super(project); + } + + protected String getTextForElement(PsiElement element) + { + final PsiMethodCallExpression call = (PsiMethodCallExpression)element; + final PsiExpressionList argumentList = call.getArgumentList(); + final PsiExpression[] args = argumentList.getExpressions(); + final PsiReferenceExpression methodExpression = call.getMethodExpression(); + final String methodName = methodExpression.getReferenceName(); + final String literal = methodName.substring("assert".length()).toLowerCase(); + + final String messageText; + if(args.length == 1) + { + messageText = ""; + } + else + { + messageText = "..., "; + } + return "Replace " + methodName + "() with assertEquals(" + messageText + literal + ", ...)"; + } + + public String getFamilyName() + { + return "Replace assertTrue, assertFalse, or assertNull with assertEquals"; + } + + public PsiElementPredicate getElementPredicate() + { + return new AssertLiteralPredicate(); + } + + public void invoke(Project project, Editor editor, PsiFile file) throws IncorrectOperationException + { + final PsiMethodCallExpression call = + (PsiMethodCallExpression) findMatchingElement(file, editor); + final PsiReferenceExpression methodExpression = call.getMethodExpression(); + final PsiExpression qualifierExp = methodExpression.getQualifierExpression(); + final String methodName = methodExpression.getReferenceName(); + final String literal = methodName.substring("assert".length()).toLowerCase(); + + final String qualifier; + if(qualifierExp == null) + { + qualifier = ""; + } + else + { + qualifier = qualifierExp.getText() + '.'; + } + final PsiExpressionList argumentList = call.getArgumentList(); + final PsiExpression[] args = argumentList.getExpressions(); + + final String callString; + if(args.length == 1) + { + callString = qualifier + "assertEquals(" + literal + ", " + args[0].getText() + ')'; + } + else + { + callString = + qualifier + "assertEquals(" + args[0].getText() + ", " + literal + ", " + args[1].getText() + + ')'; + } + replaceExpression(project, callString, call); + } +} diff --git a/plugins/IntentionPowerPak/src/com/siyeh/ipp/opassign/AssignmentExpressionReplaceableWithOperatorAssigment.java b/plugins/IntentionPowerPak/src/com/siyeh/ipp/opassign/AssignmentExpressionReplaceableWithOperatorAssigment.java new file mode 100644 index 000000000000..0f000cf5c09b --- /dev/null +++ b/plugins/IntentionPowerPak/src/com/siyeh/ipp/opassign/AssignmentExpressionReplaceableWithOperatorAssigment.java @@ -0,0 +1,46 @@ +package com.siyeh.ipp.opassign; + +import com.intellij.psi.*; +import com.siyeh.ipp.PsiElementPredicate; +import com.siyeh.ipp.psiutils.EquivalenceChecker; +import com.siyeh.ipp.psiutils.SideEffectChecker; + +class AssignmentExpressionReplaceableWithOperatorAssigment implements PsiElementPredicate +{ + public boolean satisfiedBy(PsiElement element) + { + if(!(element instanceof PsiAssignmentExpression)) + { + return false; + } + final PsiAssignmentExpression assignment = (PsiAssignmentExpression) element; + final PsiJavaToken sign = assignment.getOperationSign(); + if(sign.getTokenType() != JavaTokenType.EQ) + { + return false; + } + final PsiExpression lhs = assignment.getLExpression(); + final PsiExpression rhs = assignment.getRExpression(); + if(lhs == null || rhs == null) + { + return false; + } + if(!(rhs instanceof PsiBinaryExpression)) + { + return false; + } + final PsiBinaryExpression binaryRhs = (PsiBinaryExpression) rhs; + final PsiJavaToken operatorSign = binaryRhs.getOperationSign(); + if(operatorSign.getTokenType() == JavaTokenType.OROR || + operatorSign.getTokenType() == JavaTokenType.ANDAND) + { + return false; + } + if(SideEffectChecker.mayHaveSideEffects(lhs)) + { + return false; + } + final PsiExpression rhsLhs = binaryRhs.getLOperand(); + return EquivalenceChecker.expressionsAreEquivalent(lhs, rhsLhs); + } +} diff --git a/plugins/IntentionPowerPak/src/com/siyeh/ipp/opassign/ReplaceWithOperatorAssignmentIntention.java b/plugins/IntentionPowerPak/src/com/siyeh/ipp/opassign/ReplaceWithOperatorAssignmentIntention.java new file mode 100644 index 000000000000..28dfe84badf7 --- /dev/null +++ b/plugins/IntentionPowerPak/src/com/siyeh/ipp/opassign/ReplaceWithOperatorAssignmentIntention.java @@ -0,0 +1,46 @@ +package com.siyeh.ipp.opassign; + +import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.project.Project; +import com.intellij.psi.*; +import com.intellij.util.IncorrectOperationException; +import com.siyeh.ipp.*; + +public class ReplaceWithOperatorAssignmentIntention extends MutablyNamedIntention +{ + public ReplaceWithOperatorAssignmentIntention(Project project) + { + super(project); + } + + public String getTextForElement(PsiElement element) + { + final PsiAssignmentExpression exp = (PsiAssignmentExpression) element; + final PsiBinaryExpression rhs = (PsiBinaryExpression) exp.getRExpression(); + final PsiJavaToken sign = rhs.getOperationSign(); + final String operator = sign.getText(); + return "Replace = with " + operator + '='; + } + + public String getFamilyName() + { + return "Replace Assignment With Operator Assignment"; + } + + public PsiElementPredicate getElementPredicate() + { + return new AssignmentExpressionReplaceableWithOperatorAssigment(); + } + + public void invoke(Project project, Editor editor, PsiFile file) throws IncorrectOperationException + { + final PsiAssignmentExpression exp = (PsiAssignmentExpression) findMatchingElement(file, editor); + final PsiBinaryExpression rhs = (PsiBinaryExpression) exp.getRExpression(); + final PsiExpression lhs = exp.getLExpression(); + final PsiJavaToken sign = rhs.getOperationSign(); + final String operand = sign.getText(); + final PsiExpression rhsrhs = rhs.getROperand(); + final String expString = lhs.getText() + operand + '=' + rhsrhs.getText(); + replaceExpression(project, expString, exp); + } +} diff --git a/plugins/IntentionPowerPak/src/com/siyeh/ipp/parenthesis/RemoveUnnecessaryParenthesesIntention.java b/plugins/IntentionPowerPak/src/com/siyeh/ipp/parenthesis/RemoveUnnecessaryParenthesesIntention.java new file mode 100644 index 000000000000..20861c6dc025 --- /dev/null +++ b/plugins/IntentionPowerPak/src/com/siyeh/ipp/parenthesis/RemoveUnnecessaryParenthesesIntention.java @@ -0,0 +1,46 @@ +package com.siyeh.ipp.parenthesis; + +import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.project.Project; +import com.intellij.psi.PsiExpression; +import com.intellij.psi.PsiFile; +import com.intellij.util.IncorrectOperationException; +import com.siyeh.ipp.*; +import com.siyeh.ipp.psiutils.ParenthesesUtils; + +public class RemoveUnnecessaryParenthesesIntention extends Intention +{ + + public RemoveUnnecessaryParenthesesIntention(Project project) + { + super(project); + } + + public String getText() + { + return "Remove unnecessary parentheses"; + } + + public String getFamilyName() + { + return "Remove Unnecessary Parentheses"; + } + + public PsiElementPredicate getElementPredicate() + { + return new UnnecessaryParenthesesPredicate(); + } + + public void invoke(Project project, Editor editor, PsiFile file) throws IncorrectOperationException + { + PsiExpression exp = + (PsiExpression) findMatchingElement(file, editor); + while(exp.getParent() instanceof PsiExpression) + { + exp = (PsiExpression) exp.getParent(); + } + final String newExpression = ParenthesesUtils.removeParentheses(exp); + replaceExpression(project, newExpression, exp); + } + +} diff --git a/plugins/IntentionPowerPak/src/com/siyeh/ipp/parenthesis/UnnecessaryParenthesesPredicate.java b/plugins/IntentionPowerPak/src/com/siyeh/ipp/parenthesis/UnnecessaryParenthesesPredicate.java new file mode 100644 index 000000000000..1bca0dd1c31f --- /dev/null +++ b/plugins/IntentionPowerPak/src/com/siyeh/ipp/parenthesis/UnnecessaryParenthesesPredicate.java @@ -0,0 +1,49 @@ +package com.siyeh.ipp.parenthesis; + +import com.intellij.psi.*; +import com.intellij.psi.tree.IElementType; +import com.siyeh.ipp.PsiElementPredicate; +import com.siyeh.ipp.psiutils.ParenthesesUtils; + +class UnnecessaryParenthesesPredicate implements PsiElementPredicate{ + public boolean satisfiedBy(PsiElement element){ + if(!(element instanceof PsiParenthesizedExpression)){ + return false; + } + final PsiParenthesizedExpression expression = (PsiParenthesizedExpression) element; + final PsiElement parent = expression.getParent(); + if(!(parent instanceof PsiExpression)){ + return true; + } + final PsiExpression body = expression.getExpression(); + if(body instanceof PsiParenthesizedExpression){ + return true; + } + + final int parentPrecendence = ParenthesesUtils.getPrecendence( + (PsiExpression) parent); + final int childPrecendence = ParenthesesUtils.getPrecendence(body); + if(parentPrecendence > childPrecendence){ + return true; + } else if(parentPrecendence == childPrecendence){ + + if(parent instanceof PsiBinaryExpression && + body instanceof PsiBinaryExpression){ + final PsiJavaToken parentSign = ((PsiBinaryExpression) parent).getOperationSign(); + final IElementType parentOperator = parentSign.getTokenType(); + final PsiJavaToken childSign = ((PsiBinaryExpression) body).getOperationSign(); + final IElementType childOperator = childSign.getTokenType(); + + final PsiBinaryExpression binaryExpression = (PsiBinaryExpression) parent; + final PsiExpression lhs = binaryExpression.getLOperand(); + return lhs.equals(expression) && + parentOperator == childOperator; + } else{ + return false; + } + } else{ + return false; + } + + } +} \ No newline at end of file diff --git a/plugins/IntentionPowerPak/src/com/siyeh/ipp/psiutils/BoolUtils.java b/plugins/IntentionPowerPak/src/com/siyeh/ipp/psiutils/BoolUtils.java new file mode 100644 index 000000000000..5a4c5d76a7f5 --- /dev/null +++ b/plugins/IntentionPowerPak/src/com/siyeh/ipp/psiutils/BoolUtils.java @@ -0,0 +1,108 @@ +package com.siyeh.ipp.psiutils; + +import com.intellij.psi.*; + +public class BoolUtils +{ + private BoolUtils() + { + super(); + + } + + public static boolean isNegated(PsiExpression exp) + { + PsiExpression ancestor = exp; + while(ancestor.getParent() instanceof PsiParenthesizedExpression) + { + ancestor = (PsiExpression) ancestor.getParent(); + } + if(ancestor.getParent() instanceof PsiPrefixExpression) + { + final PsiPrefixExpression prefixAncestor = (PsiPrefixExpression) ancestor.getParent(); + final PsiJavaToken sign = prefixAncestor.getOperationSign(); + if(sign.getTokenType()== JavaTokenType.EXCL) + { + return true; + } + } + return false; + } + + public static PsiExpression findNegation(PsiExpression exp) + { + PsiExpression ancestor = exp; + while(ancestor.getParent() instanceof PsiParenthesizedExpression) + { + ancestor = (PsiExpression) ancestor.getParent(); + } + if(ancestor.getParent() instanceof PsiPrefixExpression) + { + final PsiPrefixExpression prefixAncestor = (PsiPrefixExpression) ancestor.getParent(); + final PsiJavaToken sign = prefixAncestor.getOperationSign(); + if(sign.getTokenType() == JavaTokenType.EXCL) + { + return prefixAncestor; + } + } + return null; + } + + public static boolean isNegation(PsiExpression exp) + { + if(!(exp instanceof PsiPrefixExpression)) + { + return false; + } + final PsiPrefixExpression prefixExp = (PsiPrefixExpression) exp; + final PsiJavaToken sign = prefixExp.getOperationSign(); + return sign.getTokenType() == JavaTokenType.EXCL; + } + + public static PsiExpression getNegated(PsiExpression exp) + { + final PsiPrefixExpression prefixExp = (PsiPrefixExpression) exp; + final PsiExpression operand = prefixExp.getOperand(); + return ParenthesesUtils.stripParentheses(operand); + } + + public static boolean isBooleanLiteral(PsiExpression exp) + { + if(exp instanceof PsiLiteralExpression) + { + final PsiLiteralExpression expression = (PsiLiteralExpression) exp; + final String text = expression.getText(); + return "true".equals(text) || "false".equals(text); + } + return false; + } + + public static String getNegatedExpressionText(PsiExpression condition) + { + if(BoolUtils.isNegation(condition)) + { + final PsiExpression negated = getNegated(condition); + return negated.getText(); + } + else if(ComparisonUtils.isComparison(condition)) + { + final PsiBinaryExpression binaryExpression = (PsiBinaryExpression) condition; + final PsiJavaToken sign = binaryExpression.getOperationSign(); + final String operator = sign.getText(); + final String negatedComparison = ComparisonUtils.getNegatedComparison(operator); + final PsiExpression lhs = binaryExpression.getLOperand(); + final PsiExpression rhs = binaryExpression.getROperand(); + return lhs.getText() + negatedComparison + rhs.getText(); + } + else if(ParenthesesUtils.getPrecendence(condition) > + ParenthesesUtils.PREFIX_PRECEDENCE) + { + return "!(" + condition.getText() + ')'; + } + else + { + return '!' + condition.getText(); + } + + } +} diff --git a/plugins/IntentionPowerPak/src/com/siyeh/ipp/psiutils/ComparisonUtils.java b/plugins/IntentionPowerPak/src/com/siyeh/ipp/psiutils/ComparisonUtils.java new file mode 100644 index 000000000000..67636ab42817 --- /dev/null +++ b/plugins/IntentionPowerPak/src/com/siyeh/ipp/psiutils/ComparisonUtils.java @@ -0,0 +1,65 @@ +package com.siyeh.ipp.psiutils; + +import com.intellij.psi.*; + +import java.util.*; + +public class ComparisonUtils +{ + + private static final Set s_comparisonStrings = new HashSet(6); + private static final Map s_swappedComparisons = new HashMap(6); + private static final Map s_invertedComparisons = new HashMap(6); + + private ComparisonUtils() + { + super(); + } + + static + { + s_comparisonStrings.add("=="); + s_comparisonStrings.add("!="); + s_comparisonStrings.add(">"); + s_comparisonStrings.add("<"); + s_comparisonStrings.add(">="); + s_comparisonStrings.add("<="); + + s_swappedComparisons.put("==", "=="); + s_swappedComparisons.put("!=", "!="); + s_swappedComparisons.put(">", "<"); + s_swappedComparisons.put("<", ">"); + s_swappedComparisons.put(">=", "<="); + s_swappedComparisons.put("<=", ">="); + + s_invertedComparisons.put("==", "!="); + s_invertedComparisons.put("!=", "=="); + s_invertedComparisons.put(">", "<="); + s_invertedComparisons.put("<", ">="); + s_invertedComparisons.put(">=", "<"); + s_invertedComparisons.put("<=", ">"); + } + + public static boolean isComparison(PsiExpression exp) + { + if(!(exp instanceof PsiBinaryExpression)) + { + return false; + } + final PsiBinaryExpression binaryExpression = (PsiBinaryExpression) exp; + final PsiJavaToken sign = binaryExpression.getOperationSign(); + final String operation = sign.getText(); + return s_comparisonStrings.contains(operation); + } + + public static String getFlippedComparison(String str) + { + return (String) s_swappedComparisons.get(str); + } + + public static String getNegatedComparison(String str) + { + return (String) s_invertedComparisons.get(str); + } + +} diff --git a/plugins/IntentionPowerPak/src/com/siyeh/ipp/psiutils/ConditionalUtils.java b/plugins/IntentionPowerPak/src/com/siyeh/ipp/psiutils/ConditionalUtils.java new file mode 100644 index 000000000000..2cd5c1948494 --- /dev/null +++ b/plugins/IntentionPowerPak/src/com/siyeh/ipp/psiutils/ConditionalUtils.java @@ -0,0 +1,92 @@ +package com.siyeh.ipp.psiutils; + +import com.intellij.psi.*; + +public class ConditionalUtils +{ + private ConditionalUtils() + { + super(); + } + + public static PsiStatement stripBraces(PsiStatement branch) + { + if(branch instanceof PsiBlockStatement) + { + final PsiBlockStatement block = (PsiBlockStatement) branch; + final PsiCodeBlock codeBlock = block.getCodeBlock(); + final PsiStatement[] statements = codeBlock.getStatements(); + if(statements.length == 1) + { + return statements[0]; + } + else + { + return block; + } + } + else + { + return branch; + } + } + + public static boolean isReturn(PsiStatement statement, String value) + { + if(statement == null) + { + return false; + } + if(!(statement instanceof PsiReturnStatement)) + { + return false; + } + final PsiReturnStatement returnStatement = (PsiReturnStatement) statement; + if(returnStatement.getReturnValue() == null) + { + return false; + } + final PsiExpression returnValue = returnStatement.getReturnValue(); + final String returnValueText = returnValue.getText(); + return value.equals(returnValueText); + } + + public static boolean isAssignment(PsiStatement statement, String value) + { + if(statement == null) + { + return false; + } + if(!(statement instanceof PsiExpressionStatement)) + { + return false; + } + final PsiExpressionStatement expressionStatement = (PsiExpressionStatement) statement; + final PsiExpression expression = expressionStatement.getExpression(); + if(!(expression instanceof PsiAssignmentExpression)) + { + return false; + } + final PsiAssignmentExpression assignment = (PsiAssignmentExpression) expression; + final PsiExpression rhs = assignment.getRExpression(); + final PsiExpression lhs = assignment.getLExpression(); + if(lhs == null || rhs == null) + { + return false; + } + final String rhsText = rhs.getText(); + return value.equals(rhsText); + } + + public static boolean isAssignment(PsiStatement statement) + { + if(!(statement instanceof PsiExpressionStatement)) + { + return false; + } + final PsiExpressionStatement expressionStatement = (PsiExpressionStatement) statement; + final PsiExpression expression = expressionStatement.getExpression(); + return expression instanceof PsiAssignmentExpression; + } + +} diff --git a/plugins/IntentionPowerPak/src/com/siyeh/ipp/psiutils/ControlFlowUtils.java b/plugins/IntentionPowerPak/src/com/siyeh/ipp/psiutils/ControlFlowUtils.java new file mode 100644 index 000000000000..93b1e61c5347 --- /dev/null +++ b/plugins/IntentionPowerPak/src/com/siyeh/ipp/psiutils/ControlFlowUtils.java @@ -0,0 +1,269 @@ +package com.siyeh.ipp.psiutils; + +import com.intellij.psi.*; +import com.intellij.psi.util.ConstantExpressionUtil; +import com.intellij.psi.util.PsiUtil; + +public class ControlFlowUtils +{ + private ControlFlowUtils() + { + super(); + } + public static boolean statementMayCompleteNormally(PsiStatement statement) + { + if(statement instanceof PsiBreakStatement || + statement instanceof PsiContinueStatement || + statement instanceof PsiReturnStatement || + statement instanceof PsiThrowStatement) + { + return false; + } + else if(statement instanceof PsiExpressionListStatement || + statement instanceof PsiExpressionStatement || + statement instanceof PsiEmptyStatement || + statement instanceof PsiAssertStatement || + statement instanceof PsiDeclarationStatement) + { + return true; + } + else if(statement instanceof PsiForStatement) + { + final PsiForStatement loopStatement = (PsiForStatement) statement; + final PsiExpression test = loopStatement.getCondition(); + + return test != null && !isBooleanConstant(test, false) || statementIsBreakTarget(loopStatement); + } + else if(statement instanceof PsiWhileStatement) + { + final PsiWhileStatement loopStatement = (PsiWhileStatement) statement; + final PsiExpression test = loopStatement.getCondition(); + return !isBooleanConstant(test, true) + || statementIsBreakTarget(loopStatement); + } + else if(statement instanceof PsiDoWhileStatement) + { + final PsiDoWhileStatement loopStatement = (PsiDoWhileStatement) statement; + final PsiExpression test = loopStatement.getCondition(); + return statementMayCompleteNormally(loopStatement) && !isBooleanConstant(test, true) + || statementIsBreakTarget(loopStatement); + } + else if(statement instanceof PsiSynchronizedStatement) + { + final PsiCodeBlock body = ((PsiSynchronizedStatement) statement).getBody(); + return codeBlockMayCompleteNormally(body); + } + else if(statement instanceof PsiBlockStatement) + { + final PsiCodeBlock codeBlock = ((PsiBlockStatement) statement).getCodeBlock(); + return codeBlockMayCompleteNormally(codeBlock); + } + else if(statement instanceof PsiLabeledStatement) + { + final PsiLabeledStatement labeledStatement = (PsiLabeledStatement) statement; + final PsiStatement body = labeledStatement.getStatement(); + return statementMayCompleteNormally(body) + || statementIsBreakTarget(body); + } + else if(statement instanceof PsiIfStatement) + { + final PsiIfStatement ifStatement = (PsiIfStatement) statement; + final PsiStatement thenBranch = ifStatement.getThenBranch(); + if(statementMayCompleteNormally(thenBranch)) + { + return true; + } + final PsiStatement elseBranch = ifStatement.getElseBranch(); + if(elseBranch == null || + statementMayCompleteNormally(elseBranch)) + { + return true; + } + return false; + } + else if(statement instanceof PsiTryStatement) + { + final PsiTryStatement tryStatement = (PsiTryStatement) statement; + + final PsiCodeBlock finallyBlock = tryStatement.getFinallyBlock(); + if(finallyBlock != null) + { + if(!codeBlockMayCompleteNormally(finallyBlock)) + { + return false; + } + } + final PsiCodeBlock tryBlock = tryStatement.getTryBlock(); + if(codeBlockMayCompleteNormally(tryBlock)) + { + return true; + } + final PsiCodeBlock[] catchBlocks = tryStatement.getCatchBlocks(); + for(int i = 0; i < catchBlocks.length; i++) + { + final PsiCodeBlock catchBlock = catchBlocks[i]; + if(codeBlockMayCompleteNormally(catchBlock)) + { + return true; + } + } + return false; + } + else if(statement instanceof PsiSwitchStatement) + { + final PsiSwitchStatement switchStatement = (PsiSwitchStatement) statement; + if(statementIsBreakTarget(switchStatement)) + { + return true; + } + final PsiCodeBlock body = switchStatement.getBody(); + final PsiStatement[] statements = body.getStatements(); + int lastNonLabelOffset = -1; + for(int i = statements.length - 1; i >= 0; i--) + { + if(!(statements[i] instanceof PsiSwitchLabelStatement)) + { + lastNonLabelOffset = i; + break; + } + } + if(lastNonLabelOffset == -1) + { + return true; // it's all labels + } + else if(lastNonLabelOffset == statements.length - 1) + { + return statementMayCompleteNormally(statements[statements.length - 1]); + } + else + { + return true; // the last statement is a label + } + } + else // unknown statement type + { + return false; + } + } + + private static boolean codeBlockMayCompleteNormally(PsiCodeBlock block) + { + final PsiStatement[] statements = block.getStatements(); + for(int i = 0; i < statements.length; i++) + { + final PsiStatement statement = statements[i]; + if(!statementMayCompleteNormally(statement)) + { + return false; + } + } + return true; + } + + private static boolean isBooleanConstant(PsiExpression test, boolean val) + { + if(!PsiUtil.isConstantExpression(test)) + { + return false; + } + final boolean value = ((Boolean) ConstantExpressionUtil.computeCastTo(test, PsiType.BOOLEAN)).booleanValue(); + return value == val; + } + + private static boolean statementIsBreakTarget(PsiStatement statement) + { + final BreakTargetFinder breakFinder = new BreakTargetFinder(statement); + statement.accept(breakFinder); + return breakFinder.breakFound(); + } + + private static class BreakTargetFinder extends PsiRecursiveElementVisitor + { + private boolean m_found = false; + private final PsiStatement m_target; + + private BreakTargetFinder(PsiStatement target) + { + super(); + m_target = target; + } + + private boolean breakFound() + { + return m_found; + } + + public void visitReferenceExpression(PsiReferenceExpression psiReferenceExpression) + { + } + + public void visitBreakStatement(PsiBreakStatement breakStatement) + { + super.visitBreakStatement(breakStatement); + final PsiStatement exitedStatement = breakStatement.findExitedStatement(); + if(exitedStatement.equals(m_target)) + { + m_found = true; + } + } + } + + public static boolean statementContainsExitingBreak(PsiStatement statement) + { + + final ExitingBreakFinder breakFinder = new ExitingBreakFinder(); + statement.accept(breakFinder); + + return breakFinder.breakFound(); + } + + private static class ExitingBreakFinder extends PsiRecursiveElementVisitor + { + private boolean m_found = false; + + private ExitingBreakFinder() + { + super(); + } + + private boolean breakFound() + { + return m_found; + } + + public void visitReferenceExpression(PsiReferenceExpression exp) + { + } + + public void visitBreakStatement(PsiBreakStatement breakStatement) + { + if(breakStatement.getLabelIdentifier() != null) + { + return; + } + m_found = true; + } + + public void visitDoWhileStatement(PsiDoWhileStatement statement) + { + // don't drill down + } + + public void visitForStatement(PsiForStatement statement) + { + // don't drill down + } + + public void visitWhileStatement(PsiWhileStatement statement) + { + // don't drill down + } + + public void visitSwitchStatement(PsiSwitchStatement statement) + { + // don't drill down + } + + } + +} diff --git a/plugins/IntentionPowerPak/src/com/siyeh/ipp/psiutils/DeclarationUtils.java b/plugins/IntentionPowerPak/src/com/siyeh/ipp/psiutils/DeclarationUtils.java new file mode 100644 index 000000000000..2a9722cda234 --- /dev/null +++ b/plugins/IntentionPowerPak/src/com/siyeh/ipp/psiutils/DeclarationUtils.java @@ -0,0 +1,153 @@ +package com.siyeh.ipp.psiutils; + +import com.intellij.psi.*; + +import java.util.Set; + +public class DeclarationUtils +{ + private DeclarationUtils() + { + super(); + } + + public static void calculateVariablesDeclared(PsiStatement statement, Set variablesDeclaredAtTopLevel, + Set variablesDeclaredAtLowerLevels, boolean isTopLevel) + { + if(statement == null) + { + return; + } + if(statement instanceof PsiBreakStatement || + statement instanceof PsiExpressionStatement || + statement instanceof PsiContinueStatement || + statement instanceof PsiThrowStatement || + statement instanceof PsiExpressionListStatement || + statement instanceof PsiAssertStatement || + statement instanceof PsiReturnStatement) + { + + } + else if(statement instanceof PsiDeclarationStatement) + { + final PsiDeclarationStatement declStatement = (PsiDeclarationStatement) statement; + final PsiElement[] elements = declStatement.getDeclaredElements(); + for(int i = 0; i < elements.length; i++) + { + final PsiVariable var = (PsiVariable) elements[i]; + final String varName = var.getName(); + if(isTopLevel) + { + variablesDeclaredAtTopLevel.add(varName); + } + else + { + variablesDeclaredAtLowerLevels.add(varName); + } + } + } + else if(statement instanceof PsiForStatement) + { + final PsiForStatement loopStatement = (PsiForStatement) statement; + final PsiStatement initialization = loopStatement.getInitialization(); + calculateVariablesDeclared(initialization, variablesDeclaredAtTopLevel, + variablesDeclaredAtLowerLevels, false); + final PsiStatement update = loopStatement.getUpdate(); + calculateVariablesDeclared(update, variablesDeclaredAtTopLevel, + variablesDeclaredAtLowerLevels, false); + final PsiStatement body = loopStatement.getBody(); + calculateVariablesDeclared(body, variablesDeclaredAtTopLevel, + variablesDeclaredAtLowerLevels, false); + } + else if(statement instanceof PsiWhileStatement) + { + final PsiWhileStatement loopStatement = (PsiWhileStatement) statement; + final PsiStatement body = loopStatement.getBody(); + calculateVariablesDeclared(body, variablesDeclaredAtTopLevel, + variablesDeclaredAtLowerLevels, false); + } + else if(statement instanceof PsiDoWhileStatement) + { + final PsiDoWhileStatement loopStatement = (PsiDoWhileStatement) statement; + final PsiStatement body = loopStatement.getBody(); + calculateVariablesDeclared(body, variablesDeclaredAtTopLevel, + variablesDeclaredAtLowerLevels, false); + } + else if(statement instanceof PsiSynchronizedStatement) + { + final PsiSynchronizedStatement syncStatement = (PsiSynchronizedStatement) statement; + final PsiCodeBlock body = syncStatement.getBody(); + calculateVariablesDeclaredInCodeBlock(body, variablesDeclaredAtTopLevel, + variablesDeclaredAtLowerLevels, false); + } + else if(statement instanceof PsiBlockStatement) + { + final PsiBlockStatement block = (PsiBlockStatement) statement; + final PsiCodeBlock codeBlock = block.getCodeBlock(); + calculateVariablesDeclaredInCodeBlock(codeBlock, variablesDeclaredAtTopLevel, + variablesDeclaredAtLowerLevels, isTopLevel); + } + else if(statement instanceof PsiLabeledStatement) + { + final PsiLabeledStatement labeledStatement = (PsiLabeledStatement) statement; + final PsiStatement body = labeledStatement.getStatement(); + calculateVariablesDeclared(body, variablesDeclaredAtTopLevel, + variablesDeclaredAtLowerLevels, false); + } + else if(statement instanceof PsiIfStatement) + { + final PsiIfStatement ifStatement = (PsiIfStatement) statement; + final PsiStatement thenBranch = ifStatement.getThenBranch(); + calculateVariablesDeclared(thenBranch, variablesDeclaredAtTopLevel, + variablesDeclaredAtLowerLevels, false); + final PsiStatement elseBranch = ifStatement.getElseBranch(); + calculateVariablesDeclared(elseBranch, variablesDeclaredAtTopLevel, + variablesDeclaredAtLowerLevels, false); + } + else if(statement instanceof PsiTryStatement) + { + final PsiTryStatement tryStatement = (PsiTryStatement) statement; + final PsiCodeBlock tryBlock = tryStatement.getTryBlock(); + calculateVariablesDeclaredInCodeBlock(tryBlock, variablesDeclaredAtTopLevel, + variablesDeclaredAtLowerLevels, false); + + calculateVariablesDeclaredInCodeBlock(tryBlock, variablesDeclaredAtTopLevel, variablesDeclaredAtLowerLevels, false); + final PsiCodeBlock finallyBlock = tryStatement.getFinallyBlock(); + if(finallyBlock != null) + { + calculateVariablesDeclaredInCodeBlock(finallyBlock, variablesDeclaredAtTopLevel, variablesDeclaredAtLowerLevels, + false); + } + + final PsiCodeBlock[] catchBlocks = tryStatement.getCatchBlocks(); + for(int i = 0; i < catchBlocks.length; i++) + { + calculateVariablesDeclaredInCodeBlock(catchBlocks[i], variablesDeclaredAtTopLevel, variablesDeclaredAtLowerLevels, + false); + } + } + else if(statement instanceof PsiSwitchStatement) + { + final PsiSwitchStatement switchStatement = (PsiSwitchStatement) statement; + final PsiCodeBlock body = switchStatement.getBody(); + calculateVariablesDeclaredInCodeBlock(body, variablesDeclaredAtTopLevel, + variablesDeclaredAtLowerLevels, false); + } + + } + + private static void calculateVariablesDeclaredInCodeBlock(PsiCodeBlock block, Set variablesDeclaredAtTopLevel, + Set variablesDeclaredAtLowerLevels, boolean isTopLevel) + { + if(block == null) + { + return; + } + final PsiStatement[] statements = block.getStatements(); + for(int i = 0; i < statements.length; i++) + { + calculateVariablesDeclared(statements[i], variablesDeclaredAtTopLevel, variablesDeclaredAtLowerLevels, + isTopLevel); + } + } +} diff --git a/plugins/IntentionPowerPak/src/com/siyeh/ipp/psiutils/EquivalenceChecker.java b/plugins/IntentionPowerPak/src/com/siyeh/ipp/psiutils/EquivalenceChecker.java new file mode 100644 index 000000000000..6b916de5e91e --- /dev/null +++ b/plugins/IntentionPowerPak/src/com/siyeh/ipp/psiutils/EquivalenceChecker.java @@ -0,0 +1,889 @@ +package com.siyeh.ipp.psiutils; + +import com.intellij.psi.*; + +import java.util.ArrayList; +import java.util.List; + +public class EquivalenceChecker +{ + private EquivalenceChecker() + { + super(); + } + + private static final int THIS_EXPRESSION = 0; + private static final int LITERAL_EXPRESSION = 1; + private static final int CLASS_OBJECT_EXPRESSION = 2; + private static final int REFERENCE_EXPRESSION = 3; + private static final int SUPER_EXPRESSION = 4; + private static final int METHOD_CALL_EXPRESSION = 5; + private static final int NEW_EXPRESSION = 6; + private static final int ARRAY_INITIALIZER_EXPRESSION = 7; + private static final int TYPECAST_EXPRESSION = 8; + private static final int ARRAY_ACCESS_EXPRESSION = 9; + private static final int PREFIX_EXPRESSION = 10; + private static final int POSTFIX_EXPRESSION = 11; + private static final int BINARY_EXPRESSION = 12; + private static final int CONDITIONAL_EXPRESSION = 13; + private static final int ASSIGNMENT_EXPRESSION = 14; + + private static final int ASSERT_STATEMENT = 0; + private static final int BLOCK_STATEMENT = 1; + private static final int BREAK_STATEMENT = 2; + private static final int CONTINUE_STATEMENT = 3; + private static final int DECLARATION_STATEMENT = 4; + private static final int DO_WHILE_STATEMENT = 5; + private static final int EMPTY_STATEMENT = 6; + private static final int EXPRESSION_LIST_STATEMENT = 7; + private static final int EXPRESSION_STATEMENT = 8; + private static final int FOR_STATEMENT = 9; + private static final int IF_STATEMENT = 10; + private static final int LABELED_STATEMENT = 11; + private static final int RETURN_STATEMENT = 12; + private static final int SWITCH_LABEL_STATEMENT = 13; + private static final int SWITCH_STATEMENT = 14; + private static final int SYNCHRONIZED_STATEMENT = 15; + private static final int THROW_STATEMENT = 16; + private static final int TRY_STATEMENT = 17; + private static final int WHILE_STATEMENT = 18; + + public static boolean statementsAreEquivalent(PsiStatement exp1, PsiStatement exp2) + { + if(exp1 == null && exp2 == null) + { + return true; + } + if(exp1 == null || exp2 == null) + { + return false; + } + final int type1 = getStatementType(exp1); + final int type2 = getStatementType(exp2); + if(type1 != type2) + { + return false; + } + switch(type1) + { + case ASSERT_STATEMENT: + return assertStatementsAreEquivalent((PsiAssertStatement) exp1, + (PsiAssertStatement) exp2); + case BLOCK_STATEMENT: + return blockStatementsAreEquivalent((PsiBlockStatement) exp1, + (PsiBlockStatement) exp2); + case BREAK_STATEMENT: + return breakStatementsAreEquivalent((PsiBreakStatement) exp1, + (PsiBreakStatement) exp2); + case CONTINUE_STATEMENT: + return continueStatementsAreEquivalent((PsiContinueStatement) exp1, + (PsiContinueStatement) exp2); + case DECLARATION_STATEMENT: + return declarationStatementsAreEquivalent((PsiDeclarationStatement) exp1, + (PsiDeclarationStatement) exp2); + case DO_WHILE_STATEMENT: + return doWhileStatementsAreEquivalent((PsiDoWhileStatement) exp1, + (PsiDoWhileStatement) exp2); + case EMPTY_STATEMENT: + return true; + case EXPRESSION_LIST_STATEMENT: + return expressionListStatementsAreEquivalent((PsiExpressionListStatement) exp1, + (PsiExpressionListStatement) exp2); + case EXPRESSION_STATEMENT: + return expressionStatementsAreEquivalent((PsiExpressionStatement) exp1, + (PsiExpressionStatement) exp2); + case FOR_STATEMENT: + return forStatementsAreEquivalent((PsiForStatement) exp1, + (PsiForStatement) exp2); + case IF_STATEMENT: + return ifStatementsAreEquivalent((PsiIfStatement) exp1, + (PsiIfStatement) exp2); + case LABELED_STATEMENT: + return labeledStatementsAreEquivalent((PsiLabeledStatement) exp1, + (PsiLabeledStatement) exp2); + case RETURN_STATEMENT: + return returnStatementsAreEquivalent((PsiReturnStatement) exp1, + (PsiReturnStatement) exp2); + case SWITCH_LABEL_STATEMENT: + return switchLabelStatementsAreEquivalent((PsiSwitchLabelStatement) exp1, + (PsiSwitchLabelStatement) exp2); + case SWITCH_STATEMENT: + return switchStatementsAreEquivalent((PsiSwitchStatement) exp1, + (PsiSwitchStatement) exp2); + case SYNCHRONIZED_STATEMENT: + return synchronizedStatementsAreEquivalent((PsiSynchronizedStatement) exp1, + (PsiSynchronizedStatement) exp2); + case THROW_STATEMENT: + return throwStatementsAreEquivalent((PsiThrowStatement) exp1, + (PsiThrowStatement) exp2); + case TRY_STATEMENT: + return tryStatementsAreEquivalent((PsiTryStatement) exp1, + (PsiTryStatement) exp2); + case WHILE_STATEMENT: + return whileStatementsAreEquivalent((PsiWhileStatement) exp1, + (PsiWhileStatement) exp2); + default: + return false; + } + } + + private static boolean declarationStatementsAreEquivalent(PsiDeclarationStatement statement1, + PsiDeclarationStatement statement2) + { + final PsiElement[] elements1 = statement1.getDeclaredElements(); + final List vars1 = new ArrayList(elements1.length); + for(int i = 0; i < elements1.length; i++) + { + if(elements1[i] instanceof PsiLocalVariable) + { + vars1.add(elements1[i]); + } + } + final PsiElement[] elements2 = statement2.getDeclaredElements(); + final List vars2 = new ArrayList(elements2.length); + for(int i = 0; i < elements2.length; i++) + { + if(elements2[i] instanceof PsiLocalVariable) + { + vars2.add(elements2[i]); + } + } + if(vars1.size() != vars2.size()) + { + return false; + } + for(int i = 0; i < vars1.size(); i++) + { + final PsiLocalVariable var1 = (PsiLocalVariable) vars1.get(i); + final PsiLocalVariable var2 = (PsiLocalVariable) vars2.get(i); + if(localVariableAreEquivalent(var1, var2)) + { + return false; + } + } + return true; + } + + private static boolean localVariableAreEquivalent(PsiLocalVariable var1, PsiLocalVariable var2) + { + final PsiType type1 = var1.getType(); + final PsiType type2 = var2.getType(); + if(!typesAreEquivalent(type1, type2)) + { + return false; + } + final String name1 = var1.getName(); + final String name2 = var2.getName(); + if(name1 == null) + { + return name2 == null; + } + return name1.equals(name2); + } + + private static boolean tryStatementsAreEquivalent(PsiTryStatement statement1, + PsiTryStatement statement2) + { + final PsiCodeBlock tryBlock1 = statement1.getTryBlock(); + final PsiCodeBlock tryBlock2 = statement2.getTryBlock(); + if(!codeBlocksAreEquivalent(tryBlock1, tryBlock2)) + { + return false; + } + final PsiCodeBlock finallyBlock1 = statement1.getFinallyBlock(); + final PsiCodeBlock finallyBlock2 = statement2.getFinallyBlock(); + if(!codeBlocksAreEquivalent(finallyBlock1, finallyBlock2)) + { + return false; + } + final PsiCodeBlock[] catchBlocks1 = statement1.getCatchBlocks(); + final PsiCodeBlock[] catchBlocks2 = statement2.getCatchBlocks(); + if(catchBlocks1.length != catchBlocks2.length) + { + return false; + } + for(int i = 0; i < catchBlocks2.length; i++) + { + if(!codeBlocksAreEquivalent(catchBlocks1[i], catchBlocks2[i])) + { + return false; + } + } + final PsiParameter[] catchParameters1 = statement1.getCatchBlockParameters(); + final PsiParameter[] catchParameters2 = statement2.getCatchBlockParameters(); + if(catchParameters1.length != catchParameters2.length) + { + return false; + } + for(int i = 0; i < catchParameters2.length; i++) + { + if(!parametersAreEquivalent(catchParameters2[i], catchParameters1[i])) + { + return false; + } + } + return true; + } + + private static boolean parametersAreEquivalent(PsiParameter parameter1, PsiParameter parameter2) + { + final PsiType type1 = parameter1.getType(); + final PsiType type2 = parameter2.getType(); + if(!typesAreEquivalent(type1, type2)) + { + return false; + } + final String name1 = parameter1.getName(); + final String name2 = parameter2.getName(); + if(name1 == null) + { + return name2 == null; + } + return name1.equals(name2); + } + + private static boolean typesAreEquivalent(PsiType type1, PsiType type2) + { + if(type1 == null) + { + return type2 == null; + } + if(type2 == null) + { + return false; + } + final String type1Text = type1.getCanonicalText(); + final String type2Text = type2.getCanonicalText(); + return type1Text.equals(type2Text); + } + + private static boolean whileStatementsAreEquivalent(PsiWhileStatement statement1, + PsiWhileStatement statement2) + { + final PsiExpression condition1 = statement1.getCondition(); + final PsiExpression condition2 = statement2.getCondition(); + final PsiStatement body1 = statement1.getBody(); + final PsiStatement body2 = statement2.getBody(); + return expressionsAreEquivalent(condition1, condition2) && + statementsAreEquivalent(body1, body2); + } + + private static boolean forStatementsAreEquivalent(PsiForStatement statement1, + PsiForStatement statement2) + { + final PsiExpression condition1 = statement1.getCondition(); + final PsiExpression condition2 = statement2.getCondition(); + if(!expressionsAreEquivalent(condition1, condition2)) + { + return false; + } + final PsiStatement initialization1 = statement1.getInitialization(); + final PsiStatement initialization2 = statement2.getInitialization(); + if(!statementsAreEquivalent(initialization1, initialization2)) + { + return false; + } + final PsiStatement update1 = statement1.getUpdate(); + final PsiStatement update2 = statement2.getUpdate(); + if(!statementsAreEquivalent(update1, update2)) + { + return false; + } + final PsiStatement body1 = statement1.getBody(); + final PsiStatement body2 = statement2.getBody(); + return statementsAreEquivalent(body1, body2); + } + + private static boolean switchStatementsAreEquivalent(PsiSwitchStatement statement1, + PsiSwitchStatement statement2) + { + final PsiExpression switchExpression1 = statement1.getExpression(); + final PsiExpression swithcExpression2 = statement2.getExpression(); + final PsiCodeBlock body1 = statement1.getBody(); + final PsiCodeBlock body2 = statement2.getBody(); + return expressionsAreEquivalent(switchExpression1, swithcExpression2) && + codeBlocksAreEquivalent(body1, body2); + } + + private static boolean doWhileStatementsAreEquivalent(PsiDoWhileStatement statement1, + PsiDoWhileStatement statement2) + { + final PsiExpression condition1 = statement1.getCondition(); + final PsiExpression condition2 = statement2.getCondition(); + final PsiStatement body1 = statement1.getBody(); + final PsiStatement body2 = statement2.getBody(); + return expressionsAreEquivalent(condition1, condition2) && + statementsAreEquivalent(body1, body2); + } + + private static boolean assertStatementsAreEquivalent(PsiAssertStatement statement1, + PsiAssertStatement statement2) + { + final PsiExpression condition1 = statement1.getAssertCondition(); + final PsiExpression condition2 = statement2.getAssertCondition(); + final PsiExpression description1 = statement1.getAssertDescription(); + final PsiExpression description2 = statement2.getAssertDescription(); + return expressionsAreEquivalent(condition1, condition2) && + expressionsAreEquivalent(description1, description2); + } + + private static boolean synchronizedStatementsAreEquivalent(PsiSynchronizedStatement statement1, + PsiSynchronizedStatement statement2) + { + final PsiExpression lock1 = statement1.getLockExpression(); + final PsiExpression lock2 = statement2.getLockExpression(); + final PsiCodeBlock body1 = statement1.getBody(); + final PsiCodeBlock body2 = statement2.getBody(); + return expressionsAreEquivalent(lock1, lock2) && + codeBlocksAreEquivalent(body1, body2); + } + + private static boolean blockStatementsAreEquivalent(PsiBlockStatement statement1, + PsiBlockStatement statement2) + { + final PsiCodeBlock block1 = statement1.getCodeBlock(); + final PsiCodeBlock block2 = statement2.getCodeBlock(); + return codeBlocksAreEquivalent(block1, block2); + } + + private static boolean breakStatementsAreEquivalent(PsiBreakStatement statement1, + PsiBreakStatement statement2) + { + final PsiIdentifier identifier1 = statement1.getLabelIdentifier(); + final PsiIdentifier identifier2 = statement2.getLabelIdentifier(); + if(identifier1 == null) + { + return identifier2 == null; + } + if(identifier2 == null) + { + return false; + } + final String text1 = identifier1.getText(); + final String text2 = identifier2.getText(); + return text1.equals(text2); + } + + private static boolean continueStatementsAreEquivalent(PsiContinueStatement statement1, + PsiContinueStatement statement2) + { + final PsiIdentifier identifier1 = statement1.getLabelIdentifier(); + final PsiIdentifier identifier2 = statement2.getLabelIdentifier(); + if(identifier1 == null) + { + return identifier2 == null; + } + if(identifier2 == null) + { + return false; + } + final String text1 = identifier1.getText(); + final String text2 = identifier2.getText(); + return text1.equals(text2); + } + + private static boolean switchLabelStatementsAreEquivalent(PsiSwitchLabelStatement statement1, + PsiSwitchLabelStatement statement2) + { + if(statement1.isDefaultCase()) + { + return statement2.isDefaultCase(); + } + if(statement2.isDefaultCase()) + { + return false; + } + final PsiExpression caseExpression1 = statement1.getCaseValue(); + final PsiExpression caseExpression2 = statement2.getCaseValue(); + return expressionsAreEquivalent(caseExpression1, caseExpression2); + } + + private static boolean labeledStatementsAreEquivalent(PsiLabeledStatement statement1, + PsiLabeledStatement statement2) + { + + final PsiIdentifier identifier1 = statement1.getLabelIdentifier(); + final PsiIdentifier identifier2 = statement2.getLabelIdentifier(); + if(identifier1 == null) + { + return identifier2 == null; + } + if(identifier2 == null) + { + return false; + } + final String text1 = identifier1.getText(); + final String text2 = identifier2.getText(); + return text1.equals(text2); + } + + private static boolean codeBlocksAreEquivalent(PsiCodeBlock block1, PsiCodeBlock block2) + { + if(block1 == null && block2 == null) + { + return true; + } + if(block1 == null || block2 == null) + { + return false; + } + final PsiStatement[] statements1 = block1.getStatements(); + final PsiStatement[] statements2 = block2.getStatements(); + if(statements2.length != statements1.length) + { + return false; + } + for(int i = 0; i < statements2.length; i++) + { + if(!statementsAreEquivalent(statements2[i], statements1[i])) + { + return false; + } + } + return true; + } + + private static boolean ifStatementsAreEquivalent(PsiIfStatement statement1, + PsiIfStatement statement2) + { + final PsiExpression condition1 = statement1.getCondition(); + final PsiExpression condition2 = statement2.getCondition(); + final PsiStatement thenBranch1 = statement1.getThenBranch(); + final PsiStatement thenBranch2 = statement2.getThenBranch(); + final PsiStatement elseBranch1 = statement1.getElseBranch(); + final PsiStatement elseBranch2 = statement2.getElseBranch(); + return expressionsAreEquivalent(condition1, condition2) && + statementsAreEquivalent(thenBranch1, thenBranch2) && + statementsAreEquivalent(elseBranch1, elseBranch2); + } + + private static boolean expressionStatementsAreEquivalent(PsiExpressionStatement statement1, + PsiExpressionStatement statement2) + { + final PsiExpression expression1 = statement1.getExpression(); + final PsiExpression expression2 = statement2.getExpression(); + return expressionsAreEquivalent(expression1, expression2); + } + + private static boolean returnStatementsAreEquivalent(PsiReturnStatement statement1, + PsiReturnStatement statement2) + { + final PsiExpression returnValue1 = statement1.getReturnValue(); + final PsiExpression returnValue2 = statement2.getReturnValue(); + return expressionsAreEquivalent(returnValue1, returnValue2); + } + + private static boolean throwStatementsAreEquivalent(PsiThrowStatement statement1, + PsiThrowStatement statement2) + { + final PsiExpression exception1 = statement1.getException(); + final PsiExpression exception2 = statement2.getException(); + return expressionsAreEquivalent(exception1, exception2); + } + + private static boolean expressionListStatementsAreEquivalent(PsiExpressionListStatement statement1, + PsiExpressionListStatement statement2) + { + final PsiExpressionList expressionList1 = statement1.getExpressionList(); + final PsiExpression[] expressions1 = expressionList1.getExpressions(); + final PsiExpressionList expressionList2 = statement2.getExpressionList(); + final PsiExpression[] expressions2 = expressionList2.getExpressions(); + return expressionListsAreEquivalent(expressions1, + expressions2); + } + + public static boolean expressionsAreEquivalent(PsiExpression exp1, PsiExpression exp2) + { + if(exp1 == null && exp2 == null) + { + return true; + } + if(exp1 == null || exp2 == null) + { + return false; + } + PsiExpression expToCompare1 = exp1; + while(expToCompare1 instanceof PsiParenthesizedExpression) + { + expToCompare1 = ((PsiParenthesizedExpression) expToCompare1).getExpression(); + } + PsiExpression expToCompare2 = exp2; + while(expToCompare2 instanceof PsiParenthesizedExpression) + { + expToCompare2 = ((PsiParenthesizedExpression) expToCompare2).getExpression(); + } + final int type1 = getExpressionType(expToCompare1); + final int type2 = getExpressionType(expToCompare2); + if(type1 != type2) + { + return false; + } + switch(type1) + { + case THIS_EXPRESSION: + case SUPER_EXPRESSION: + return true; + case LITERAL_EXPRESSION: + case CLASS_OBJECT_EXPRESSION: + case REFERENCE_EXPRESSION: + final String text1 = expToCompare1.getText(); + final String text2 = expToCompare2.getText(); + return text1.equals(text2); + case METHOD_CALL_EXPRESSION: + return methodCallExpressionsAreEquivalent((PsiMethodCallExpression) expToCompare1, + (PsiMethodCallExpression) expToCompare2); + case NEW_EXPRESSION: + return newExpressionsAreEquivalent((PsiNewExpression) expToCompare1, + (PsiNewExpression) expToCompare2); + case ARRAY_INITIALIZER_EXPRESSION: + return arrayInitializerExpressionsAreEquivalent((PsiArrayInitializerExpression) expToCompare1, + (PsiArrayInitializerExpression) expToCompare2); + case TYPECAST_EXPRESSION: + return typecastExpressionsAreEquivalent((PsiTypeCastExpression) expToCompare2, + (PsiTypeCastExpression) expToCompare1); + case ARRAY_ACCESS_EXPRESSION: + return arrayAccessExpressionsAreEquivalent((PsiArrayAccessExpression) expToCompare2, + (PsiArrayAccessExpression) expToCompare1); + case PREFIX_EXPRESSION: + return prefixExpressionsAreEquivalent((PsiPrefixExpression) expToCompare1, + (PsiPrefixExpression) expToCompare2); + case POSTFIX_EXPRESSION: + return postfixExpressionsAreEquivalent((PsiPostfixExpression) expToCompare1, + (PsiPostfixExpression) expToCompare2); + case BINARY_EXPRESSION: + return binaryExpressionsAreEquivalent((PsiBinaryExpression) expToCompare1, + (PsiBinaryExpression) expToCompare2); + case ASSIGNMENT_EXPRESSION: + return assignmentExpressionsAreEquivalent((PsiAssignmentExpression) expToCompare1, + (PsiAssignmentExpression) expToCompare2); + case CONDITIONAL_EXPRESSION: + return conditionalExpressionsAreEquivalent((PsiConditionalExpression) expToCompare1, + (PsiConditionalExpression) expToCompare2); + default: + return false; + } + } + + private static boolean methodCallExpressionsAreEquivalent(final PsiMethodCallExpression methodExp1, + final PsiMethodCallExpression methodExp2) + { + final PsiReferenceExpression methodExpression1 = methodExp1.getMethodExpression(); + final PsiReferenceExpression methodExpression2 = methodExp2.getMethodExpression(); + if(!expressionsAreEquivalent(methodExpression1, methodExpression2)) + { + return false; + } + final PsiExpressionList argumentList1 = methodExp1.getArgumentList(); + final PsiExpression[] args1 = argumentList1.getExpressions(); + final PsiExpressionList argumentList2 = methodExp2.getArgumentList(); + final PsiExpression[] args2 = argumentList2.getExpressions(); + return expressionListsAreEquivalent(args1, + args2); + } + + private static boolean newExpressionsAreEquivalent(final PsiNewExpression newExp1, final PsiNewExpression newExp2) + { + final PsiExpression[] arrayDimensions1 = newExp1.getArrayDimensions(); + final PsiExpression[] arrayDimensions2 = newExp2.getArrayDimensions(); + if(!expressionListsAreEquivalent(arrayDimensions1, arrayDimensions2)) + { + return false; + } + final PsiArrayInitializerExpression arrayInitializer1 = newExp1.getArrayInitializer(); + final PsiArrayInitializerExpression arrayInitializer2 = newExp2.getArrayInitializer(); + if(!expressionsAreEquivalent(arrayInitializer1, arrayInitializer2)) + { + return false; + } + final PsiExpression qualifier1 = newExp1.getQualifier(); + final PsiExpression qualifier2 = newExp2.getQualifier(); + if(!expressionsAreEquivalent(qualifier1, qualifier2)) + { + return false; + } + final PsiExpressionList argumentList1 = newExp1.getArgumentList(); + final PsiExpression[] args1 = argumentList1 == null ? null : argumentList1.getExpressions(); + final PsiExpressionList argumentList2 = newExp2.getArgumentList(); + final PsiExpression[] args2 = argumentList2 == null ? null : argumentList2.getExpressions(); + return expressionListsAreEquivalent(args1, args2); + } + + private static boolean arrayInitializerExpressionsAreEquivalent(final PsiArrayInitializerExpression arrInitExp1, + final PsiArrayInitializerExpression arrInitExp2) + { + final PsiExpression[] initializers1 = arrInitExp1.getInitializers(); + final PsiExpression[] initializers2 = arrInitExp2.getInitializers(); + return expressionListsAreEquivalent(initializers1, initializers2); + } + + private static boolean typecastExpressionsAreEquivalent(final PsiTypeCastExpression typecastExp2, + final PsiTypeCastExpression typecastExp1) + { + final PsiTypeElement castType2 = typecastExp2.getCastType(); + final PsiTypeElement castType1 = typecastExp1.getCastType(); + if(!castType2.equals(castType1)) + { + return false; + } + final PsiExpression operand1 = typecastExp1.getOperand(); + final PsiExpression operand2 = typecastExp2.getOperand(); + return expressionsAreEquivalent(operand1, operand2); + } + + private static boolean arrayAccessExpressionsAreEquivalent(final PsiArrayAccessExpression arrAccessExp2, + final PsiArrayAccessExpression arrAccessExp1) + { + final PsiExpression arrayExpression2 = arrAccessExp2.getArrayExpression(); + final PsiExpression arrayExpression1 = arrAccessExp1.getArrayExpression(); + final PsiExpression indexExpression2 = arrAccessExp2.getIndexExpression(); + final PsiExpression indexExpression1 = arrAccessExp1.getIndexExpression(); + return expressionsAreEquivalent(arrayExpression2, arrayExpression1) + && expressionsAreEquivalent(indexExpression2, indexExpression1); + } + + private static boolean prefixExpressionsAreEquivalent(final PsiPrefixExpression prefixExp1, + final PsiPrefixExpression prefixExp2) + { + final PsiJavaToken sign1 = prefixExp1.getOperationSign(); + final PsiJavaToken sign2 = prefixExp2.getOperationSign(); + if(sign1.getTokenType() != sign2.getTokenType()) + { + return false; + } + final PsiExpression operand1 = prefixExp1.getOperand(); + final PsiExpression operand2 = prefixExp2.getOperand(); + return expressionsAreEquivalent(operand1, operand2); + } + + private static boolean postfixExpressionsAreEquivalent(final PsiPostfixExpression postfixExp1, + final PsiPostfixExpression postfixExp2) + { + final PsiJavaToken sign1 = postfixExp1.getOperationSign(); + final PsiJavaToken sign2 = postfixExp2.getOperationSign(); + if(sign1.getTokenType()!=sign2.getTokenType()) + { + return false; + } + final PsiExpression operand1 = postfixExp1.getOperand(); + final PsiExpression operand2 = postfixExp2.getOperand(); + return expressionsAreEquivalent(operand1, operand2); + } + + private static boolean binaryExpressionsAreEquivalent(final PsiBinaryExpression binaryExp1, + final PsiBinaryExpression binaryExp2) + { + final PsiJavaToken sign1 = binaryExp1.getOperationSign(); + final PsiJavaToken sign2 = binaryExp2.getOperationSign(); + if(sign1.getTokenType() != sign2.getTokenType()) + { + return false; + } + final PsiExpression lhs1 = binaryExp1.getLOperand(); + final PsiExpression lhs2 = binaryExp2.getLOperand(); + final PsiExpression rhs1 = binaryExp1.getROperand(); + final PsiExpression rhs2 = binaryExp2.getROperand(); + return expressionsAreEquivalent(lhs1, lhs2) + && expressionsAreEquivalent(rhs1, rhs2); + } + + private static boolean assignmentExpressionsAreEquivalent(final PsiAssignmentExpression assignExp1, + final PsiAssignmentExpression assignExp2) + { + final PsiJavaToken sign1 = assignExp1.getOperationSign(); + final PsiJavaToken sign2 = assignExp2.getOperationSign(); + if(sign1.getTokenType() != sign2.getTokenType()) + { + return false; + } + final PsiExpression lhs1 = assignExp1.getLExpression(); + final PsiExpression lhs2 = assignExp2.getLExpression(); + final PsiExpression rhs1 = assignExp1.getRExpression(); + final PsiExpression rhs2 = assignExp2.getRExpression(); + return expressionsAreEquivalent(lhs1, lhs2) + && expressionsAreEquivalent(rhs1, rhs2); + } + + private static boolean conditionalExpressionsAreEquivalent(final PsiConditionalExpression condExp1, + final PsiConditionalExpression condExp2) + { + final PsiExpression condition1 = condExp1.getCondition(); + final PsiExpression condition2 = condExp2.getCondition(); + final PsiExpression thenExpression1 = condExp1.getThenExpression(); + final PsiExpression thenExpression2 = condExp2.getThenExpression(); + final PsiExpression elseExpression1 = condExp1.getElseExpression(); + final PsiExpression elseExpression2 = condExp2.getElseExpression(); + return expressionsAreEquivalent(condition1, condition2) + && expressionsAreEquivalent(thenExpression1, thenExpression2) + && expressionsAreEquivalent(elseExpression1, elseExpression2); + } + + private static boolean expressionListsAreEquivalent(PsiExpression[] expressions1, PsiExpression[] expressions2) + { + if(expressions1 == null && expressions2 == null) + { + return true; + } + if(expressions1 == null || expressions2 == null) + { + return false; + } + if(expressions1.length != expressions2.length) + { + return false; + } + for(int i = 0; i < expressions1.length; i++) + { + if(!expressionsAreEquivalent(expressions1[i], expressions2[i])) + { + return false; + } + } + return true; + } + + private static int getExpressionType(PsiExpression exp) + { + if(exp instanceof PsiThisExpression) + { + return THIS_EXPRESSION; + } + if(exp instanceof PsiLiteralExpression) + { + return LITERAL_EXPRESSION; + } + if(exp instanceof PsiClassObjectAccessExpression) + { + return CLASS_OBJECT_EXPRESSION; + } + if(exp instanceof PsiReferenceExpression) + { + return REFERENCE_EXPRESSION; + } + if(exp instanceof PsiSuperExpression) + { + return SUPER_EXPRESSION; + } + if(exp instanceof PsiMethodCallExpression) + { + return METHOD_CALL_EXPRESSION; + } + if(exp instanceof PsiNewExpression) + { + return NEW_EXPRESSION; + } + if(exp instanceof PsiArrayInitializerExpression) + { + return ARRAY_INITIALIZER_EXPRESSION; + } + if(exp instanceof PsiTypeCastExpression) + { + return TYPECAST_EXPRESSION; + } + if(exp instanceof PsiArrayAccessExpression) + { + return ARRAY_ACCESS_EXPRESSION; + } + if(exp instanceof PsiPrefixExpression) + { + return PREFIX_EXPRESSION; + } + if(exp instanceof PsiPostfixExpression) + { + return POSTFIX_EXPRESSION; + } + if(exp instanceof PsiBinaryExpression) + { + return BINARY_EXPRESSION; + } + if(exp instanceof PsiConditionalExpression) + { + return CONDITIONAL_EXPRESSION; + } + if(exp instanceof PsiAssignmentExpression) + { + return ASSIGNMENT_EXPRESSION; + } + return -1; + } + + private static int getStatementType(PsiStatement statement) + { + if(statement instanceof PsiAssertStatement) + { + return ASSERT_STATEMENT; + } + if(statement instanceof PsiBlockStatement) + { + return BLOCK_STATEMENT; + } + if(statement instanceof PsiBreakStatement) + { + return BREAK_STATEMENT; + } + if(statement instanceof PsiContinueStatement) + { + return CONTINUE_STATEMENT; + } + if(statement instanceof PsiDeclarationStatement) + { + return DECLARATION_STATEMENT; + } + if(statement instanceof PsiDoWhileStatement) + { + return DO_WHILE_STATEMENT; + } + if(statement instanceof PsiEmptyStatement) + { + return EMPTY_STATEMENT; + } + if(statement instanceof PsiExpressionListStatement) + { + return EXPRESSION_LIST_STATEMENT; + } + if(statement instanceof PsiExpressionStatement) + { + return EXPRESSION_STATEMENT; + } + if(statement instanceof PsiForStatement) + { + return FOR_STATEMENT; + } + if(statement instanceof PsiIfStatement) + { + return IF_STATEMENT; + } + if(statement instanceof PsiLabeledStatement) + { + return LABELED_STATEMENT; + } + if(statement instanceof PsiReturnStatement) + { + return RETURN_STATEMENT; + } + if(statement instanceof PsiSwitchLabelStatement) + { + return SWITCH_LABEL_STATEMENT; + } + if(statement instanceof PsiSwitchStatement) + { + return SWITCH_STATEMENT; + } + if(statement instanceof PsiSynchronizedStatement) + { + return SYNCHRONIZED_STATEMENT; + } + if(statement instanceof PsiThrowStatement) + { + return THROW_STATEMENT; + } + if(statement instanceof PsiTryStatement) + { + return TRY_STATEMENT; + } + if(statement instanceof PsiWhileStatement) + { + return WHILE_STATEMENT; + } + return -1; + } +} diff --git a/plugins/IntentionPowerPak/src/com/siyeh/ipp/psiutils/ParenthesesUtils.java b/plugins/IntentionPowerPak/src/com/siyeh/ipp/psiutils/ParenthesesUtils.java new file mode 100644 index 000000000000..f45eb06caea8 --- /dev/null +++ b/plugins/IntentionPowerPak/src/com/siyeh/ipp/psiutils/ParenthesesUtils.java @@ -0,0 +1,429 @@ +package com.siyeh.ipp.psiutils; + +import com.intellij.psi.*; +import com.intellij.psi.tree.IElementType; + +import java.util.HashMap; +import java.util.Map; + +public class ParenthesesUtils +{ + private static final int PARENTHESIZED_EXPRESSION_PRECEDENCE = 0; + private static final int LITERAL_PRECEDENCE = 0; + public static final int METHOD_CALL_PRECEDENCE = 1; + + private static final int POSTFIX_PRECEDENCE = 2; + public static final int PREFIX_PRECEDENCE = 3; + private static final int TYPE_CAST_PRECEDENCE = 4; + private static final int MULTIPLICATIVE_PRECEDENCE = 5; + private static final int ADDITIVE_PRECEDENCE = 6; + private static final int SHIFT_PRECEDENCE = 7; + private static final int RELATIONAL_PRECEDENCE = 8; + public static final int EQUALITY_PRECEDENCE = 9; + + private static final int BINARY_AND_PRECEDENCE = 10; + private static final int BINARY_XOR_PRECEDENCE = 11; + private static final int BINARY_OR_PRECEDENCE = 12; + public static final int AND_PRECEDENCE = 13; + public static final int OR_PRECEDENCE = 14; + public static final int CONDITIONAL_EXPRESSION_EXPRESSION = 15; + private static final int ASSIGNMENT_EXPRESSION_PRECEDENCE = 16; + + private static final Map s_binaryOperatorPrecedence = new HashMap(16); + + static + { + s_binaryOperatorPrecedence.put("+", new Integer(ADDITIVE_PRECEDENCE)); + s_binaryOperatorPrecedence.put("-", new Integer(ADDITIVE_PRECEDENCE)); + s_binaryOperatorPrecedence.put("*", new Integer(MULTIPLICATIVE_PRECEDENCE)); + s_binaryOperatorPrecedence.put("/", new Integer(MULTIPLICATIVE_PRECEDENCE)); + s_binaryOperatorPrecedence.put("%", new Integer(MULTIPLICATIVE_PRECEDENCE)); + s_binaryOperatorPrecedence.put("&&", new Integer(AND_PRECEDENCE)); + s_binaryOperatorPrecedence.put("||", new Integer(OR_PRECEDENCE)); + s_binaryOperatorPrecedence.put("&", new Integer(BINARY_AND_PRECEDENCE)); + s_binaryOperatorPrecedence.put("|", new Integer(BINARY_OR_PRECEDENCE)); + s_binaryOperatorPrecedence.put("^", new Integer(BINARY_XOR_PRECEDENCE)); + s_binaryOperatorPrecedence.put("<<", new Integer(SHIFT_PRECEDENCE)); + s_binaryOperatorPrecedence.put(">>", new Integer(SHIFT_PRECEDENCE)); + s_binaryOperatorPrecedence.put(">>>", new Integer(SHIFT_PRECEDENCE)); + s_binaryOperatorPrecedence.put(">", new Integer(RELATIONAL_PRECEDENCE)); + s_binaryOperatorPrecedence.put(">=", new Integer(RELATIONAL_PRECEDENCE)); + s_binaryOperatorPrecedence.put("<", new Integer(RELATIONAL_PRECEDENCE)); + s_binaryOperatorPrecedence.put("<=", new Integer(RELATIONAL_PRECEDENCE)); + s_binaryOperatorPrecedence.put("==", new Integer(EQUALITY_PRECEDENCE)); + s_binaryOperatorPrecedence.put("!=", new Integer(EQUALITY_PRECEDENCE)); + } + + private ParenthesesUtils() + { + super(); + } + + public static PsiExpression stripParentheses(PsiExpression exp) + { + PsiExpression parenthesized = exp; + while(parenthesized instanceof PsiParenthesizedExpression) + { + parenthesized = ((PsiParenthesizedExpression) parenthesized).getExpression(); + } + return parenthesized; + } + + public static int getPrecendence(PsiExpression exp) + { + + if(exp instanceof PsiThisExpression || + exp instanceof PsiLiteralExpression || + exp instanceof PsiSuperExpression || + exp instanceof PsiReferenceExpression || + exp instanceof PsiClassObjectAccessExpression || + exp instanceof PsiArrayAccessExpression || + exp instanceof PsiArrayInitializerExpression) + { + return LITERAL_PRECEDENCE; + } + if(exp instanceof PsiMethodCallExpression) + { + return METHOD_CALL_PRECEDENCE; + } + if(exp instanceof PsiTypeCastExpression || + exp instanceof PsiNewExpression) + { + return TYPE_CAST_PRECEDENCE; + } + if(exp instanceof PsiPrefixExpression) + { + return PREFIX_PRECEDENCE; + } + if(exp instanceof PsiPostfixExpression) + { + return POSTFIX_PRECEDENCE; + } + if(exp instanceof PsiBinaryExpression) + { + final PsiBinaryExpression binaryExpression = (PsiBinaryExpression) exp; + final PsiJavaToken sign = binaryExpression.getOperationSign(); + return precedenceForBinaryOperator(sign); + } + if(exp instanceof PsiInstanceOfExpression) + { + return RELATIONAL_PRECEDENCE; + } + if(exp instanceof PsiConditionalExpression) + { + return CONDITIONAL_EXPRESSION_EXPRESSION; + } + if(exp instanceof PsiAssignmentExpression) + { + return ASSIGNMENT_EXPRESSION_PRECEDENCE; + } + if(exp instanceof PsiParenthesizedExpression) + { + return PARENTHESIZED_EXPRESSION_PRECEDENCE; + } + return -1; + } + + private static int precedenceForBinaryOperator(PsiJavaToken sign) + { + final String operator = sign.getText(); + final Integer precedence = (Integer) s_binaryOperatorPrecedence.get(operator); + return precedence.intValue(); + } + + public static String removeParentheses(PsiExpression exp) + { + if(exp instanceof PsiThisExpression || + exp instanceof PsiLiteralExpression || + exp instanceof PsiClassObjectAccessExpression || + exp instanceof PsiReferenceExpression || + exp instanceof PsiSuperExpression) + { + return exp.getText(); + } + else if(exp instanceof PsiMethodCallExpression) + { + return removeParenthesesForMethodCall((PsiMethodCallExpression)exp); + + } + else if(exp instanceof PsiNewExpression) + { + return removeParenthesesForNewExpression((PsiNewExpression)exp); + + } + else if(exp instanceof PsiAssignmentExpression) + { + return removeParenthesesForAssignment((PsiAssignmentExpression)exp); + } + else if(exp instanceof PsiArrayInitializerExpression) + { + return removeParenthesesForArrayInitializer((PsiArrayInitializerExpression)exp); + } + else if(exp instanceof PsiTypeCastExpression) + { + return removeParenthesesForTypeCast((PsiTypeCastExpression)exp); + } + else if(exp instanceof PsiArrayAccessExpression) + { + return removeParenthesesForArrayAccess((PsiArrayAccessExpression)exp); + } + else if(exp instanceof PsiPrefixExpression) + { + return removeParenthesesForPrefixExpression((PsiPrefixExpression)exp); + } + else if(exp instanceof PsiPostfixExpression) + { + return removeParenthesesForPostfixExpression((PsiPostfixExpression)exp); + } + else if(exp instanceof PsiBinaryExpression) + { + return removeParenthesesForBinaryExpression((PsiBinaryExpression)exp); + } + else if(exp instanceof PsiInstanceOfExpression) + { + return removeParenthesesForInstanceofExpression((PsiInstanceOfExpression)exp); + + } + else if(exp instanceof PsiConditionalExpression) + { + return removeParenthesesForConditionalExpression((PsiConditionalExpression)exp); + } + else if(exp instanceof PsiParenthesizedExpression) + { + return removeParensFromParenthesizedExpression((PsiParenthesizedExpression) exp); + } + return exp.getText(); // this shouldn't happen + } + + + + private static String removeParensFromParenthesizedExpression( + PsiParenthesizedExpression parenthesizedExp){ + PsiExpression body = parenthesizedExp.getExpression(); + while(body instanceof PsiParenthesizedExpression){ + body = ((PsiParenthesizedExpression) body).getExpression(); + } + if(!(parenthesizedExp.getParent() instanceof PsiExpression)){ + return removeParentheses(body); + } + final PsiExpression parentExp = (PsiExpression) parenthesizedExp.getParent(); + final int parentPrecedence = getPrecendence(parentExp); + final int childPrecedence = getPrecendence(body); + if(parentPrecedence < childPrecedence){ + return '(' + removeParentheses(body) + ')'; + } else if(parentPrecedence == childPrecedence){ + if(parentExp instanceof PsiBinaryExpression && + body instanceof PsiBinaryExpression){ + final IElementType parentOperator = ((PsiBinaryExpression) parentExp).getOperationSign() + .getTokenType(); + final IElementType bodyOperator = ((PsiBinaryExpression) body).getOperationSign() + .getTokenType(); + + final PsiExpression lhs = ((PsiBinaryExpression) parentExp).getLOperand(); + + if(lhs.equals(parenthesizedExp) && + parentOperator == bodyOperator){ + return removeParentheses(body); + } else{ + return '(' + removeParentheses(body) + ')'; + } + } else{ + return removeParentheses(body); + } + } else{ + return removeParentheses(body); + } + } + + private static String removeParenthesesForConditionalExpression(PsiConditionalExpression conditionalExp) + { + final PsiExpression condition = conditionalExp.getCondition(); + final PsiExpression thenBranch = conditionalExp.getThenExpression(); + final PsiExpression elseBranch = conditionalExp.getElseExpression(); + return removeParentheses(condition) + '?' + + removeParentheses(thenBranch) + ':' + + removeParentheses(elseBranch); + } + + private static String removeParenthesesForInstanceofExpression(PsiInstanceOfExpression instanceofExp) + { + final PsiExpression body = instanceofExp.getOperand(); + + final PsiTypeElement checkType = instanceofExp.getCheckType(); + return removeParentheses(body) + " instanceof " + checkType.getText(); + } + + private static String removeParenthesesForBinaryExpression(PsiBinaryExpression binaryExp) + { + final PsiExpression lhs = binaryExp.getLOperand(); + final PsiExpression rhs = binaryExp.getROperand(); + final PsiJavaToken sign = binaryExp.getOperationSign(); + return removeParentheses(lhs) + sign.getText() + + removeParentheses(rhs); + } + + private static String removeParenthesesForPostfixExpression(PsiPostfixExpression postfixExp) + { + final PsiExpression body = postfixExp.getOperand(); + final PsiJavaToken sign = postfixExp.getOperationSign(); + final String operand = sign.getText(); + return removeParentheses(body) + operand; + } + + private static String removeParenthesesForPrefixExpression(PsiPrefixExpression prefixExp) + { + final PsiExpression body = prefixExp.getOperand(); + final PsiJavaToken sign = prefixExp.getOperationSign(); + final String operand = sign.getText(); + return operand + removeParentheses(body); + } + + private static String removeParenthesesForArrayAccess(PsiArrayAccessExpression arrayAccessExp) + { + final PsiExpression arrayExp = arrayAccessExp.getArrayExpression(); + final PsiExpression indexExp = arrayAccessExp.getIndexExpression(); + return removeParentheses(arrayExp) + '[' + removeParentheses(indexExp) + ']'; + } + + private static String removeParenthesesForTypeCast(PsiTypeCastExpression typeCast) + { + final PsiExpression body = typeCast.getOperand(); + final PsiTypeElement type = typeCast.getCastType(); + return '(' + type.getText() + ')' + removeParentheses(body); + } + + private static String removeParenthesesForArrayInitializer(PsiArrayInitializerExpression init) + { + final PsiExpression[] contents = init.getInitializers(); + final String text = init.getText(); + final int originalLength = text.length(); + final StringBuffer out = new StringBuffer(originalLength); + out.append("{"); + for(int i = 0; i < contents.length; i++) + { + final PsiExpression arg = contents[i]; + if(i != 0) + { + out.append(","); + } + final String strippedArg = removeParentheses(arg); + out.append(strippedArg); + } + out.append("}"); + return out.toString(); + } + + private static String removeParenthesesForAssignment(PsiAssignmentExpression assignment) + { + final PsiExpression lhs = assignment.getLExpression(); + final PsiExpression rhs = assignment.getRExpression(); + final PsiJavaToken sign = assignment.getOperationSign(); + return removeParentheses(lhs) + sign.getText() + removeParentheses(rhs); + } + + private static String removeParenthesesForNewExpression(PsiNewExpression newExp) + { + final PsiExpression[] dimensions = newExp.getArrayDimensions(); + String[] strippedDimensions = null; + if(dimensions != null) + { + strippedDimensions = new String[dimensions.length]; + for(int i = 0; i < dimensions.length; i++) + { + strippedDimensions[i] = removeParentheses(dimensions[i]); + } + } + + final PsiExpression qualifier = newExp.getQualifier(); + final PsiExpression arrayInitializer = newExp.getArrayInitializer(); + String strippedArrayInitializer = null; + if(arrayInitializer != null) + { + strippedArrayInitializer = removeParentheses(arrayInitializer); + } + + final PsiExpressionList argumentList = newExp.getArgumentList(); + final PsiExpression[] args = argumentList == null ? null : argumentList.getExpressions(); + String[] strippedArgs = null; + if(args != null) + { + strippedArgs = new String[args.length]; + for(int i = 0; i < args.length; i++) + { + strippedArgs[i] = removeParentheses(args[i]); + } + } + if(qualifier != null) + { + return newExp.getText(); + } + final PsiElement[] children = newExp.getChildren(); + for(int i = 0; i < children.length; i++) + { + final PsiElement child = children[i]; + if(child instanceof PsiAnonymousClass) + { + return newExp.getText(); + } + } + final StringBuffer out = new StringBuffer(128); + out.append("new "); + final PsiJavaCodeReferenceElement classReference = newExp.getClassReference(); + final String classReferenceText = classReference.getText(); + out.append(classReferenceText); + if(strippedArgs != null) + { + out.append("("); + for(int i = 0; i < strippedArgs.length; i++) + { + if(i != 0) + { + out.append(","); + } + out.append(strippedArgs[i]); + } + out.append(")"); + } + + if(strippedDimensions != null) + { + for(int i = 0; i < strippedDimensions.length; i++) + { + out.append("["); + out.append(strippedDimensions[i]); + out.append("]"); + } + } + if(strippedArrayInitializer != null) + { + out.append(strippedArrayInitializer); + } + return out.toString(); + } + + private static String removeParenthesesForMethodCall(PsiMethodCallExpression methCall) + { + final PsiReferenceExpression target = methCall.getMethodExpression(); + final PsiExpressionList argumentList = methCall.getArgumentList(); + final PsiExpression[] args = argumentList.getExpressions(); + + final String text = methCall.getText(); + final int length = text.length(); + final StringBuffer out = new StringBuffer(length); + final String strippedTarget = removeParentheses(target); + out.append(strippedTarget); + out.append("("); + for(int i = 0; i < args.length; i++) + { + final PsiExpression arg = args[i]; + if(i != 0) + { + out.append(","); + } + final String strippedArg = removeParentheses(arg); + out.append(strippedArg); + } + out.append(")"); + return out.toString(); + } +} diff --git a/plugins/IntentionPowerPak/src/com/siyeh/ipp/psiutils/SideEffectChecker.java b/plugins/IntentionPowerPak/src/com/siyeh/ipp/psiutils/SideEffectChecker.java new file mode 100644 index 000000000000..b89a3f661ac1 --- /dev/null +++ b/plugins/IntentionPowerPak/src/com/siyeh/ipp/psiutils/SideEffectChecker.java @@ -0,0 +1,96 @@ +package com.siyeh.ipp.psiutils; + +import com.intellij.psi.*; +import com.intellij.psi.tree.IElementType; + +public class SideEffectChecker +{ + private SideEffectChecker() + { + super(); + } + + public static boolean mayHaveSideEffects(PsiExpression exp) + { + if(exp instanceof PsiThisExpression || + exp instanceof PsiLiteralExpression || + exp instanceof PsiClassObjectAccessExpression || + exp instanceof PsiReferenceExpression || + exp instanceof PsiSuperExpression) + { + return false; + } + else if(exp instanceof PsiMethodCallExpression || + exp instanceof PsiNewExpression || + exp instanceof PsiAssignmentExpression || + exp instanceof PsiArrayInitializerExpression) + { + return true; + } + else if(exp instanceof PsiTypeCastExpression) + { + final PsiExpression body = ((PsiTypeCastExpression) exp).getOperand(); + return mayHaveSideEffects(body); + } + else if(exp instanceof PsiArrayAccessExpression) + { + final PsiArrayAccessExpression arrayAccessExp = (PsiArrayAccessExpression) exp; + final PsiExpression arrayExp = arrayAccessExp.getArrayExpression(); + final PsiExpression indexExp = arrayAccessExp.getIndexExpression(); + return mayHaveSideEffects(arrayExp) || mayHaveSideEffects(indexExp); + } + else if(exp instanceof PsiPrefixExpression) + { + final PsiPrefixExpression prefixExp = (PsiPrefixExpression) exp; + final PsiExpression body = prefixExp.getOperand(); + if(mayHaveSideEffects(body)) + { + return true; + } + final PsiJavaToken sign = prefixExp.getOperationSign(); + final IElementType tokenType = sign.getTokenType(); + return tokenType == JavaTokenType.PLUSPLUS || tokenType == JavaTokenType.MINUSMINUS; + } + else if(exp instanceof PsiPostfixExpression) + { + final PsiPostfixExpression postfixExp = (PsiPostfixExpression) exp; + final PsiExpression body = postfixExp.getOperand(); + if(mayHaveSideEffects(body)) + { + return true; + } + final PsiJavaToken sign = postfixExp.getOperationSign(); + final IElementType tokenType = sign.getTokenType(); + return tokenType == JavaTokenType.PLUSPLUS || tokenType == JavaTokenType.MINUSMINUS; + } + else if(exp instanceof PsiBinaryExpression) + { + final PsiBinaryExpression binaryExp = (PsiBinaryExpression) exp; + final PsiExpression lhs = binaryExp.getLOperand(); + final PsiExpression rhs = binaryExp.getROperand(); + return mayHaveSideEffects(lhs) || + mayHaveSideEffects(rhs); + } + else if(exp instanceof PsiInstanceOfExpression) + { + final PsiExpression body = ((PsiInstanceOfExpression) exp).getOperand(); + return mayHaveSideEffects(body); + } + else if(exp instanceof PsiConditionalExpression) + { + final PsiConditionalExpression conditionalExp = (PsiConditionalExpression) exp; + final PsiExpression condition = conditionalExp.getCondition(); + final PsiExpression thenBranch = conditionalExp.getThenExpression(); + final PsiExpression elseBranch = conditionalExp.getElseExpression(); + return mayHaveSideEffects(condition) || + mayHaveSideEffects(thenBranch) || + mayHaveSideEffects(elseBranch); + } + else if(exp instanceof PsiParenthesizedExpression) + { + final PsiExpression body = ((PsiParenthesizedExpression) exp).getExpression(); + return mayHaveSideEffects(body); + } + return true; // this shouldn't happen + } +} diff --git a/plugins/IntentionPowerPak/src/com/siyeh/ipp/shift/MultiplyByPowerOfTwoPredicate.java b/plugins/IntentionPowerPak/src/com/siyeh/ipp/shift/MultiplyByPowerOfTwoPredicate.java new file mode 100644 index 000000000000..1b352858671e --- /dev/null +++ b/plugins/IntentionPowerPak/src/com/siyeh/ipp/shift/MultiplyByPowerOfTwoPredicate.java @@ -0,0 +1,65 @@ +package com.siyeh.ipp.shift; + +import com.intellij.psi.*; +import com.intellij.psi.tree.IElementType; +import com.siyeh.ipp.PsiElementPredicate; + +class MultiplyByPowerOfTwoPredicate implements PsiElementPredicate { + public boolean satisfiedBy(PsiElement element) { + if (element instanceof PsiBinaryExpression) { + return binaryExpressionIsMultiplyByPowerOfTwo((PsiBinaryExpression) element); + } else if (element instanceof PsiAssignmentExpression) { + return assignmentExpressionIsMultiplyByPowerOfTwo((PsiAssignmentExpression) element); + } else { + return false; + } + } + + private boolean assignmentExpressionIsMultiplyByPowerOfTwo(PsiAssignmentExpression expression) { + final PsiJavaToken sign = expression.getOperationSign(); + final IElementType tokenType = sign.getTokenType(); + if (!tokenType.equals(JavaTokenType.ASTERISKEQ) && !tokenType.equals(JavaTokenType.DIVEQ)) { + return false; + } + final PsiExpression lhs = expression.getLExpression(); + if (lhs == null) { + return false; + } + final PsiType lhsType = lhs.getType(); + if (lhsType == null) { + return false; + } + if (!ShiftUtils.isIntegral(lhsType)) { + return false; + } + final PsiExpression rhs = expression.getRExpression(); + if (rhs == null) { + return false; + } + return ShiftUtils.isPowerOfTwo(rhs); + } + + private boolean binaryExpressionIsMultiplyByPowerOfTwo(PsiBinaryExpression expression) { + final PsiJavaToken sign = expression.getOperationSign(); + final IElementType tokenType = sign.getTokenType(); + if (!tokenType.equals(JavaTokenType.ASTERISK) && !tokenType.equals(JavaTokenType.DIV)) { + return false; + } + final PsiExpression lhs = expression.getLOperand(); + if (lhs == null) { + return false; + } + final PsiType lhsType = lhs.getType(); + if (lhsType == null) { + return false; + } + if (!ShiftUtils.isIntegral(lhsType)) { + return false; + } + final PsiExpression rhs = expression.getROperand(); + if (rhs == null) { + return false; + } + return ShiftUtils.isPowerOfTwo(rhs); + } +} diff --git a/plugins/IntentionPowerPak/src/com/siyeh/ipp/shift/ReplaceMultiplyWithShiftIntention.java b/plugins/IntentionPowerPak/src/com/siyeh/ipp/shift/ReplaceMultiplyWithShiftIntention.java new file mode 100644 index 000000000000..c82af89f46e0 --- /dev/null +++ b/plugins/IntentionPowerPak/src/com/siyeh/ipp/shift/ReplaceMultiplyWithShiftIntention.java @@ -0,0 +1,86 @@ +package com.siyeh.ipp.shift; + +import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.project.Project; +import com.intellij.psi.*; +import com.intellij.psi.tree.IElementType; +import com.intellij.util.IncorrectOperationException; +import com.siyeh.ipp.*; + +public class ReplaceMultiplyWithShiftIntention extends MutablyNamedIntention { + public ReplaceMultiplyWithShiftIntention(Project project) { + super(project); + } + + protected String getTextForElement(PsiElement element) { + if (element instanceof PsiBinaryExpression) { + final PsiBinaryExpression exp = (PsiBinaryExpression) element; + final PsiJavaToken sign = exp.getOperationSign(); + final IElementType tokenType = sign.getTokenType(); + final String operatorString; + if (tokenType.equals(JavaTokenType.ASTERISK)) { + operatorString = "<<"; + } else { + operatorString = ">>"; + } + return "Replace " + sign.getText() + " with " + operatorString; + } else { + final PsiAssignmentExpression exp = (PsiAssignmentExpression) element; + final PsiJavaToken sign = exp.getOperationSign(); + final IElementType tokenType = sign.getTokenType(); + final String assignString; + if (tokenType.equals(JavaTokenType.ASTERISKEQ)) { + assignString = "<<="; + } else { + assignString = ">>="; + } + return "Replace " + sign.getText() + " with " + assignString; + + } + } + + public String getFamilyName() { + return "Replace Multiply with Shift"; + } + + public PsiElementPredicate getElementPredicate() { + return new MultiplyByPowerOfTwoPredicate(); + } + + + public void invoke(Project project, Editor editor, PsiFile file) throws IncorrectOperationException { + final PsiElement matchingElement = findMatchingElement(file, editor); + if (matchingElement instanceof PsiBinaryExpression) { + final PsiBinaryExpression exp = + (PsiBinaryExpression) matchingElement; + final PsiExpression lhs = exp.getLOperand(); + final PsiExpression rhs = exp.getROperand(); + final PsiJavaToken sign = exp.getOperationSign(); + final IElementType tokenType = sign.getTokenType(); + final String operatorString; + if (tokenType.equals(JavaTokenType.ASTERISK)) { + operatorString = "<<"; + } else { + operatorString = ">>"; + } + final String expString = lhs.getText() + operatorString + ShiftUtils.getLogBase2(rhs); + replaceExpression(project, expString, exp); + } else { + final PsiAssignmentExpression exp = + (PsiAssignmentExpression) findMatchingElement(file, editor); + final PsiExpression lhs = exp.getLExpression(); + final PsiExpression rhs = exp.getRExpression(); + final PsiJavaToken sign = exp.getOperationSign(); + final IElementType tokenType = sign.getTokenType(); + final String assignString; + if (tokenType.equals(JavaTokenType.ASTERISKEQ)) { + assignString = "<<="; + } else { + assignString = ">>="; + } + final String expString = lhs.getText() + assignString + ShiftUtils.getLogBase2(rhs); + replaceExpression(project, expString, exp); + } + + } +} diff --git a/plugins/IntentionPowerPak/src/com/siyeh/ipp/shift/ReplaceShiftWithMultiplyIntention.java b/plugins/IntentionPowerPak/src/com/siyeh/ipp/shift/ReplaceShiftWithMultiplyIntention.java new file mode 100644 index 000000000000..961942101018 --- /dev/null +++ b/plugins/IntentionPowerPak/src/com/siyeh/ipp/shift/ReplaceShiftWithMultiplyIntention.java @@ -0,0 +1,84 @@ +package com.siyeh.ipp.shift; + +import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.project.Project; +import com.intellij.psi.*; +import com.intellij.psi.tree.IElementType; +import com.intellij.util.IncorrectOperationException; +import com.siyeh.ipp.*; + +public class ReplaceShiftWithMultiplyIntention extends MutablyNamedIntention { + public ReplaceShiftWithMultiplyIntention(Project project) { + super(project); + } + + protected String getTextForElement(PsiElement element) { + if (element instanceof PsiBinaryExpression) { + final PsiBinaryExpression exp = (PsiBinaryExpression) element; + final PsiJavaToken sign = exp.getOperationSign(); + final IElementType tokenType = sign.getTokenType(); + final String operatorString; + if (tokenType.equals(JavaTokenType.LTLT)) { + operatorString = "*"; + } else { + operatorString = "/"; + } + return "Replace " + sign.getText() + " with " + operatorString; + } else { + final PsiAssignmentExpression exp = (PsiAssignmentExpression) element; + final PsiJavaToken sign = exp.getOperationSign(); + final IElementType tokenType = sign.getTokenType(); + final String assignString; + if (tokenType == JavaTokenType.LTLTEQ) { + assignString = "*="; + } else { + assignString = "/="; + } + return "Replace " + sign.getText() + " with " + assignString; + } + } + + public String getFamilyName() { + return "Replace Shift with Multiply"; + } + + public PsiElementPredicate getElementPredicate() { + return new ShiftByLiteralPredicate(); + } + + public void invoke(Project project, Editor editor, PsiFile file) throws IncorrectOperationException { + final PsiElement element = findMatchingElement(file, editor); + if (element instanceof PsiBinaryExpression) { + final PsiBinaryExpression exp = + (PsiBinaryExpression) element; + final PsiExpression lhs = exp.getLOperand(); + final PsiExpression rhs = exp.getROperand(); + final PsiJavaToken sign = exp.getOperationSign(); + final IElementType tokenType = sign.getTokenType(); + final String operatorString; + if (tokenType.equals(JavaTokenType.LTLT)) { + operatorString = "*"; + } else { + operatorString = "/"; + } + final String expString = lhs.getText() + operatorString + ShiftUtils.getExpBase2(rhs); + replaceExpression(project, expString, exp); + } else { + final PsiAssignmentExpression exp = + (PsiAssignmentExpression) element; + final PsiExpression lhs = exp.getLExpression(); + final PsiExpression rhs = exp.getRExpression(); + final PsiJavaToken sign = exp.getOperationSign(); + final IElementType tokenType = sign.getTokenType(); + final String assignString; + if (tokenType.equals(JavaTokenType.LTLTEQ)) { + assignString = "*="; + } else { + assignString = "/="; + } + final String expString = lhs.getText() + assignString + ShiftUtils.getExpBase2(rhs); + replaceExpression(project, expString, exp); + } + + } +} diff --git a/plugins/IntentionPowerPak/src/com/siyeh/ipp/shift/ShiftByLiteralPredicate.java b/plugins/IntentionPowerPak/src/com/siyeh/ipp/shift/ShiftByLiteralPredicate.java new file mode 100644 index 000000000000..68d772bc204a --- /dev/null +++ b/plugins/IntentionPowerPak/src/com/siyeh/ipp/shift/ShiftByLiteralPredicate.java @@ -0,0 +1,58 @@ +package com.siyeh.ipp.shift; + +import com.intellij.psi.*; +import com.intellij.psi.tree.IElementType; +import com.siyeh.ipp.PsiElementPredicate; + +class ShiftByLiteralPredicate implements PsiElementPredicate +{ + public boolean satisfiedBy(PsiElement element) + { + if (element instanceof PsiBinaryExpression) { + return isBinaryShiftByLiteral((PsiBinaryExpression) element); + } if (element instanceof PsiAssignmentExpression) { + return isAssignmentShiftByLiteral((PsiAssignmentExpression) element); + } else { + return false; + } + } + + private boolean isAssignmentShiftByLiteral(PsiAssignmentExpression expression) { + final PsiJavaToken sign = expression.getOperationSign(); + final IElementType tokenType = sign.getTokenType(); + if (!tokenType.equals(JavaTokenType.LTLTEQ) && !tokenType.equals(JavaTokenType.GTGTEQ)) { + return false; + } + final PsiExpression lhs = expression.getLExpression(); + if (lhs == null) { + return false; + } + final PsiType lhsType = lhs.getType(); + if (lhsType == null) { + return false; + } + if (!ShiftUtils.isIntegral(lhsType)) { + return false; + } + final PsiExpression rhs = expression.getRExpression(); + if (rhs == null) { + return false; + } + return ShiftUtils.isIntLiteral(rhs); + } + + private boolean isBinaryShiftByLiteral(PsiBinaryExpression expression) { + final PsiJavaToken sign = expression.getOperationSign(); + final IElementType tokenType = sign.getTokenType(); + if (!tokenType.equals(JavaTokenType.LTLT) && !tokenType.equals(JavaTokenType.GTGT)) { + return false; + } + final PsiExpression lOperand = expression.getLOperand(); + final PsiType lhsType = lOperand.getType(); + if (!ShiftUtils.isIntegral(lhsType)) { + return false; + } + final PsiExpression rhs = expression.getROperand(); + return ShiftUtils.isIntLiteral(rhs); + } +} diff --git a/plugins/IntentionPowerPak/src/com/siyeh/ipp/shift/ShiftUtils.java b/plugins/IntentionPowerPak/src/com/siyeh/ipp/shift/ShiftUtils.java new file mode 100644 index 000000000000..b15aebfbe86a --- /dev/null +++ b/plugins/IntentionPowerPak/src/com/siyeh/ipp/shift/ShiftUtils.java @@ -0,0 +1,94 @@ +package com.siyeh.ipp.shift; + +import com.intellij.psi.*; + +class ShiftUtils +{ + private ShiftUtils() + { + super(); + } + + public static boolean isPowerOfTwo(PsiExpression rhs) + { + if(!(rhs instanceof PsiLiteralExpression)) + { + return false; + } + final PsiLiteralExpression literal = (PsiLiteralExpression) rhs; + final Object value = literal.getValue(); + if(!(value instanceof Number)) + { + return false; + } + if(value instanceof Double || value instanceof Float) + { + return false; + } + int intValue = ((Number) value).intValue(); + if(intValue <= 0) + { + return false; + } + while(intValue % 2 == 0) + { + intValue >>= 1; + } + return intValue == 1; + } + + public static int getLogBase2(PsiExpression rhs) + { + final PsiLiteralExpression literal = (PsiLiteralExpression) rhs; + final Object value = literal.getValue(); + int intValue = ((Number) value).intValue(); + int log = 0; + while(intValue % 2 == 0) + { + intValue >>= 1; + log++; + } + return log; + } + + public static int getExpBase2(PsiExpression rhs) + { + final PsiLiteralExpression literal = (PsiLiteralExpression) rhs; + final Object value = literal.getValue(); + final int intValue = ((Number) value).intValue(); + int exp = 1; + for(int i = 0; i < intValue; i++) + { + exp <<= 1; + } + return exp; + } + + public static boolean isIntegral(final PsiType lhsType) + { + return lhsType!=null && + (lhsType.equals(PsiType.INT) + || lhsType.equals(PsiType.SHORT) + || lhsType.equals(PsiType.LONG) + || lhsType.equals(PsiType.BYTE)); + } + + public static boolean isIntLiteral(PsiExpression rhs) + { + if(!(rhs instanceof PsiLiteralExpression)) + { + return false; + } + final PsiLiteralExpression literal = (PsiLiteralExpression) rhs; + final Object value = literal.getValue(); + if(!(value instanceof Number)) + { + return false; + } + if(value instanceof Double || value instanceof Float) + { + return false; + } + return true; + } +} diff --git a/plugins/IntentionPowerPak/src/com/siyeh/ipp/switchtoif/CaseUtil.java b/plugins/IntentionPowerPak/src/com/siyeh/ipp/switchtoif/CaseUtil.java new file mode 100644 index 000000000000..121e6ec0ae12 --- /dev/null +++ b/plugins/IntentionPowerPak/src/com/siyeh/ipp/switchtoif/CaseUtil.java @@ -0,0 +1,251 @@ +package com.siyeh.ipp.switchtoif; + +import com.intellij.psi.*; +import com.intellij.psi.tree.IElementType; +import com.intellij.psi.util.PsiUtil; +import com.siyeh.ipp.psiutils.EquivalenceChecker; +import com.siyeh.ipp.psiutils.SideEffectChecker; + +import java.util.*; + +class CaseUtil +{ + private CaseUtil() + { + super(); + } + + private static boolean canBeCaseLabel(PsiExpression expression) + { + if (expression == null) { + return false; + } + final PsiType type = expression.getType(); + if(type == null) + { + return false; + } + if(!type.equals(PsiType.INT) && + !type.equals(PsiType.CHAR) && + !type.equals(PsiType.LONG) && + !type.equals(PsiType.SHORT)) + { + return false; + } + return PsiUtil.isConstantExpression(expression); + } + + public static boolean containsHiddenBreak(PsiStatement statement) + { + return containsHiddenBreak(statement, true); + } + + private static boolean containsHiddenBreak(PsiStatement statement, boolean isTopLevel) + { + if(statement instanceof PsiBlockStatement) + { + final PsiCodeBlock codeBlock = ((PsiBlockStatement) statement).getCodeBlock(); + final PsiStatement[] statements = codeBlock.getStatements(); + for(int i = 0; i < statements.length; i++) + { + final PsiStatement childStatement = statements[i]; + if(containsHiddenBreak(childStatement, false)) + { + return true; + } + } + } + else if(statement instanceof PsiIfStatement) + { + final PsiIfStatement ifStatement = (PsiIfStatement) statement; + final PsiStatement thenBranch = ifStatement.getThenBranch(); + final PsiStatement elseBranch = ifStatement.getElseBranch(); + return containsHiddenBreak(thenBranch, false) || + containsHiddenBreak(elseBranch, false); + } + else if(statement instanceof PsiBreakStatement) + { + if(isTopLevel) + { + return false; + } + final PsiIdentifier identifier = ((PsiBreakStatement) statement).getLabelIdentifier(); + if(identifier == null) + { + return true; + } + final String text = identifier.getText(); + return "".equals(text); + } + return false; + } + + public static boolean isUsedByStatementList(PsiLocalVariable var, List statements) + { + for(Iterator iterator = statements.iterator(); iterator.hasNext();) + { + final PsiElement statement = (PsiElement) iterator.next(); + if(isUsedByStatement(var, statement)) + { + return true; + } + } + return false; + } + + private static boolean isUsedByStatement(PsiLocalVariable var, PsiElement statement) + { + final LocalVariableUsageVisitor visitor = new LocalVariableUsageVisitor(var); + statement.accept(visitor); + return visitor.isUsed(); + } + + public static String findUniqueLabel(PsiStatement statement, String baseName) + { + PsiElement ancestor = statement; + while(ancestor.getParent() != null) + { + if(ancestor instanceof PsiMethod + || ancestor instanceof PsiClass + || ancestor instanceof PsiFile) + { + break; + } + ancestor = ancestor.getParent(); + } + if(!checkForLabel(baseName, ancestor)) + { + return baseName; + } + int val = 1; + while(true) + { + final String name = baseName + val; + if(!checkForLabel(name, ancestor)) + { + return name; + } + val++; + } + } + + private static boolean checkForLabel(String name, PsiElement ancestor) + { + final LabelSearchVisitor visitor = new LabelSearchVisitor(name); + ancestor.accept(visitor); + return visitor.isUsed(); + } + + public static PsiExpression getCaseExpression(PsiIfStatement statement) + { + final PsiExpression condition = statement.getCondition(); + final List possibleCaseExpressions = determinePossibleCaseExpressions(condition); + if(possibleCaseExpressions == null) + { + return null; + } + for(Iterator iterator = possibleCaseExpressions.iterator(); iterator.hasNext();) + { + final PsiExpression caseExp = (PsiExpression) iterator.next(); + if(!SideEffectChecker.mayHaveSideEffects(caseExp)) + { + PsiIfStatement statementToCheck = statement; + while(true) + { + final PsiExpression caseCondition = statementToCheck.getCondition(); + if(canBeMadeIntoCase(caseCondition, caseExp)) + { + final PsiStatement elseBranch = statementToCheck.getElseBranch(); + if(elseBranch == null || !(elseBranch instanceof PsiIfStatement)) + { + return caseExp; + } + statementToCheck = (PsiIfStatement) elseBranch; + } + else + { + break; + } + } + } + } + return null; + } + + private static List determinePossibleCaseExpressions(PsiExpression exp) + { + final List out = new ArrayList(10); + PsiExpression expToCheck = exp; + while(expToCheck instanceof PsiParenthesizedExpression) + { + expToCheck = ((PsiParenthesizedExpression) exp).getExpression(); + } + if(!(expToCheck instanceof PsiBinaryExpression)) + { + return out; + } + final PsiBinaryExpression binaryExp = (PsiBinaryExpression) expToCheck; + final PsiJavaToken sign = binaryExp.getOperationSign(); + final IElementType operation = sign.getTokenType(); + final PsiExpression lhs = binaryExp.getLOperand(); + + final PsiExpression rhs = binaryExp.getROperand(); + if(operation.equals(JavaTokenType.OROR)) + { + return determinePossibleCaseExpressions(lhs); + } + else if(operation.equals(JavaTokenType.EQEQ)) + { + if(canBeCaseLabel(lhs)) + { + out.add(rhs); + } + if(canBeCaseLabel(rhs)) + { + out.add(lhs); + } + } + return out; + } + + private static boolean canBeMadeIntoCase(PsiExpression exp, PsiExpression caseExpression) + { + PsiExpression expToCheck = exp; + while(expToCheck instanceof PsiParenthesizedExpression) + { + expToCheck = ((PsiParenthesizedExpression) exp).getExpression(); + } + if(!(expToCheck instanceof PsiBinaryExpression)) + { + return false; + } + final PsiBinaryExpression binaryExp = (PsiBinaryExpression) expToCheck; + final PsiJavaToken sign = binaryExp.getOperationSign(); + final IElementType operation = sign.getTokenType(); + final PsiExpression lOperand = binaryExp.getLOperand(); + final PsiExpression rhs = binaryExp.getROperand(); + if(!(operation != JavaTokenType.OROR)) + { + return canBeMadeIntoCase(lOperand, caseExpression) && + canBeMadeIntoCase(rhs, caseExpression); + } + else if(operation.equals(JavaTokenType.EQEQ)) + { + if(canBeCaseLabel(lOperand) && + EquivalenceChecker.expressionsAreEquivalent(caseExpression, rhs)) + { + return true; + } + else if(canBeCaseLabel(rhs) && + EquivalenceChecker.expressionsAreEquivalent(caseExpression, lOperand)) + { + return true; + } + return false; + } + else + { + return false; + } + } +} diff --git a/plugins/IntentionPowerPak/src/com/siyeh/ipp/switchtoif/IfStatementBranch.java b/plugins/IntentionPowerPak/src/com/siyeh/ipp/switchtoif/IfStatementBranch.java new file mode 100644 index 000000000000..ba31e678064a --- /dev/null +++ b/plugins/IntentionPowerPak/src/com/siyeh/ipp/switchtoif/IfStatementBranch.java @@ -0,0 +1,91 @@ +package com.siyeh.ipp.switchtoif; + +import com.intellij.psi.PsiStatement; + +import java.util.*; + +class IfStatementBranch +{ + private Set m_topLevelVariables = new HashSet(3); + private Set m_innerVariables = new HashSet(3); + private final List m_conditions = new ArrayList(3); + private PsiStatement m_statement = null; + private boolean m_else = false; + + IfStatementBranch() + { + super(); + } + + public void addCondition(String conditionString) + { + m_conditions.add(conditionString); + } + + public void setStatement(PsiStatement statement) + { + m_statement = statement; + } + + public PsiStatement getStatement() + { + return m_statement; + } + + public List getConditions() + { + return Collections.unmodifiableList(m_conditions); + } + + public boolean isElse() + { + return m_else; + } + + public void setElse() + { + m_else = true; + } + + public void setTopLevelVariables(Set topLevelVariables) + { + m_topLevelVariables = new HashSet(topLevelVariables); + } + + public void setInnerVariables(Set innerVariables) + { + m_innerVariables = new HashSet(innerVariables); + } + + private Set getTopLevelVariables() + { + return Collections.unmodifiableSet(m_topLevelVariables); + } + + private Set getInnerVariables() + { + return Collections.unmodifiableSet(m_innerVariables); + } + + public boolean topLevelDeclarationsConfictWith(IfStatementBranch testBranch) + { + final Set innerVariables = testBranch.getInnerVariables(); + final Set topLevel = testBranch.getTopLevelVariables(); + return hasNonEmptyIntersection(m_topLevelVariables, topLevel) || + hasNonEmptyIntersection(m_topLevelVariables, innerVariables); + } + + private static boolean hasNonEmptyIntersection(Set set1, Set set2) + { + for(Iterator iterator = set1.iterator(); iterator.hasNext();) + { + final Object set1Element = iterator.next(); + if(set2.contains(set1Element)) + { + return true; + } + } + return false; + } + +} diff --git a/plugins/IntentionPowerPak/src/com/siyeh/ipp/switchtoif/IfToSwitchPredicate.java b/plugins/IntentionPowerPak/src/com/siyeh/ipp/switchtoif/IfToSwitchPredicate.java new file mode 100644 index 000000000000..cf8a514dc588 --- /dev/null +++ b/plugins/IntentionPowerPak/src/com/siyeh/ipp/switchtoif/IfToSwitchPredicate.java @@ -0,0 +1,27 @@ +package com.siyeh.ipp.switchtoif; + +import com.intellij.psi.*; +import com.siyeh.ipp.PsiElementPredicate; + +class IfToSwitchPredicate implements PsiElementPredicate +{ + public boolean satisfiedBy(PsiElement exp) + { + if(!(exp instanceof PsiJavaToken)) + { + return false; + } + final String text = exp.getText(); + if(!"if".equals(text)) + { + return false; + } + if(!(exp.getParent() instanceof PsiIfStatement)) + { + return false; + } + final PsiIfStatement statement = (PsiIfStatement) exp.getParent(); + return CaseUtil.getCaseExpression(statement) != null; + } + +} diff --git a/plugins/IntentionPowerPak/src/com/siyeh/ipp/switchtoif/LabelSearchVisitor.java b/plugins/IntentionPowerPak/src/com/siyeh/ipp/switchtoif/LabelSearchVisitor.java new file mode 100644 index 000000000000..71d8d93dbd2d --- /dev/null +++ b/plugins/IntentionPowerPak/src/com/siyeh/ipp/switchtoif/LabelSearchVisitor.java @@ -0,0 +1,36 @@ +package com.siyeh.ipp.switchtoif; + +import com.intellij.psi.*; + +class LabelSearchVisitor extends PsiRecursiveElementVisitor +{ + private final String m_labelName; + private boolean m_used = false; + + LabelSearchVisitor(String name) + { + super(); + m_labelName = name; + } + + public void visitReferenceExpression(PsiReferenceExpression expression) + { + + } + + public void visitLabeledStatement(PsiLabeledStatement statement) + { + final PsiIdentifier labelIdentifier = statement.getLabelIdentifier(); + final String labelText = labelIdentifier.getText(); + if(labelText.equals(m_labelName)) + { + m_used = true; + } + } + + public boolean isUsed() + { + return m_used; + } + +} diff --git a/plugins/IntentionPowerPak/src/com/siyeh/ipp/switchtoif/LocalVariableUsageVisitor.java b/plugins/IntentionPowerPak/src/com/siyeh/ipp/switchtoif/LocalVariableUsageVisitor.java new file mode 100644 index 000000000000..7a134521384b --- /dev/null +++ b/plugins/IntentionPowerPak/src/com/siyeh/ipp/switchtoif/LocalVariableUsageVisitor.java @@ -0,0 +1,31 @@ +package com.siyeh.ipp.switchtoif; + +import com.intellij.psi.*; + +class LocalVariableUsageVisitor extends PsiRecursiveElementVisitor +{ + private final PsiLocalVariable m_var; + private boolean m_used = false; + + LocalVariableUsageVisitor(PsiLocalVariable name) + { + super(); + m_var = name; + } + + public void visitReferenceExpression(PsiReferenceExpression expression) + { + final PsiElement reference = expression.resolve(); + if(m_var.equals(reference)) + { + m_used = true; + } + super.visitReferenceElement(expression); + } + + public boolean isUsed() + { + return m_used; + } + +} diff --git a/plugins/IntentionPowerPak/src/com/siyeh/ipp/switchtoif/ReplaceIfWithSwitchIntention.java b/plugins/IntentionPowerPak/src/com/siyeh/ipp/switchtoif/ReplaceIfWithSwitchIntention.java new file mode 100644 index 000000000000..3574af4f9889 --- /dev/null +++ b/plugins/IntentionPowerPak/src/com/siyeh/ipp/switchtoif/ReplaceIfWithSwitchIntention.java @@ -0,0 +1,323 @@ +package com.siyeh.ipp.switchtoif; + +import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.project.Project; +import com.intellij.psi.*; +import com.intellij.util.IncorrectOperationException; +import com.siyeh.ipp.*; +import com.siyeh.ipp.psiutils.*; + +import java.util.*; + +public class ReplaceIfWithSwitchIntention extends Intention +{ + public ReplaceIfWithSwitchIntention(Project project) + { + super(project); + } + + public String getText() + { + return "Replace if with switch"; + } + + public String getFamilyName() + { + return "Replace If With Switch"; + } + + public PsiElementPredicate getElementPredicate() + { + return new IfToSwitchPredicate(); + } + + public void invoke(Project project, Editor editor, PsiFile file) throws IncorrectOperationException + { + final PsiJavaToken switchToken = (PsiJavaToken) findMatchingElement(file, editor); + PsiIfStatement ifStatement = (PsiIfStatement) switchToken.getParent(); + boolean breaksNeedRelabeled = false; + PsiStatement breakTarget = null; + String labelString = ""; + if(ControlFlowUtils.statementContainsExitingBreak(ifStatement)) + { + // what a pain. + PsiElement ancestor = ifStatement.getParent(); + while(ancestor != null) + { + if(ancestor instanceof PsiForStatement || + ancestor instanceof PsiDoWhileStatement || + ancestor instanceof PsiWhileStatement || + ancestor instanceof PsiSwitchStatement) + { + breakTarget = (PsiStatement) ancestor; + break; + } + ancestor = ancestor.getParent(); + } + if(breakTarget != null) + { + labelString = CaseUtil.findUniqueLabel(ifStatement, "Label"); + breaksNeedRelabeled = true; + } + } + final PsiIfStatement statementToReplace = ifStatement; + final StringBuffer switchStatementBuffer = new StringBuffer(1024); + final PsiExpression caseExpression = CaseUtil.getCaseExpression(ifStatement); + switchStatementBuffer.append("switch(" + caseExpression.getText() + ')'); + switchStatementBuffer.append('{'); + final List branches = new ArrayList(20); + while(true) + { + final Set topLevelVariables = new HashSet(5); + final Set innerVariables = new HashSet(5); + final PsiExpression condition = ifStatement.getCondition(); + final PsiExpression[] labels = getValuesFromCondition(condition, caseExpression); + final PsiStatement thenBranch = ifStatement.getThenBranch(); + DeclarationUtils.calculateVariablesDeclared(thenBranch, topLevelVariables, innerVariables, + true); + final IfStatementBranch ifBranch = new IfStatementBranch(); + ifBranch.setInnerVariables(innerVariables); + ifBranch.setTopLevelVariables(topLevelVariables); + ifBranch.setStatement(thenBranch); + for(int i = 0; i < labels.length; i++) + { + final PsiExpression label = labels[i]; + final String labelText = label.getText(); + ifBranch.addCondition(labelText); + } + branches.add(ifBranch); + final PsiStatement elseBranch = ifStatement.getElseBranch(); + + if(elseBranch instanceof PsiIfStatement) + { + ifStatement = (PsiIfStatement) elseBranch; + } + else if(elseBranch == null) + { + break; + } + else + { + final Set elseTopLevelVariables = new HashSet(5); + final Set elseInnerVariables = new HashSet(5); + DeclarationUtils.calculateVariablesDeclared(elseBranch, elseTopLevelVariables, elseInnerVariables, + true); + final IfStatementBranch elseIfBranch = new IfStatementBranch(); + elseIfBranch.setInnerVariables(elseInnerVariables); + elseIfBranch.setTopLevelVariables(elseTopLevelVariables); + elseIfBranch.setElse(); + elseIfBranch.setStatement(elseBranch); + branches.add(elseIfBranch); + break; + } + } + + for(Iterator iterator = branches.iterator(); iterator.hasNext();) + { + final IfStatementBranch branch = (IfStatementBranch) iterator.next(); + boolean hasConflicts = false; + for(Iterator innerIterator = branches.iterator(); innerIterator.hasNext();) + { + final IfStatementBranch testBranch = (IfStatementBranch) innerIterator.next(); + if(branch.topLevelDeclarationsConfictWith(testBranch)) + { + hasConflicts = true; + } + } + + final PsiStatement branchStatement = branch.getStatement(); + if(branch.isElse()) + { + dumpDefaultBranch(switchStatementBuffer, branchStatement, hasConflicts, + breaksNeedRelabeled, labelString); + } + else + { + final List conditions = branch.getConditions(); + dumpBranch(switchStatementBuffer, conditions, branchStatement, + hasConflicts, breaksNeedRelabeled, labelString); + } + } + switchStatementBuffer.append('}'); + final String switchStatementString = switchStatementBuffer.toString(); + if(breaksNeedRelabeled) + { + final int length = switchStatementBuffer.length(); + final StringBuffer out = new StringBuffer(length); + out.append(labelString + ':'); + termReplace(out, breakTarget, statementToReplace, switchStatementString); + final String newStatement = out.toString(); + replaceStatement(project, newStatement, breakTarget); + } + else + { + final String newStatement = switchStatementString; + replaceStatement(project, newStatement, statementToReplace); + } + } + + private void termReplace(StringBuffer out, PsiElement target, PsiElement replace, String stringToReplaceWith) + { + if(target.equals(replace)) + { + out.append(stringToReplaceWith); + } + else if(target.getChildren() != null && target.getChildren().length != 0) + { + final PsiElement[] children = target.getChildren(); + for(int i = 0; i < children.length; i++) + { + final PsiElement child = children[i]; + termReplace(out, child, replace, stringToReplaceWith); + } + } + else + { + final String text = target.getText(); + out.append(text); + } + } + + private PsiExpression[] getValuesFromCondition(PsiExpression condition, PsiExpression caseExpression) + { + final List values = new ArrayList(10); + final PsiBinaryExpression binaryCond = (PsiBinaryExpression) condition; + getValuesFromExpression(binaryCond, caseExpression, values); + return (PsiExpression[]) values.toArray(new PsiExpression[values.size()]); + } + + private void getValuesFromExpression(PsiBinaryExpression binaryCond, PsiExpression caseExpression, List values) + { + final PsiExpression lhs = binaryCond.getLOperand(); + final PsiExpression rhs = binaryCond.getROperand(); + final PsiJavaToken sign = binaryCond.getOperationSign(); + if(sign.getTokenType().equals(JavaTokenType.OROR)) + { + getValuesFromExpression((PsiBinaryExpression) lhs, caseExpression, values); + getValuesFromExpression((PsiBinaryExpression) rhs, caseExpression, values); + } + else + { + if(EquivalenceChecker.expressionsAreEquivalent(caseExpression, rhs)) + { + values.add(lhs); + } + else + { + values.add(rhs); + } + } + } + + private static void dumpBranch(StringBuffer switchStatementString, List labels, PsiStatement body, boolean wrap, + boolean renameBreaks, String breakLabelName) + { + dumpLabels(switchStatementString, labels); + dumpBody(switchStatementString, body, wrap, renameBreaks, breakLabelName); + } + + private static void dumpDefaultBranch(StringBuffer switchStatementString, PsiStatement body, boolean wrap, + boolean renameBreaks, String breakLabelName) + { + switchStatementString.append("default: "); + dumpBody(switchStatementString, body, wrap, renameBreaks, breakLabelName); + } + + private static void dumpLabels(StringBuffer switchStatementString, List labels) + { + for(Iterator iterator = labels.iterator(); iterator.hasNext();) + { + final String exp = (String) iterator.next(); + switchStatementString.append("case "); + switchStatementString.append(exp); + switchStatementString.append(": "); + } + } + + private static void dumpBody(StringBuffer switchStatementString, PsiStatement bodyStatement, boolean wrap, + boolean renameBreaks, String breakLabelName) + { + if(bodyStatement instanceof PsiBlockStatement) + { + if(wrap) + { + appendElement(switchStatementString, bodyStatement, renameBreaks, breakLabelName); + } + else + { + final PsiCodeBlock codeBlock = ((PsiBlockStatement) bodyStatement).getCodeBlock(); + final PsiElement[] children = codeBlock.getChildren(); + //skip the first and last members, to unwrap the block + for(int i = 1; i < children.length - 1; i++) + { + final PsiElement child = children[i]; + appendElement(switchStatementString, child, renameBreaks, breakLabelName); + } + } + } + else + { + if(wrap) + { + switchStatementString.append('{'); + appendElement(switchStatementString, bodyStatement, renameBreaks, breakLabelName); + switchStatementString.append('}'); + } + else + { + appendElement(switchStatementString, bodyStatement, renameBreaks, breakLabelName); + } + + } + if(ControlFlowUtils.statementMayCompleteNormally(bodyStatement)) + { + switchStatementString.append("break; "); + } + + } + + private static void appendElement(StringBuffer switchStatementString, PsiElement element, + boolean renameBreakElements, String breakLabelString) + { + final String text = element.getText(); + if(!renameBreakElements) + { + switchStatementString.append(text); + } + else if(element instanceof PsiBreakStatement) + { + final PsiIdentifier identifier = ((PsiBreakStatement) element).getLabelIdentifier(); + if(identifier == null) + { + switchStatementString.append("break " + breakLabelString + ';'); + } + else + { + final String identifierText = identifier.getText(); + if("".equals(identifierText)) + { + switchStatementString.append("break " + breakLabelString + ';'); + } + else + { + switchStatementString.append(text); + } + } + } + else if(element instanceof PsiBlockStatement || + element instanceof PsiCodeBlock || + element instanceof PsiIfStatement) + { + final PsiElement[] children = element.getChildren(); + for(int i = 0; i < children.length; i++) + { + final PsiElement child = children[i]; + appendElement(switchStatementString, child, renameBreakElements, breakLabelString); + } + } + else + { + switchStatementString.append(text); + } + } +} diff --git a/plugins/IntentionPowerPak/src/com/siyeh/ipp/switchtoif/ReplaceSwitchWithIfIntention.java b/plugins/IntentionPowerPak/src/com/siyeh/ipp/switchtoif/ReplaceSwitchWithIfIntention.java new file mode 100644 index 000000000000..e66127e608cb --- /dev/null +++ b/plugins/IntentionPowerPak/src/com/siyeh/ipp/switchtoif/ReplaceSwitchWithIfIntention.java @@ -0,0 +1,326 @@ +package com.siyeh.ipp.switchtoif; + +import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.project.Project; +import com.intellij.psi.*; +import com.intellij.psi.codeStyle.CodeStyleManager; +import com.intellij.util.IncorrectOperationException; +import com.siyeh.ipp.*; +import com.siyeh.ipp.psiutils.ControlFlowUtils; +import com.siyeh.ipp.psiutils.SideEffectChecker; + +import java.util.*; + +public class ReplaceSwitchWithIfIntention extends Intention +{ + public ReplaceSwitchWithIfIntention(Project project) + { + super(project); + } + + public String getText() + { + return "Replace switch with if"; + } + + public String getFamilyName() + { + return "Replace Switch With If"; + } + + public PsiElementPredicate getElementPredicate() + { + return new SwitchPredicate(); + } + + public void invoke(Project project, Editor editor, PsiFile file) throws IncorrectOperationException + { + + final PsiJavaToken switchToken = (PsiJavaToken) findMatchingElement(file, editor); + final PsiSwitchStatement switchStatement = + (PsiSwitchStatement) switchToken.getParent(); + final List allBranches = new ArrayList(10); + final List openBranches = new ArrayList(10); + SwitchStatementBranch currentBranch = null; + + final StringBuffer ifStatementBuffer = new StringBuffer(1024); + final String expressionText; + final boolean hadSideEffects; + final String declarationString; + final PsiManager mgr = PsiManager.getInstance(project); + final PsiExpression switchExpression = switchStatement.getExpression(); + final CodeStyleManager codeStyleMgr = mgr.getCodeStyleManager(); + if(SideEffectChecker.mayHaveSideEffects(switchExpression)) + { + hadSideEffects = true; + final PsiType switchExpressionType = switchExpression.getType(); + final String variableName = + codeStyleMgr.suggestUniqueVariableName("i", switchExpression, true); + expressionText = variableName; + declarationString = + switchExpressionType.getPresentableText() + ' ' + variableName + " = " + + switchExpression.getText() + + ';'; + } + else + { + hadSideEffects = false; + declarationString = null; + expressionText = switchExpression.getText(); + } + final PsiCodeBlock body = switchStatement.getBody(); + final PsiStatement[] statements = body.getStatements(); + + boolean renameBreaks = false; + for(int i = 1; i < statements.length - 1; i++) + { + if(CaseUtil.containsHiddenBreak(statements[i])) + { + renameBreaks = true; + break; + } + } + + final Set declaredVars = new HashSet(5); + String breakLabel = null; + if(renameBreaks) + { + breakLabel = CaseUtil.findUniqueLabel(switchStatement, "Label"); + ifStatementBuffer.append(breakLabel + ':'); + } + final PsiElement[] children = body.getChildren(); + + for(int i = 1; i < children.length - 1; i++) + { + final PsiElement statement = children[i]; + if(statement instanceof PsiSwitchLabelStatement) + { + final PsiSwitchLabelStatement label = (PsiSwitchLabelStatement) statement; + if(currentBranch == null) + { + openBranches.clear(); + currentBranch = new SwitchStatementBranch(); + currentBranch.addPendingVariableDeclarations(declaredVars); + allBranches.add(currentBranch); + openBranches.add(currentBranch); + } + else if(currentBranch.hasStatements()) + { + currentBranch = new SwitchStatementBranch(); + allBranches.add(currentBranch); + openBranches.add(currentBranch); + } + if(label.isDefaultCase()) + { + currentBranch.setDefault(); + } + else + { + PsiExpression value = label.getCaseValue(); + while(value instanceof PsiParenthesizedExpression) + { + value = ((PsiParenthesizedExpression) value).getExpression(); + } + final String valueText = value.getText(); + currentBranch.addLabel(valueText); + } + } + else + { + if(statement instanceof PsiStatement) + { + if(statement instanceof PsiDeclarationStatement) + { + final PsiDeclarationStatement decl = (PsiDeclarationStatement) statement; + final PsiElement[] elements = decl.getDeclaredElements(); + for(int j = 0; j < elements.length; j++) + { + final PsiLocalVariable var = (PsiLocalVariable) elements[j]; + declaredVars.add(var); + } + } + for(Iterator iterator = openBranches.iterator(); iterator.hasNext();) + { + final SwitchStatementBranch branch = (SwitchStatementBranch) iterator.next(); + branch.addStatement(statement); + } + if(!ControlFlowUtils.statementMayCompleteNormally((PsiStatement) statement)) + { + currentBranch = null; + } + } + else + { + for(Iterator iterator = openBranches.iterator(); iterator.hasNext();) + { + final SwitchStatementBranch branch = (SwitchStatementBranch) iterator.next(); + if(statement instanceof PsiWhiteSpace) + { + branch.addWhiteSpace(statement); + } + else + { + branch.addComment(statement); + } + } + } + } + } + boolean firstBranch = true; + SwitchStatementBranch defaultBranch = null; + + for(Iterator iterator = allBranches.iterator(); iterator.hasNext();) + { + final SwitchStatementBranch branch = (SwitchStatementBranch) iterator.next(); + if(branch.isDefault()) + { + defaultBranch = branch; + } + else + { + final List labels = branch.getLabels(); + final List bodyElements = branch.getBodyElements(); + final Set pendingVariableDeclarations = branch.getPendingVariableDeclarations(); + dumpBranch(ifStatementBuffer, expressionText, + labels, bodyElements, firstBranch, + renameBreaks, breakLabel, pendingVariableDeclarations); + firstBranch = false; + } + } + if(defaultBranch != null) + { + final List bodyElements = defaultBranch.getBodyElements(); + final Set pendingVariableDeclarations = defaultBranch.getPendingVariableDeclarations(); + dumpDefaultBranch(ifStatementBuffer, bodyElements, + firstBranch, renameBreaks, breakLabel, pendingVariableDeclarations); + } + final PsiElementFactory factory = mgr.getElementFactory(); + if(hadSideEffects) + { + final PsiStatement declarationStatement = factory.createStatementFromText(declarationString, null); + final String ifStatementString = ifStatementBuffer.toString(); + final PsiStatement ifStatement = factory.createStatementFromText(ifStatementString, null); + PsiElement ifElement = switchStatement.replace(ifStatement); + ifElement = codeStyleMgr.reformat(ifElement); + final PsiElement parent = ifElement.getParent(); + final PsiElement declarationElement = parent.addBefore(declarationStatement, ifElement); + codeStyleMgr.reformat(declarationElement); + codeStyleMgr.reformat(parent); + } + else + { + final String ifStatementString = ifStatementBuffer.toString(); + final PsiStatement newStatement = factory.createStatementFromText(ifStatementString, null); + final PsiElement replacedStatement = switchStatement.replace(newStatement); + codeStyleMgr.reformat(replacedStatement); + } + } + + private static void dumpBranch(StringBuffer ifStatementString, String expressionText, List labels, + List bodyStatements, boolean firstBranch, boolean renameBreaks, String breakLabel, + Set variableDecls) + { + if(!firstBranch) + { + ifStatementString.append("else "); + } + dumpLabels(ifStatementString, expressionText, labels); + dumpBody(ifStatementString, bodyStatements, renameBreaks, breakLabel, variableDecls); + } + + private static void dumpDefaultBranch(StringBuffer ifStatementString, List bodyStatements, + boolean firstBranch, boolean renameBreaks, String breakLabel, + Set variableDecls) + { + if(!firstBranch) + { + ifStatementString.append("else "); + } + dumpBody(ifStatementString, bodyStatements, renameBreaks, breakLabel, variableDecls); + } + + private static void dumpLabels(StringBuffer ifStatementString, String expressionText, List labels) + { + ifStatementString.append("if("); + boolean firstLabel = true; + for(Iterator iterator = labels.iterator(); iterator.hasNext();) + { + if(!firstLabel) + { + ifStatementString.append("||"); + } + firstLabel = false; + final String valueText = (String) iterator.next(); + ifStatementString.append(expressionText); + ifStatementString.append("=="); + ifStatementString.append(valueText); + } + ifStatementString.append(')'); + } + + private static void dumpBody(StringBuffer ifStatementString, List bodyStatements, boolean renameBreaks, + String breakLabel, Set variableDecls) + { + + ifStatementString.append('{'); + for(Iterator iterator = variableDecls.iterator(); iterator.hasNext();) + { + final PsiLocalVariable var = (PsiLocalVariable) iterator.next(); + if(CaseUtil.isUsedByStatementList(var, bodyStatements)) + { + final PsiType varType = var.getType(); + ifStatementString.append(varType.getPresentableText() + ' ' + var.getName() + ';'); + } + } + + for(Iterator iterator = bodyStatements.iterator(); iterator.hasNext();) + { + final PsiElement bodyStatement = (PsiElement) iterator.next(); + final String text = bodyStatement.getText(); + if(!"break;".equals(text)) + { + appendElement(ifStatementString, bodyStatement, renameBreaks, breakLabel); + } + } + ifStatementString.append('}'); + } + + private static void appendElement(StringBuffer ifStatementString, PsiElement element, + boolean renameBreakElements, String breakLabelString) + { + if(!renameBreakElements) + { + final String text = element.getText(); + ifStatementString.append(text); + } + else if(element instanceof PsiBreakStatement) + { + final PsiIdentifier identifier = ((PsiBreakStatement) element).getLabelIdentifier(); + if(identifier == null || "".equals(identifier.getText())) + { + ifStatementString.append("break " + breakLabelString + ';'); + } + else + { + final String text = element.getText(); + ifStatementString.append(text); + } + } + else if(element instanceof PsiBlockStatement || + element instanceof PsiCodeBlock || + element instanceof PsiIfStatement) + { + final PsiElement[] children = element.getChildren(); + for(int i = 0; i < children.length; i++) + { + final PsiElement child = children[i]; + appendElement(ifStatementString, child, renameBreakElements, breakLabelString); + } + } + else + { + final String text = element.getText(); + ifStatementString.append(text); + } + } +} diff --git a/plugins/IntentionPowerPak/src/com/siyeh/ipp/switchtoif/SwitchPredicate.java b/plugins/IntentionPowerPak/src/com/siyeh/ipp/switchtoif/SwitchPredicate.java new file mode 100644 index 000000000000..8c4f527e32f7 --- /dev/null +++ b/plugins/IntentionPowerPak/src/com/siyeh/ipp/switchtoif/SwitchPredicate.java @@ -0,0 +1,19 @@ +package com.siyeh.ipp.switchtoif; + +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiJavaToken; +import com.intellij.psi.JavaTokenType; +import com.siyeh.ipp.PsiElementPredicate; + +class SwitchPredicate implements PsiElementPredicate +{ + public boolean satisfiedBy(PsiElement exp) + { + if(!(exp instanceof PsiJavaToken)) + { + return false; + } + final PsiJavaToken token = (PsiJavaToken) exp; + return token.getTokenType() == JavaTokenType.SWITCH_KEYWORD; + } +} diff --git a/plugins/IntentionPowerPak/src/com/siyeh/ipp/switchtoif/SwitchStatementBranch.java b/plugins/IntentionPowerPak/src/com/siyeh/ipp/switchtoif/SwitchStatementBranch.java new file mode 100644 index 000000000000..9e5cebefe070 --- /dev/null +++ b/plugins/IntentionPowerPak/src/com/siyeh/ipp/switchtoif/SwitchStatementBranch.java @@ -0,0 +1,87 @@ +package com.siyeh.ipp.switchtoif; + +import com.intellij.psi.PsiElement; + +import java.util.*; + +class SwitchStatementBranch +{ + private final Set m_pendingVariableDeclarations = new HashSet(5); + private final List m_labels = new ArrayList(2); + private final List m_bodyElements = new ArrayList(5); + private final List m_pendingWhiteSpace = new ArrayList(2); + private boolean m_default = false; + private boolean m_hasStatements = false; + + SwitchStatementBranch() + { + super(); + } + + public void addLabel(String labelString) + { + m_labels.add(labelString); + } + + public void addStatement(PsiElement statement) + { + m_hasStatements = true; + addElement(statement); + } + + public void addComment(PsiElement comment) + { + addElement(comment); + } + + private void addElement(PsiElement element) + { + m_bodyElements.addAll(m_pendingWhiteSpace); + m_pendingWhiteSpace.clear(); + m_bodyElements.add(element); + } + + public void addWhiteSpace(PsiElement statement) + { + if(m_bodyElements.size() > 0) + { + m_pendingWhiteSpace.add(statement); + } + } + + public List getLabels() + { + return Collections.unmodifiableList(m_labels) ; + } + + public List getBodyElements() + { + return Collections.unmodifiableList(m_bodyElements) ; + } + + public boolean isDefault() + { + return m_default; + } + + public void setDefault() + { + m_default = true; + } + + public boolean hasStatements() + { + return m_hasStatements; + } + + public void addPendingVariableDeclarations(Set vars) + { + m_pendingVariableDeclarations.addAll(vars); + } + + public Set getPendingVariableDeclarations() + { + return Collections.unmodifiableSet(m_pendingVariableDeclarations); + } + +} diff --git a/plugins/IntentionPowerPak/src/com/siyeh/ipp/trivialif/ExpandBooleanIntention.java b/plugins/IntentionPowerPak/src/com/siyeh/ipp/trivialif/ExpandBooleanIntention.java new file mode 100644 index 000000000000..9bf0b44fe4eb --- /dev/null +++ b/plugins/IntentionPowerPak/src/com/siyeh/ipp/trivialif/ExpandBooleanIntention.java @@ -0,0 +1,50 @@ +package com.siyeh.ipp.trivialif; + +import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.project.Project; +import com.intellij.psi.*; +import com.intellij.psi.util.PsiTreeUtil; +import com.intellij.util.IncorrectOperationException; +import com.siyeh.ipp.Intention; +import com.siyeh.ipp.PsiElementPredicate; + +public class ExpandBooleanIntention extends Intention { + public ExpandBooleanIntention(Project project) { + super(project); + } + + public String getText() { + return "Expand boolean use to if-else"; + } + + public String getFamilyName() { + return "Expand Boolean"; + } + + public PsiElementPredicate getElementPredicate() { + return new ExpandBooleanPredicate(); + } + + public void invoke(Project project, Editor editor, PsiFile file) throws IncorrectOperationException { + final PsiJavaToken token = (PsiJavaToken) findMatchingElement(file, editor); + final PsiStatement containingStatement = + (PsiStatement) PsiTreeUtil.getParentOfType(token, PsiStatement.class); + + if (ExpandBooleanPredicate.isBooleanAssignment(containingStatement)) { + final PsiExpressionStatement assignmentStatement = (PsiExpressionStatement) containingStatement; + final PsiAssignmentExpression assignmentExpression = (PsiAssignmentExpression) assignmentStatement.getExpression(); + final PsiExpression rhs = assignmentExpression.getRExpression(); + final String rhsText = rhs.getText(); + final PsiExpression lhs = assignmentExpression.getLExpression(); + final String lhsText = lhs.getText(); + final String statement = "if(" + rhsText + "){" + lhsText + " = true;}else{" + lhsText + " = false;}"; + replaceStatement(project, statement, containingStatement); + } else if (ExpandBooleanPredicate.isBooleanReturn(containingStatement)) { + final PsiReturnStatement returnStatement = (PsiReturnStatement) containingStatement; + final PsiExpression returnValue = returnStatement.getReturnValue(); + final String valueText = returnValue.getText(); + final String statement = "if(" + valueText + "){return true;}else{return false;}"; + replaceStatement(project, statement, containingStatement); + } + } +} \ No newline at end of file diff --git a/plugins/IntentionPowerPak/src/com/siyeh/ipp/trivialif/ExpandBooleanPredicate.java b/plugins/IntentionPowerPak/src/com/siyeh/ipp/trivialif/ExpandBooleanPredicate.java new file mode 100644 index 000000000000..3e6bd2979eb0 --- /dev/null +++ b/plugins/IntentionPowerPak/src/com/siyeh/ipp/trivialif/ExpandBooleanPredicate.java @@ -0,0 +1,68 @@ +package com.siyeh.ipp.trivialif; + +import com.intellij.psi.*; +import com.intellij.psi.util.PsiTreeUtil; +import com.siyeh.ipp.PsiElementPredicate; + +class ExpandBooleanPredicate implements PsiElementPredicate { + public boolean satisfiedBy(PsiElement element) { + if (!(element instanceof PsiJavaToken)) { + return false; + } + final PsiJavaToken token = (PsiJavaToken) element; + final PsiStatement containingStatement = + (PsiStatement) PsiTreeUtil.getParentOfType(token, PsiStatement.class); + if (containingStatement == null) { + return false; + } + if (isBooleanReturn(containingStatement)) { + return true; + } + if (isBooleanAssignment(containingStatement)) { + return true; + } + return false; + } + + public static boolean isBooleanReturn(PsiStatement containingStatement) { + if (!(containingStatement instanceof PsiReturnStatement)) { + return false; + } + final PsiReturnStatement returnStatement = + (PsiReturnStatement) containingStatement; + final PsiExpression returnValue = returnStatement.getReturnValue(); + if (returnValue == null) { + return false; + } + final PsiType returnType = returnValue.getType(); + if (returnType == null) { + return false; + } + return returnType.equals(PsiType.BOOLEAN); + } + + public static boolean isBooleanAssignment(PsiStatement containingStatement) { + if (!(containingStatement instanceof PsiExpressionStatement)) { + return false; + } + final PsiExpressionStatement expressionStatement = + (PsiExpressionStatement) containingStatement; + final PsiExpression expression = expressionStatement.getExpression(); + if (expression == null) { + return false; + } + if (!(expression instanceof PsiAssignmentExpression)) { + return false; + } + final PsiAssignmentExpression assignment = (PsiAssignmentExpression) expression; + final PsiExpression rhs = assignment.getRExpression(); + if (rhs == null) { + return false; + } + final PsiType assignmentType = rhs.getType(); + if (assignmentType == null) { + return false; + } + return assignmentType.equals(PsiType.BOOLEAN); + } +} diff --git a/plugins/IntentionPowerPak/src/com/siyeh/ipp/trivialif/MergeIfAndIntention.java b/plugins/IntentionPowerPak/src/com/siyeh/ipp/trivialif/MergeIfAndIntention.java new file mode 100644 index 000000000000..2cd234b6c53c --- /dev/null +++ b/plugins/IntentionPowerPak/src/com/siyeh/ipp/trivialif/MergeIfAndIntention.java @@ -0,0 +1,71 @@ +package com.siyeh.ipp.trivialif; + +import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.project.Project; +import com.intellij.psi.*; +import com.intellij.util.IncorrectOperationException; +import com.siyeh.ipp.Intention; +import com.siyeh.ipp.PsiElementPredicate; +import com.siyeh.ipp.psiutils.ConditionalUtils; +import com.siyeh.ipp.psiutils.ParenthesesUtils; + +public class MergeIfAndIntention extends Intention +{ + public MergeIfAndIntention(Project project) + { + super(project); + } + + public String getText() + { + return "Merge 'if's"; + } + + public String getFamilyName() + { + return "Merge Nested Ifs To ANDed Condition"; + } + + public PsiElementPredicate getElementPredicate() + { + return new MergeIfAndPredicate(); + } + + public void invoke(Project project, Editor editor, PsiFile file) throws IncorrectOperationException + { + final PsiJavaToken token = (PsiJavaToken) findMatchingElement(file, editor); + final PsiIfStatement parentStatement = (PsiIfStatement) token.getParent(); + final PsiStatement parentThenBranch = parentStatement.getThenBranch(); + final PsiIfStatement childStatement = (PsiIfStatement) ConditionalUtils.stripBraces(parentThenBranch); + + final String childConditionText; + final PsiExpression childCondition = childStatement.getCondition(); + if(ParenthesesUtils.getPrecendence(childCondition) + > ParenthesesUtils.AND_PRECEDENCE) + { + childConditionText = '(' + childCondition.getText() + ')'; + } + else + { + childConditionText = childCondition.getText(); + + } + final String parentConditionText; + + final PsiExpression parentCondition = parentStatement.getCondition(); + if(ParenthesesUtils.getPrecendence(parentCondition) + > ParenthesesUtils.AND_PRECEDENCE) + { + parentConditionText = '(' + parentCondition.getText() + ')'; + } + else + { + parentConditionText = parentCondition.getText(); + } + + final PsiStatement childThenBranch = childStatement.getThenBranch(); + final String statement = "if(" + parentConditionText + "&&" + childConditionText + ')' + + childThenBranch.getText(); + replaceStatement(project, statement, parentStatement); + } +} \ No newline at end of file diff --git a/plugins/IntentionPowerPak/src/com/siyeh/ipp/trivialif/MergeIfAndPredicate.java b/plugins/IntentionPowerPak/src/com/siyeh/ipp/trivialif/MergeIfAndPredicate.java new file mode 100644 index 000000000000..d26df4e90b7b --- /dev/null +++ b/plugins/IntentionPowerPak/src/com/siyeh/ipp/trivialif/MergeIfAndPredicate.java @@ -0,0 +1,43 @@ +package com.siyeh.ipp.trivialif; + +import com.intellij.psi.*; +import com.siyeh.ipp.PsiElementPredicate; +import com.siyeh.ipp.psiutils.ConditionalUtils; + +class MergeIfAndPredicate implements PsiElementPredicate +{ + public boolean satisfiedBy(PsiElement element) + { + if(!(element instanceof PsiJavaToken)) + { + return false; + } + final PsiJavaToken token = (PsiJavaToken) element; + + final PsiElement parent = token.getParent(); + if(!(parent instanceof PsiIfStatement)) + { + return false; + } + final PsiIfStatement ifStatement = (PsiIfStatement) parent; + PsiStatement thenBranch = ifStatement.getThenBranch(); + thenBranch = ConditionalUtils.stripBraces(thenBranch); + PsiStatement elseBranch = ifStatement.getElseBranch(); + elseBranch = ConditionalUtils.stripBraces(elseBranch); + if(thenBranch == null) + { + return false; + } + if(elseBranch != null) + { + return false; + } + if(!(thenBranch instanceof PsiIfStatement)) + { + return false; + } + final PsiIfStatement childIfStatement = (PsiIfStatement) thenBranch; + + return childIfStatement.getElseBranch() == null; + } +} diff --git a/plugins/IntentionPowerPak/src/com/siyeh/ipp/trivialif/MergeIfOrIntention.java b/plugins/IntentionPowerPak/src/com/siyeh/ipp/trivialif/MergeIfOrIntention.java new file mode 100644 index 000000000000..74894fecf66d --- /dev/null +++ b/plugins/IntentionPowerPak/src/com/siyeh/ipp/trivialif/MergeIfOrIntention.java @@ -0,0 +1,73 @@ +package com.siyeh.ipp.trivialif; + +import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.project.Project; +import com.intellij.psi.*; +import com.intellij.util.IncorrectOperationException; +import com.siyeh.ipp.Intention; +import com.siyeh.ipp.PsiElementPredicate; +import com.siyeh.ipp.psiutils.ParenthesesUtils; + +public class MergeIfOrIntention extends Intention +{ + public MergeIfOrIntention(Project project) + { + super(project); + } + + public String getText() + { + return "Merge 'if's"; + } + + public String getFamilyName() + { + return "Merge Equivalent Ifs To ORed Condition"; + } + + public PsiElementPredicate getElementPredicate() + { + return new MergeIfOrPredicate(); + } + + public void invoke(Project project, Editor editor, PsiFile file) throws IncorrectOperationException + { + final PsiJavaToken token = (PsiJavaToken) findMatchingElement(file, editor); + final PsiIfStatement parentStatement = (PsiIfStatement) token.getParent(); + final PsiIfStatement childStatement = (PsiIfStatement) parentStatement.getElseBranch(); + + final String childConditionText; + final PsiExpression childCondition = childStatement.getCondition(); + if(ParenthesesUtils.getPrecendence(childCondition) + > ParenthesesUtils.OR_PRECEDENCE) + { + childConditionText = '(' + childCondition.getText() + ')'; + } + else + { + childConditionText = childCondition.getText(); + } + + final String parentConditionText; + final PsiExpression condition = parentStatement.getCondition(); + if(ParenthesesUtils.getPrecendence(condition) + > ParenthesesUtils.OR_PRECEDENCE) + { + parentConditionText = '(' + condition.getText() + ')'; + } + else + { + parentConditionText = condition.getText(); + } + + final PsiStatement parentThenBranch = parentStatement.getThenBranch(); + String statement = "if(" + parentConditionText + "||" + childConditionText + ')' + + parentThenBranch.getText(); + final PsiStatement childElseBranch = childStatement.getElseBranch(); + if(childElseBranch != null) + { + statement += "else " + childElseBranch.getText(); + } + replaceStatement(project, statement, parentStatement); + } +} \ No newline at end of file diff --git a/plugins/IntentionPowerPak/src/com/siyeh/ipp/trivialif/MergeIfOrPredicate.java b/plugins/IntentionPowerPak/src/com/siyeh/ipp/trivialif/MergeIfOrPredicate.java new file mode 100644 index 000000000000..ad76cd569f97 --- /dev/null +++ b/plugins/IntentionPowerPak/src/com/siyeh/ipp/trivialif/MergeIfOrPredicate.java @@ -0,0 +1,42 @@ +package com.siyeh.ipp.trivialif; + +import com.intellij.psi.*; +import com.siyeh.ipp.PsiElementPredicate; +import com.siyeh.ipp.psiutils.EquivalenceChecker; + +class MergeIfOrPredicate implements PsiElementPredicate +{ + public boolean satisfiedBy(PsiElement element) + { + if(!(element instanceof PsiJavaToken)) + { + return false; + } + final PsiJavaToken token = (PsiJavaToken) element; + + final PsiElement parent = token.getParent(); + if(!(parent instanceof PsiIfStatement)) + { + return false; + } + final PsiIfStatement ifStatement = (PsiIfStatement) parent; + final PsiStatement thenBranch = ifStatement.getThenBranch(); + final PsiStatement elseBranch = ifStatement.getElseBranch(); + if(thenBranch == null) + { + return false; + } + if(elseBranch == null) + { + return false; + } + if(!(elseBranch instanceof PsiIfStatement)) + { + return false; + } + final PsiIfStatement childIfStatement = (PsiIfStatement) elseBranch; + + final PsiStatement childThenBranch = childIfStatement.getThenBranch(); + return EquivalenceChecker.statementsAreEquivalent(thenBranch, childThenBranch); + } +} diff --git a/plugins/IntentionPowerPak/src/com/siyeh/ipp/trivialif/ReplaceIfWithConditionalIntention.java b/plugins/IntentionPowerPak/src/com/siyeh/ipp/trivialif/ReplaceIfWithConditionalIntention.java new file mode 100644 index 000000000000..6b25b25ef4d5 --- /dev/null +++ b/plugins/IntentionPowerPak/src/com/siyeh/ipp/trivialif/ReplaceIfWithConditionalIntention.java @@ -0,0 +1,155 @@ +package com.siyeh.ipp.trivialif; + +import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.project.Project; +import com.intellij.psi.*; +import com.intellij.util.IncorrectOperationException; +import com.siyeh.ipp.*; +import com.siyeh.ipp.psiutils.ConditionalUtils; +import com.siyeh.ipp.psiutils.ParenthesesUtils; + +public class ReplaceIfWithConditionalIntention extends Intention { + public ReplaceIfWithConditionalIntention(Project project) { + super(project); + } + + public String getText() { + return "Replace if-else with ?:"; + } + + public String getFamilyName() { + return "Replace If Else With Conditional"; + } + + public PsiElementPredicate getElementPredicate() { + return new ReplaceIfWithConditionalPredicate(); + } + + public void invoke(Project project, Editor editor, PsiFile file) throws IncorrectOperationException { + final PsiJavaToken token = (PsiJavaToken) findMatchingElement(file, editor); + final PsiIfStatement ifStatement = (PsiIfStatement) token.getParent(); + if (ReplaceIfWithConditionalPredicate.isReplaceableAssignment(ifStatement)) { + final PsiExpression condition = ifStatement.getCondition(); + final PsiStatement thenBranch = ifStatement.getThenBranch(); + final PsiExpressionStatement strippedThenBranch = (PsiExpressionStatement) ConditionalUtils.stripBraces(thenBranch); + final PsiStatement elseBranch = ifStatement.getElseBranch(); + final PsiExpressionStatement strippedElseBranch = (PsiExpressionStatement) ConditionalUtils.stripBraces(elseBranch); + final PsiAssignmentExpression thenAssign = (PsiAssignmentExpression) strippedThenBranch.getExpression(); + final PsiAssignmentExpression elseAssign = (PsiAssignmentExpression) strippedElseBranch.getExpression(); + final PsiExpression lhs = thenAssign.getLExpression(); + final String lhsText = lhs.getText(); + final PsiJavaToken sign = thenAssign.getOperationSign(); + final String operator = sign.getText(); + final String thenValue; + final PsiExpression thenRhs = thenAssign.getRExpression(); + if (ParenthesesUtils.getPrecendence(thenRhs) + <= ParenthesesUtils.CONDITIONAL_EXPRESSION_EXPRESSION) { + thenValue = thenRhs.getText(); + } else { + thenValue = '(' + thenRhs.getText() + ')'; + + } + final String elseValue; + final PsiExpression elseRhs = elseAssign.getRExpression(); + if (ParenthesesUtils.getPrecendence(elseRhs) + <= ParenthesesUtils.CONDITIONAL_EXPRESSION_EXPRESSION) { + elseValue = elseRhs.getText(); + } else { + elseValue = '(' + elseRhs.getText() + ')'; + + } + final String conditionText; + if (ParenthesesUtils.getPrecendence(condition) + <= ParenthesesUtils.CONDITIONAL_EXPRESSION_EXPRESSION) { + conditionText = condition.getText(); + } else { + conditionText = '(' + condition.getText() + ')'; + + } + + replaceStatement(project, + lhsText + operator + conditionText + '?' + thenValue + ':' + elseValue + ';', + ifStatement); + } else if (ReplaceIfWithConditionalPredicate.isReplaceableReturn(ifStatement)) { + final PsiExpression condition = ifStatement.getCondition(); + final PsiStatement thenBranch = ifStatement.getThenBranch(); + final PsiReturnStatement thenReturn = (PsiReturnStatement) ConditionalUtils.stripBraces(thenBranch); + final PsiStatement elseBranch = ifStatement.getElseBranch(); + final PsiReturnStatement elseReturn = (PsiReturnStatement) ConditionalUtils.stripBraces(elseBranch); + + final String thenValue; + final PsiExpression thenReturnValue = thenReturn.getReturnValue(); + if (ParenthesesUtils.getPrecendence(thenReturnValue) + <= ParenthesesUtils.CONDITIONAL_EXPRESSION_EXPRESSION) { + thenValue = thenReturnValue.getText(); + } else { + thenValue = '(' + thenReturnValue.getText() + ')'; + + } + final String elseValue; + final PsiExpression elseReturnValue = elseReturn.getReturnValue(); + if (ParenthesesUtils.getPrecendence(elseReturnValue) + <= ParenthesesUtils.CONDITIONAL_EXPRESSION_EXPRESSION) { + elseValue = elseReturnValue.getText(); + } else { + elseValue = '(' + elseReturnValue.getText() + ')'; + + } + final String conditionText; + if (ParenthesesUtils.getPrecendence(condition) + <= ParenthesesUtils.CONDITIONAL_EXPRESSION_EXPRESSION) { + conditionText = condition.getText(); + } else { + conditionText = '(' + condition.getText() + ')'; + + } + + replaceStatement(project, + "return " + conditionText + '?' + thenValue + ':' + elseValue + ';', + ifStatement); + } else if (ReplaceIfWithConditionalPredicate.isReplaceableImplicitReturn(ifStatement)) { + final PsiExpression condition = ifStatement.getCondition(); + final PsiStatement rawThenBranch = ifStatement.getThenBranch(); + final PsiReturnStatement thenBranch = (PsiReturnStatement) ConditionalUtils.stripBraces(rawThenBranch); + PsiElement nextStatement = ifStatement.getNextSibling(); + while (nextStatement instanceof PsiWhiteSpace) { + nextStatement = nextStatement.getNextSibling(); + } + + final PsiReturnStatement elseBranch = (PsiReturnStatement) nextStatement; + + final String thenValue; + final PsiExpression thenReturnValue = thenBranch.getReturnValue(); + if (ParenthesesUtils.getPrecendence(thenReturnValue) + <= ParenthesesUtils.CONDITIONAL_EXPRESSION_EXPRESSION) { + thenValue = thenReturnValue.getText(); + } else { + thenValue = '(' + thenReturnValue.getText() + ')'; + + } + final String elseValue; + final PsiExpression elseReturnValue = elseBranch.getReturnValue(); + if (ParenthesesUtils.getPrecendence(elseReturnValue) + <= ParenthesesUtils.CONDITIONAL_EXPRESSION_EXPRESSION) { + elseValue = elseReturnValue.getText(); + } else { + elseValue = '(' + elseReturnValue.getText() + ')'; + + } + final String conditionText; + if (ParenthesesUtils.getPrecendence(condition) + <= ParenthesesUtils.CONDITIONAL_EXPRESSION_EXPRESSION) { + conditionText = condition.getText(); + } else { + conditionText = '(' + condition.getText() + ')'; + + } + + replaceStatement(project, + "return " + conditionText + '?' + thenValue + ':' + elseValue + ';', + ifStatement); + elseBranch.delete(); + } + } + +} diff --git a/plugins/IntentionPowerPak/src/com/siyeh/ipp/trivialif/ReplaceIfWithConditionalPredicate.java b/plugins/IntentionPowerPak/src/com/siyeh/ipp/trivialif/ReplaceIfWithConditionalPredicate.java new file mode 100644 index 000000000000..ff034746736f --- /dev/null +++ b/plugins/IntentionPowerPak/src/com/siyeh/ipp/trivialif/ReplaceIfWithConditionalPredicate.java @@ -0,0 +1,171 @@ +package com.siyeh.ipp.trivialif; + +import com.intellij.psi.*; +import com.siyeh.ipp.PsiElementPredicate; +import com.siyeh.ipp.psiutils.EquivalenceChecker; +import com.siyeh.ipp.psiutils.ConditionalUtils; + +class ReplaceIfWithConditionalPredicate implements PsiElementPredicate +{ + public boolean satisfiedBy(PsiElement element) + { + if(!(element instanceof PsiJavaToken)) + { + return false; + } + final PsiJavaToken token = (PsiJavaToken) element; + + final PsiElement parent = token.getParent(); + if(!(parent instanceof PsiIfStatement)) + { + return false; + } + final PsiIfStatement ifStatement = (PsiIfStatement) parent; + if( isReplaceableAssignment(ifStatement)) + { + return true; + } + if( isReplaceableReturn(ifStatement)) + { + return true; + } + if( isReplaceableImplicitReturn(ifStatement)) + { + return true; + } + return false; + } + + public static boolean isReplaceableImplicitReturn(PsiIfStatement ifStatement) { + PsiElement nextStatement = ifStatement.getNextSibling(); + while (nextStatement != null && nextStatement instanceof PsiWhiteSpace) { + nextStatement = nextStatement.getNextSibling(); + } + if (nextStatement == null) { + return false; + } + if (!(nextStatement instanceof PsiReturnStatement)) { + return false; + } + PsiStatement thenBranch = ifStatement.getThenBranch(); + thenBranch = ConditionalUtils.stripBraces(thenBranch); + if (!(thenBranch instanceof PsiReturnStatement)) { + return false; + } + + final PsiExpression thenReturn = ((PsiReturnStatement) thenBranch).getReturnValue(); + if (thenReturn == null) { + return false; + } + final PsiType thenType = thenReturn.getType(); + if (thenType == null) { + return false; + } + + final PsiExpression elseReturn = ((PsiReturnStatement) nextStatement).getReturnValue(); + if (elseReturn == null) { + return false; + } + final PsiType elseType = elseReturn.getType(); + if (elseType == null) { + return false; + } + + if (!(thenType.isAssignableFrom(elseType) || elseType.isAssignableFrom(thenType))) { + return false; + } + return true; + } + + public static boolean isReplaceableReturn(PsiIfStatement ifStatement) { + PsiStatement thenBranch = ifStatement.getThenBranch(); + thenBranch = ConditionalUtils.stripBraces(thenBranch); + PsiStatement elseBranch = ifStatement.getElseBranch(); + elseBranch = ConditionalUtils.stripBraces(elseBranch); + if (!(thenBranch instanceof PsiReturnStatement) || !(elseBranch instanceof PsiReturnStatement)) { + return false; + } + final PsiExpression thenReturn = ((PsiReturnStatement) thenBranch).getReturnValue(); + if (thenReturn == null) { + return false; + } + final PsiExpression elseReturn = ((PsiReturnStatement) elseBranch).getReturnValue(); + if (elseReturn == null) { + return false; + } + final PsiType thenType = thenReturn.getType(); + final PsiType elseType = elseReturn.getType(); + if (thenType == null || elseType == null) { + return false; + } + if (!(thenType.isAssignableFrom(elseType) || elseType.isAssignableFrom(thenType))) { + return false; + } + return true; + } + + public static boolean isReplaceableAssignment(final PsiIfStatement ifStatement) { + PsiStatement thenBranch = ifStatement.getThenBranch(); + if(thenBranch == null) + { + return false; + } + thenBranch = ConditionalUtils.stripBraces(thenBranch); + + if(!ConditionalUtils.isAssignment(thenBranch)) + { + return false; + } + PsiStatement elseBranch = ifStatement.getElseBranch(); + elseBranch = ConditionalUtils.stripBraces(elseBranch); + if(elseBranch == null) + { + return false; + } + if(!ConditionalUtils.isAssignment(elseBranch)) + { + return false; + } + final PsiAssignmentExpression thenExpression = + (PsiAssignmentExpression) ((PsiExpressionStatement) thenBranch).getExpression(); + final PsiAssignmentExpression elseExpression = + (PsiAssignmentExpression) ((PsiExpressionStatement) elseBranch).getExpression(); + final PsiJavaToken thenSign = thenExpression.getOperationSign(); + final PsiJavaToken elseSign = elseExpression.getOperationSign(); + if(thenSign.getTokenType()!=elseSign.getTokenType()) + { + return false; + } + final PsiExpression thenLhs = thenExpression.getLExpression(); + if(thenExpression.getRExpression() == null || thenLhs == null) + { + return false; + } + if(elseExpression.getRExpression() == null || elseExpression.getLExpression() == null) + { + return false; + } + final PsiExpression thenRhs = thenExpression.getRExpression(); + final PsiType thenType = thenRhs.getType(); + if(thenType == null) + { + return false; + } + final PsiExpression elseRhs = elseExpression.getRExpression(); + final PsiType elseType = elseRhs.getType(); + if(elseType == null) + { + return false; + } + if(!(thenType.isAssignableFrom(elseType) || elseType.isAssignableFrom(thenType))) + { + return false; + } + final PsiExpression elseLhs = elseExpression.getLExpression(); + if(!EquivalenceChecker.expressionsAreEquivalent(thenLhs, elseLhs)) + { + return false; + } + return true; + } +} diff --git a/plugins/IntentionPowerPak/src/com/siyeh/ipp/trivialif/SimplifyIfElseIntention.java b/plugins/IntentionPowerPak/src/com/siyeh/ipp/trivialif/SimplifyIfElseIntention.java new file mode 100644 index 000000000000..b4dd570a5e73 --- /dev/null +++ b/plugins/IntentionPowerPak/src/com/siyeh/ipp/trivialif/SimplifyIfElseIntention.java @@ -0,0 +1,110 @@ +package com.siyeh.ipp.trivialif; + +import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.project.Project; +import com.intellij.psi.*; +import com.intellij.util.IncorrectOperationException; +import com.siyeh.ipp.*; +import com.siyeh.ipp.psiutils.ConditionalUtils; +import com.siyeh.ipp.psiutils.BoolUtils; + +public class SimplifyIfElseIntention extends Intention { + public SimplifyIfElseIntention(Project project) { + super(project); + } + + public String getText() { + return "Simplify if-else"; + } + + public String getFamilyName() { + return "Simplify If Else"; + } + + public PsiElementPredicate getElementPredicate() { + return new SimplifyIfElsePredicate(); + } + + public void invoke(Project project, Editor editor, PsiFile file) throws IncorrectOperationException { + final PsiJavaToken token = (PsiJavaToken) findMatchingElement(file, editor); + final PsiIfStatement statement = (PsiIfStatement) token.getParent(); + if (SimplifyIfElsePredicate.isSimplifiableAssignment(statement)) { + replaceSimplifiableAssignment(statement, project); + } else if (SimplifyIfElsePredicate.isSimplifiableReturn(statement)) { + repaceSimplifiableReturn(statement, project); + } else if (SimplifyIfElsePredicate.isSimplifiableImplicitReturn(statement)) { + replaceSimplifiableImplicitReturn(statement, project); + } else if (SimplifyIfElsePredicate.isSimplifiableAssignmentNegated(statement)) { + replaceSimplifiableAssignmentNegated(statement, project); + } else if (SimplifyIfElsePredicate.isSimplifiableReturnNegated(statement)) { + repaceSimplifiableReturnNegated(statement, project); + } else if (SimplifyIfElsePredicate.isSimplifiableImplicitReturnNegated(statement)) { + replaceSimplifiableImplicitReturnNegated(statement, project); + } + } + + private static void replaceSimplifiableImplicitReturn(PsiIfStatement statement, Project project) throws IncorrectOperationException { + final PsiExpression condition = statement.getCondition(); + final String conditionText = condition.getText(); + PsiElement nextStatement = statement.getNextSibling(); + while (nextStatement instanceof PsiWhiteSpace) { + nextStatement = nextStatement.getNextSibling(); + } + final String newStatement = "return " + conditionText + ';'; + replaceStatement(project, newStatement, statement); + nextStatement.delete(); + } + + private static void repaceSimplifiableReturn(PsiIfStatement statement, Project project) throws IncorrectOperationException { + final PsiExpression condition = statement.getCondition(); + final String conditionText = condition.getText(); + final String newStatement = "return " + conditionText + ';'; + replaceStatement(project, newStatement, statement); + } + + private static void replaceSimplifiableAssignment(PsiIfStatement statement, Project project) throws IncorrectOperationException { + final PsiExpression condition = statement.getCondition(); + final String conditionText = condition.getText(); + final PsiStatement thenBranch = statement.getThenBranch(); + final PsiExpressionStatement assignmentStatement = (PsiExpressionStatement) ConditionalUtils.stripBraces(thenBranch); + final PsiAssignmentExpression assignmentExpression = (PsiAssignmentExpression) assignmentStatement.getExpression(); + final PsiJavaToken operator = assignmentExpression.getOperationSign(); + final String operand = operator.getText(); + final PsiExpression lhs = assignmentExpression.getLExpression(); + final String lhsText = lhs.getText(); + replaceStatement(project, lhsText + operand + conditionText + ';', statement); + } + + private static void replaceSimplifiableImplicitReturnNegated(PsiIfStatement statement, Project project) throws IncorrectOperationException { + final PsiExpression condition = statement.getCondition(); + final String conditionText =BoolUtils.getNegatedExpressionText(condition); + PsiElement nextStatement = statement.getNextSibling(); + while (nextStatement instanceof PsiWhiteSpace) { + nextStatement = nextStatement.getNextSibling(); + } + final String newStatement = "return " + conditionText + ';'; + replaceStatement(project, newStatement, statement); + nextStatement.delete(); + } + + private static void repaceSimplifiableReturnNegated(PsiIfStatement statement, Project project) throws IncorrectOperationException { + final PsiExpression condition = statement.getCondition(); + final String conditionText = BoolUtils.getNegatedExpressionText(condition); + final String newStatement = "return " + conditionText + ';'; + replaceStatement(project, newStatement, statement); + } + + private static void replaceSimplifiableAssignmentNegated(PsiIfStatement statement, Project project) throws IncorrectOperationException { + final PsiExpression condition = statement.getCondition(); + final String conditionText = BoolUtils.getNegatedExpressionText(condition); + final PsiStatement thenBranch = statement.getThenBranch(); + final PsiExpressionStatement assignmentStatement = (PsiExpressionStatement) ConditionalUtils.stripBraces(thenBranch); + final PsiAssignmentExpression assignmentExpression = (PsiAssignmentExpression) assignmentStatement.getExpression(); + final PsiJavaToken operator = assignmentExpression.getOperationSign(); + final String operand = operator.getText(); + final PsiExpression lhs = assignmentExpression.getLExpression(); + final String lhsText = lhs.getText(); + replaceStatement(project, lhsText + operand + conditionText + ';', statement); + } + +} diff --git a/plugins/IntentionPowerPak/src/com/siyeh/ipp/trivialif/SimplifyIfElsePredicate.java b/plugins/IntentionPowerPak/src/com/siyeh/ipp/trivialif/SimplifyIfElsePredicate.java new file mode 100644 index 000000000000..672f8155324e --- /dev/null +++ b/plugins/IntentionPowerPak/src/com/siyeh/ipp/trivialif/SimplifyIfElsePredicate.java @@ -0,0 +1,156 @@ +package com.siyeh.ipp.trivialif; + +import com.intellij.psi.*; +import com.siyeh.ipp.PsiElementPredicate; +import com.siyeh.ipp.psiutils.ConditionalUtils; +import com.siyeh.ipp.psiutils.EquivalenceChecker; + +class SimplifyIfElsePredicate implements PsiElementPredicate { + public boolean satisfiedBy(PsiElement element) { + if (!(element instanceof PsiJavaToken)) { + return false; + } + final PsiJavaToken token = (PsiJavaToken) element; + + final PsiElement parent = token.getParent(); + if (!(parent instanceof PsiIfStatement)) { + return false; + } + final PsiIfStatement ifStatement = (PsiIfStatement) parent; + if (isSimplifiableAssignment(ifStatement)) { + return true; + } + + if (isSimplifiableReturn(ifStatement)) { + return true; + } + + if (isSimplifiableImplicitReturn(ifStatement)) { + return true; + } + if (isSimplifiableAssignmentNegated(ifStatement)) { + return true; + } + + if (isSimplifiableReturnNegated(ifStatement)) { + return true; + } + + if (isSimplifiableImplicitReturnNegated(ifStatement)) { + return true; + } + return false; + } + + public static boolean isSimplifiableImplicitReturn(PsiIfStatement ifStatement) { + PsiStatement thenBranch = ifStatement.getThenBranch(); + thenBranch = ConditionalUtils.stripBraces(thenBranch); + PsiElement nextStatement = ifStatement.getNextSibling(); + while (nextStatement != null && nextStatement instanceof PsiWhiteSpace) { + nextStatement = nextStatement.getNextSibling(); + } + if (nextStatement == null) { + return false; + } + if (!(nextStatement instanceof PsiStatement)) { + return false; + } + final PsiStatement elseBranch = (PsiStatement) nextStatement; + if (ConditionalUtils.isReturn(thenBranch, "true") + && ConditionalUtils.isReturn(elseBranch, "false")) { + return true; + } + return false; + } + public static boolean isSimplifiableImplicitReturnNegated(PsiIfStatement ifStatement) { + PsiStatement thenBranch = ifStatement.getThenBranch(); + thenBranch = ConditionalUtils.stripBraces(thenBranch); + PsiElement nextStatement = ifStatement.getNextSibling(); + while (nextStatement != null && nextStatement instanceof PsiWhiteSpace) { + nextStatement = nextStatement.getNextSibling(); + } + if (nextStatement == null) { + return false; + } + if (!(nextStatement instanceof PsiStatement)) { + return false; + } + final PsiStatement elseBranch = (PsiStatement) nextStatement; + if (ConditionalUtils.isReturn(thenBranch, "false") + && ConditionalUtils.isReturn(elseBranch, "true")) { + return true; + } + return false; + } + + public static boolean isSimplifiableReturn(PsiIfStatement ifStatement) { + PsiStatement thenBranch = ifStatement.getThenBranch(); + thenBranch = ConditionalUtils.stripBraces(thenBranch); + PsiStatement elseBranch = ifStatement.getElseBranch(); + elseBranch = ConditionalUtils.stripBraces(elseBranch); + if (ConditionalUtils.isReturn(thenBranch, "true") + && ConditionalUtils.isReturn(elseBranch, "false")) { + return true; + } + return false; + } + + public static boolean isSimplifiableReturnNegated(PsiIfStatement ifStatement) { + PsiStatement thenBranch = ifStatement.getThenBranch(); + thenBranch = ConditionalUtils.stripBraces(thenBranch); + PsiStatement elseBranch = ifStatement.getElseBranch(); + elseBranch = ConditionalUtils.stripBraces(elseBranch); + if (ConditionalUtils.isReturn(thenBranch, "false") + && ConditionalUtils.isReturn(elseBranch, "true")) { + return true; + } + return false; + } + + public static boolean isSimplifiableAssignment(PsiIfStatement ifStatement) { + PsiStatement thenBranch = ifStatement.getThenBranch(); + thenBranch = ConditionalUtils.stripBraces(thenBranch); + PsiStatement elseBranch = ifStatement.getElseBranch(); + elseBranch = ConditionalUtils.stripBraces(elseBranch); + if (ConditionalUtils.isAssignment(thenBranch, "true") && + ConditionalUtils.isAssignment(elseBranch, "false")) { + final PsiAssignmentExpression thenExpression = + (PsiAssignmentExpression) ((PsiExpressionStatement) thenBranch).getExpression(); + final PsiAssignmentExpression elseExpression = + (PsiAssignmentExpression) ((PsiExpressionStatement) elseBranch).getExpression(); + final PsiJavaToken thenSign = thenExpression.getOperationSign(); + final PsiJavaToken elseSign = elseExpression.getOperationSign(); + if (!thenSign.getTokenType().equals(elseSign.getTokenType())) { + return false; + } + final PsiExpression thenLhs = thenExpression.getLExpression(); + final PsiExpression elseLhs = elseExpression.getLExpression(); + return EquivalenceChecker.expressionsAreEquivalent(thenLhs, elseLhs); + } else { + return false; + } + } + public static boolean isSimplifiableAssignmentNegated(PsiIfStatement ifStatement) { + PsiStatement thenBranch = ifStatement.getThenBranch(); + thenBranch = ConditionalUtils.stripBraces(thenBranch); + PsiStatement elseBranch = ifStatement.getElseBranch(); + elseBranch = ConditionalUtils.stripBraces(elseBranch); + if (ConditionalUtils.isAssignment(thenBranch, "false") && + ConditionalUtils.isAssignment(elseBranch, "true")) { + final PsiAssignmentExpression thenExpression = + (PsiAssignmentExpression) ((PsiExpressionStatement) thenBranch).getExpression(); + final PsiAssignmentExpression elseExpression = + (PsiAssignmentExpression) ((PsiExpressionStatement) elseBranch).getExpression(); + final PsiJavaToken thenSign = thenExpression.getOperationSign(); + final PsiJavaToken elseSign = elseExpression.getOperationSign(); + if (!thenSign.getTokenType().equals(elseSign.getTokenType())) { + return false; + } + final PsiExpression thenLhs = thenExpression.getLExpression(); + final PsiExpression elseLhs = elseExpression.getLExpression(); + return EquivalenceChecker.expressionsAreEquivalent(thenLhs, elseLhs); + } else { + return false; + } + } +} diff --git a/plugins/IntentionPowerPak/src/com/siyeh/ipp/trivialif/SplitElseIfIntention.java b/plugins/IntentionPowerPak/src/com/siyeh/ipp/trivialif/SplitElseIfIntention.java new file mode 100644 index 000000000000..8368aa9143ad --- /dev/null +++ b/plugins/IntentionPowerPak/src/com/siyeh/ipp/trivialif/SplitElseIfIntention.java @@ -0,0 +1,44 @@ +package com.siyeh.ipp.trivialif; + +import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.project.Project; +import com.intellij.psi.*; +import com.intellij.util.IncorrectOperationException; +import com.siyeh.ipp.Intention; +import com.siyeh.ipp.PsiElementPredicate; + +public class SplitElseIfIntention extends Intention +{ + public SplitElseIfIntention(Project project) + { + super(project); + } + + public String getText() + { + return "Split else-if"; + } + + public String getFamilyName() + { + return "Split Else If"; + } + + public PsiElementPredicate getElementPredicate() + { + return new SplitElseIfPredicate(); + } + + public void invoke(Project project, Editor editor, PsiFile file) throws IncorrectOperationException + { + final PsiJavaToken token = (PsiJavaToken) findMatchingElement(file, editor); + final PsiIfStatement parentStatement = (PsiIfStatement) token.getParent(); + final PsiStatement thenBranch = parentStatement.getThenBranch(); + final PsiStatement elseBranch = parentStatement.getElseBranch(); + final PsiExpression condition = parentStatement.getCondition(); + + final String newStatement = "if(" + condition.getText() + ')' +thenBranch.getText() + "else{" + elseBranch.getText() + '}'; + + replaceStatement(project, newStatement, parentStatement); + } +} \ No newline at end of file diff --git a/plugins/IntentionPowerPak/src/com/siyeh/ipp/trivialif/SplitElseIfPredicate.java b/plugins/IntentionPowerPak/src/com/siyeh/ipp/trivialif/SplitElseIfPredicate.java new file mode 100644 index 000000000000..d8553af1806f --- /dev/null +++ b/plugins/IntentionPowerPak/src/com/siyeh/ipp/trivialif/SplitElseIfPredicate.java @@ -0,0 +1,47 @@ +package com.siyeh.ipp.trivialif; + +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiIfStatement; +import com.intellij.psi.PsiJavaToken; +import com.intellij.psi.PsiStatement; +import com.siyeh.ipp.PsiElementPredicate; + +class SplitElseIfPredicate implements PsiElementPredicate +{ + public boolean satisfiedBy(PsiElement element) + { + if(!(element instanceof PsiJavaToken)) + { + return false; + } + final String text = element.getText(); + if(!"else".equals(text)) + { + return false; + } + final PsiJavaToken token = (PsiJavaToken) element; + + final PsiElement parent = token.getParent(); + if(!(parent instanceof PsiIfStatement)) + { + return false; + } + final PsiIfStatement ifStatement = (PsiIfStatement) parent; + final PsiStatement thenBranch = ifStatement.getThenBranch(); + final PsiStatement elseBranch = ifStatement.getElseBranch(); + if(thenBranch == null) + { + return false; + } + if(elseBranch == null) + { + return false; + } + if(!(elseBranch instanceof PsiIfStatement)) + { + return false; + } + + return true; + } +} diff --git a/plugins/IntentionPowerPak/src/intentionDescriptions/Convert To Decimal/after.java.template b/plugins/IntentionPowerPak/src/intentionDescriptions/Convert To Decimal/after.java.template new file mode 100644 index 000000000000..47601b788a01 --- /dev/null +++ b/plugins/IntentionPowerPak/src/intentionDescriptions/Convert To Decimal/after.java.template @@ -0,0 +1,5 @@ +public class X { + void f() { + int i = 65535; + } +} \ No newline at end of file diff --git a/plugins/IntentionPowerPak/src/intentionDescriptions/Convert To Decimal/before.java.template b/plugins/IntentionPowerPak/src/intentionDescriptions/Convert To Decimal/before.java.template new file mode 100644 index 000000000000..9a5af10400fd --- /dev/null +++ b/plugins/IntentionPowerPak/src/intentionDescriptions/Convert To Decimal/before.java.template @@ -0,0 +1,5 @@ +public class X { + void f() { + int i = 0xffff; + } +} \ No newline at end of file diff --git a/plugins/IntentionPowerPak/src/intentionDescriptions/Convert To Decimal/description.html b/plugins/IntentionPowerPak/src/intentionDescriptions/Convert To Decimal/description.html new file mode 100644 index 000000000000..34d23b3f1bb6 --- /dev/null +++ b/plugins/IntentionPowerPak/src/intentionDescriptions/Convert To Decimal/description.html @@ -0,0 +1,10 @@ + + +This intention converts selected integer literal (written in either hex or octal notation) +back into decimal notation. + + +

+Powered by IntentionPowerPack + + diff --git a/plugins/IntentionPowerPak/src/intentionDescriptions/Convert To Hexadecimal/after.java.template b/plugins/IntentionPowerPak/src/intentionDescriptions/Convert To Hexadecimal/after.java.template new file mode 100644 index 000000000000..cf8635d30db8 --- /dev/null +++ b/plugins/IntentionPowerPak/src/intentionDescriptions/Convert To Hexadecimal/after.java.template @@ -0,0 +1,5 @@ +public class X { + void f() { + int i = 0xff; + } +} \ No newline at end of file diff --git a/plugins/IntentionPowerPak/src/intentionDescriptions/Convert To Hexadecimal/before.java.template b/plugins/IntentionPowerPak/src/intentionDescriptions/Convert To Hexadecimal/before.java.template new file mode 100644 index 000000000000..0d4511d13aa9 --- /dev/null +++ b/plugins/IntentionPowerPak/src/intentionDescriptions/Convert To Hexadecimal/before.java.template @@ -0,0 +1,5 @@ +public class X { + void f() { + int i = 255; + } +} \ No newline at end of file diff --git a/plugins/IntentionPowerPak/src/intentionDescriptions/Convert To Hexadecimal/description.html b/plugins/IntentionPowerPak/src/intentionDescriptions/Convert To Hexadecimal/description.html new file mode 100644 index 000000000000..61f2c695056c --- /dev/null +++ b/plugins/IntentionPowerPak/src/intentionDescriptions/Convert To Hexadecimal/description.html @@ -0,0 +1,10 @@ + + +This intention converts selected integer literal (written in either decimal or octal notation) +into hexadecimal notation. + + +

+Powered by IntentionPowerPack + + diff --git a/plugins/IntentionPowerPak/src/intentionDescriptions/Convert To Octal/after.java.template b/plugins/IntentionPowerPak/src/intentionDescriptions/Convert To Octal/after.java.template new file mode 100644 index 000000000000..f2aafc200423 --- /dev/null +++ b/plugins/IntentionPowerPak/src/intentionDescriptions/Convert To Octal/after.java.template @@ -0,0 +1,5 @@ +public class X { + void f() { + int i = 020; + } +} \ No newline at end of file diff --git a/plugins/IntentionPowerPak/src/intentionDescriptions/Convert To Octal/before.java.template b/plugins/IntentionPowerPak/src/intentionDescriptions/Convert To Octal/before.java.template new file mode 100644 index 000000000000..6e7e7194f02d --- /dev/null +++ b/plugins/IntentionPowerPak/src/intentionDescriptions/Convert To Octal/before.java.template @@ -0,0 +1,5 @@ +public class X { + void f() { + int i = 16; + } +} \ No newline at end of file diff --git a/plugins/IntentionPowerPak/src/intentionDescriptions/Convert To Octal/description.html b/plugins/IntentionPowerPak/src/intentionDescriptions/Convert To Octal/description.html new file mode 100644 index 000000000000..9f023d773fcf --- /dev/null +++ b/plugins/IntentionPowerPak/src/intentionDescriptions/Convert To Octal/description.html @@ -0,0 +1,10 @@ + + +This intention converts selected integer literal (written in either decimal or hexadecimal notation) +into octal notation. + + +

+Powered by IntentionPowerPack + + diff --git a/plugins/IntentionPowerPak/src/intentionDescriptions/DeMorgan Law/after.java.template b/plugins/IntentionPowerPak/src/intentionDescriptions/DeMorgan Law/after.java.template new file mode 100644 index 000000000000..4e68547c700d --- /dev/null +++ b/plugins/IntentionPowerPak/src/intentionDescriptions/DeMorgan Law/after.java.template @@ -0,0 +1,5 @@ +public class X { + void f(boolean a, boolean b) { + if (!(a && b)) return; + } +} \ No newline at end of file diff --git a/plugins/IntentionPowerPak/src/intentionDescriptions/DeMorgan Law/before.java.template b/plugins/IntentionPowerPak/src/intentionDescriptions/DeMorgan Law/before.java.template new file mode 100644 index 000000000000..cb26c2b7cfe6 --- /dev/null +++ b/plugins/IntentionPowerPak/src/intentionDescriptions/DeMorgan Law/before.java.template @@ -0,0 +1,5 @@ +public class X { + void f(boolean a, boolean b) { + if (!a || !b) return; + } +} \ No newline at end of file diff --git a/plugins/IntentionPowerPak/src/intentionDescriptions/DeMorgan Law/description.html b/plugins/IntentionPowerPak/src/intentionDescriptions/DeMorgan Law/description.html new file mode 100644 index 000000000000..2fd1d583ffe2 --- /dev/null +++ b/plugins/IntentionPowerPak/src/intentionDescriptions/DeMorgan Law/description.html @@ -0,0 +1,19 @@ + + +This intention replaces either + + + +
    + a || b with !(!a && !b) or +
    + a && b with !(!a || !b) +
+ +inside boolean expression. + + +

+Powered by IntentionPowerPack + + diff --git a/plugins/IntentionPowerPak/src/intentionDescriptions/Detail Exceptions/after.java.template b/plugins/IntentionPowerPak/src/intentionDescriptions/Detail Exceptions/after.java.template new file mode 100644 index 000000000000..c215d0e6581f --- /dev/null +++ b/plugins/IntentionPowerPak/src/intentionDescriptions/Detail Exceptions/after.java.template @@ -0,0 +1,11 @@ +import java.io.*; + +public class X { + void f() { + try { + new FileInputStream("file.txt"); + } + catch (FileNotFoundException e) { + } + } +} \ No newline at end of file diff --git a/plugins/IntentionPowerPak/src/intentionDescriptions/Detail Exceptions/before.java.template b/plugins/IntentionPowerPak/src/intentionDescriptions/Detail Exceptions/before.java.template new file mode 100644 index 000000000000..9140eca80072 --- /dev/null +++ b/plugins/IntentionPowerPak/src/intentionDescriptions/Detail Exceptions/before.java.template @@ -0,0 +1,11 @@ +import java.io.*; + +public class X { + void f() { + try { + new FileInputStream("file.txt"); + } + catch (Throwable e) { + } + } +} \ No newline at end of file diff --git a/plugins/IntentionPowerPak/src/intentionDescriptions/Detail Exceptions/description.html b/plugins/IntentionPowerPak/src/intentionDescriptions/Detail Exceptions/description.html new file mode 100644 index 000000000000..a6e3c23c7883 --- /dev/null +++ b/plugins/IntentionPowerPak/src/intentionDescriptions/Detail Exceptions/description.html @@ -0,0 +1,9 @@ + + +This intention replaces too broad exceptions in the catch clause with more specific ones.
+
+ +

+Powered by IntentionPowerPack + + diff --git a/plugins/IntentionPowerPak/src/intentionDescriptions/Expand Boolean/after.java.template b/plugins/IntentionPowerPak/src/intentionDescriptions/Expand Boolean/after.java.template new file mode 100644 index 000000000000..ffb16defa19a --- /dev/null +++ b/plugins/IntentionPowerPak/src/intentionDescriptions/Expand Boolean/after.java.template @@ -0,0 +1,10 @@ +public class X { + boolean f(boolean a) { + if(a){ + return true; + } + else{ + return false; + } + } +} \ No newline at end of file diff --git a/plugins/IntentionPowerPak/src/intentionDescriptions/Expand Boolean/before.java.template b/plugins/IntentionPowerPak/src/intentionDescriptions/Expand Boolean/before.java.template new file mode 100644 index 000000000000..ee3d23a3745e --- /dev/null +++ b/plugins/IntentionPowerPak/src/intentionDescriptions/Expand Boolean/before.java.template @@ -0,0 +1,5 @@ +public class X { + boolean f(boolean a) { + return a; + } +} \ No newline at end of file diff --git a/plugins/IntentionPowerPak/src/intentionDescriptions/Expand Boolean/description.html b/plugins/IntentionPowerPak/src/intentionDescriptions/Expand Boolean/description.html new file mode 100644 index 000000000000..83a9d7ce477d --- /dev/null +++ b/plugins/IntentionPowerPak/src/intentionDescriptions/Expand Boolean/description.html @@ -0,0 +1,10 @@ + + +This intention replaces uses of boolean values with equivalent if-then-else statements, +if possible. + + +

+Powered by IntentionPowerPack + + diff --git a/plugins/IntentionPowerPak/src/intentionDescriptions/Flip Assert Literal/after.java.template b/plugins/IntentionPowerPak/src/intentionDescriptions/Flip Assert Literal/after.java.template new file mode 100644 index 000000000000..4981f6771458 --- /dev/null +++ b/plugins/IntentionPowerPak/src/intentionDescriptions/Flip Assert Literal/after.java.template @@ -0,0 +1,5 @@ +public class XTest { + void testFeature() { + assertFalse(!isFeatureWork()); + } +} \ No newline at end of file diff --git a/plugins/IntentionPowerPak/src/intentionDescriptions/Flip Assert Literal/before.java.template b/plugins/IntentionPowerPak/src/intentionDescriptions/Flip Assert Literal/before.java.template new file mode 100644 index 000000000000..131dad5891d5 --- /dev/null +++ b/plugins/IntentionPowerPak/src/intentionDescriptions/Flip Assert Literal/before.java.template @@ -0,0 +1,5 @@ +public class XTest { + void testFeature() { + assertTrue(isFeatureWork()); + } +} \ No newline at end of file diff --git a/plugins/IntentionPowerPak/src/intentionDescriptions/Flip Assert Literal/description.html b/plugins/IntentionPowerPak/src/intentionDescriptions/Flip Assert Literal/description.html new file mode 100644 index 000000000000..4942a4996acd --- /dev/null +++ b/plugins/IntentionPowerPak/src/intentionDescriptions/Flip Assert Literal/description.html @@ -0,0 +1,10 @@ + + +This intention is JUnit specific.
+It replaces an assertTrue() or assertFalse() method call with it's converse. +
+ +

+Powered by IntentionPowerPack + + diff --git a/plugins/IntentionPowerPak/src/intentionDescriptions/Flip Commutative Method Call/after.java.template b/plugins/IntentionPowerPak/src/intentionDescriptions/Flip Commutative Method Call/after.java.template new file mode 100644 index 000000000000..ffbc96e44c6f --- /dev/null +++ b/plugins/IntentionPowerPak/src/intentionDescriptions/Flip Commutative Method Call/after.java.template @@ -0,0 +1,5 @@ +public class X { + void f(Object x) { + if (x.equals(this)) return; + } +} \ No newline at end of file diff --git a/plugins/IntentionPowerPak/src/intentionDescriptions/Flip Commutative Method Call/before.java.template b/plugins/IntentionPowerPak/src/intentionDescriptions/Flip Commutative Method Call/before.java.template new file mode 100644 index 000000000000..9931d0b8e0d6 --- /dev/null +++ b/plugins/IntentionPowerPak/src/intentionDescriptions/Flip Commutative Method Call/before.java.template @@ -0,0 +1,5 @@ +public class X { + void f(Object x) { + if (this.equals(x)) return; + } +} \ No newline at end of file diff --git a/plugins/IntentionPowerPak/src/intentionDescriptions/Flip Commutative Method Call/description.html b/plugins/IntentionPowerPak/src/intentionDescriptions/Flip Commutative Method Call/description.html new file mode 100644 index 000000000000..3ed7dbc627dc --- /dev/null +++ b/plugins/IntentionPowerPak/src/intentionDescriptions/Flip Commutative Method Call/description.html @@ -0,0 +1,10 @@ + + +This intention replaces caller.method(object) with object.method(caller) if possible.
+ +
+ +

+Powered by IntentionPowerPack + + diff --git a/plugins/IntentionPowerPak/src/intentionDescriptions/Flip Comparison/after.java.template b/plugins/IntentionPowerPak/src/intentionDescriptions/Flip Comparison/after.java.template new file mode 100644 index 000000000000..68db49da5167 --- /dev/null +++ b/plugins/IntentionPowerPak/src/intentionDescriptions/Flip Comparison/after.java.template @@ -0,0 +1,5 @@ +public class X { + void f(int a, int b) { + if (b == a) return; + } +} \ No newline at end of file diff --git a/plugins/IntentionPowerPak/src/intentionDescriptions/Flip Comparison/before.java.template b/plugins/IntentionPowerPak/src/intentionDescriptions/Flip Comparison/before.java.template new file mode 100644 index 000000000000..6f650cc79b8a --- /dev/null +++ b/plugins/IntentionPowerPak/src/intentionDescriptions/Flip Comparison/before.java.template @@ -0,0 +1,5 @@ +public class X { + void f(int a, int b) { + if (a == b) return; + } +} \ No newline at end of file diff --git a/plugins/IntentionPowerPak/src/intentionDescriptions/Flip Comparison/description.html b/plugins/IntentionPowerPak/src/intentionDescriptions/Flip Comparison/description.html new file mode 100644 index 000000000000..651b8c979e64 --- /dev/null +++ b/plugins/IntentionPowerPak/src/intentionDescriptions/Flip Comparison/description.html @@ -0,0 +1,10 @@ + + +This intention swaps operands of comparasion expression.
+ +
+ +

+Powered by IntentionPowerPack + + diff --git a/plugins/IntentionPowerPak/src/intentionDescriptions/Flip Conditional/after.java.template b/plugins/IntentionPowerPak/src/intentionDescriptions/Flip Conditional/after.java.template new file mode 100644 index 000000000000..b6248b9b1858 --- /dev/null +++ b/plugins/IntentionPowerPak/src/intentionDescriptions/Flip Conditional/after.java.template @@ -0,0 +1,5 @@ +public class X { + int f(boolean a) { + return a ? 2 : 1; + } +} \ No newline at end of file diff --git a/plugins/IntentionPowerPak/src/intentionDescriptions/Flip Conditional/before.java.template b/plugins/IntentionPowerPak/src/intentionDescriptions/Flip Conditional/before.java.template new file mode 100644 index 000000000000..029d2a738d24 --- /dev/null +++ b/plugins/IntentionPowerPak/src/intentionDescriptions/Flip Conditional/before.java.template @@ -0,0 +1,5 @@ +public class X { + int f(boolean a) { + return !a ? 1 : 2; + } +} \ No newline at end of file diff --git a/plugins/IntentionPowerPak/src/intentionDescriptions/Flip Conditional/description.html b/plugins/IntentionPowerPak/src/intentionDescriptions/Flip Conditional/description.html new file mode 100644 index 000000000000..ea1487e11b30 --- /dev/null +++ b/plugins/IntentionPowerPak/src/intentionDescriptions/Flip Conditional/description.html @@ -0,0 +1,9 @@ + + +This intention flips branches of the conditional operator. + + +

+Powered by IntentionPowerPack + + diff --git a/plugins/IntentionPowerPak/src/intentionDescriptions/Flip Conjunction Operands/after.java.template b/plugins/IntentionPowerPak/src/intentionDescriptions/Flip Conjunction Operands/after.java.template new file mode 100644 index 000000000000..6d898b1ce4a5 --- /dev/null +++ b/plugins/IntentionPowerPak/src/intentionDescriptions/Flip Conjunction Operands/after.java.template @@ -0,0 +1,5 @@ +public class X { + void f(boolean a, boolean b) { + if (b && a) return; + } +} \ No newline at end of file diff --git a/plugins/IntentionPowerPak/src/intentionDescriptions/Flip Conjunction Operands/before.java.template b/plugins/IntentionPowerPak/src/intentionDescriptions/Flip Conjunction Operands/before.java.template new file mode 100644 index 000000000000..450e6cd9b76d --- /dev/null +++ b/plugins/IntentionPowerPak/src/intentionDescriptions/Flip Conjunction Operands/before.java.template @@ -0,0 +1,5 @@ +public class X { + void f(boolean a, boolean b) { + if (a && b) return; + } +} \ No newline at end of file diff --git a/plugins/IntentionPowerPak/src/intentionDescriptions/Flip Conjunction Operands/description.html b/plugins/IntentionPowerPak/src/intentionDescriptions/Flip Conjunction Operands/description.html new file mode 100644 index 000000000000..e6b36609fc64 --- /dev/null +++ b/plugins/IntentionPowerPak/src/intentionDescriptions/Flip Conjunction Operands/description.html @@ -0,0 +1,10 @@ + + +This intention swaps operands of && or || expression.
+ +
+ +

+Powered by IntentionPowerPack + + diff --git a/plugins/IntentionPowerPak/src/intentionDescriptions/Join Concatenated String Literals/after.java.template b/plugins/IntentionPowerPak/src/intentionDescriptions/Join Concatenated String Literals/after.java.template new file mode 100644 index 000000000000..6439c376275b --- /dev/null +++ b/plugins/IntentionPowerPak/src/intentionDescriptions/Join Concatenated String Literals/after.java.template @@ -0,0 +1,5 @@ +public class X { + String f() { + return "foobar"); + } +} \ No newline at end of file diff --git a/plugins/IntentionPowerPak/src/intentionDescriptions/Join Concatenated String Literals/before.java.template b/plugins/IntentionPowerPak/src/intentionDescriptions/Join Concatenated String Literals/before.java.template new file mode 100644 index 000000000000..06c8b47573e7 --- /dev/null +++ b/plugins/IntentionPowerPak/src/intentionDescriptions/Join Concatenated String Literals/before.java.template @@ -0,0 +1,5 @@ +public class X { + String f() { + return "foo" + "bar"; + } +} \ No newline at end of file diff --git a/plugins/IntentionPowerPak/src/intentionDescriptions/Join Concatenated String Literals/description.html b/plugins/IntentionPowerPak/src/intentionDescriptions/Join Concatenated String Literals/description.html new file mode 100644 index 000000000000..00c18de3080f --- /dev/null +++ b/plugins/IntentionPowerPak/src/intentionDescriptions/Join Concatenated String Literals/description.html @@ -0,0 +1,9 @@ + + +This intention joins adjacent concatenated string literals into a single literal.
+
+ +

+Powered by IntentionPowerPack + + diff --git a/plugins/IntentionPowerPak/src/intentionDescriptions/Merge Equivalent Ifs To ORed Condition/after.java.template b/plugins/IntentionPowerPak/src/intentionDescriptions/Merge Equivalent Ifs To ORed Condition/after.java.template new file mode 100644 index 000000000000..7c68216df97b --- /dev/null +++ b/plugins/IntentionPowerPak/src/intentionDescriptions/Merge Equivalent Ifs To ORed Condition/after.java.template @@ -0,0 +1,8 @@ +public class X { + boolean f(boolean a, boolean b) { + if (!a || b) { + return true; + } + return false; + } +} \ No newline at end of file diff --git a/plugins/IntentionPowerPak/src/intentionDescriptions/Merge Equivalent Ifs To ORed Condition/before.java.template b/plugins/IntentionPowerPak/src/intentionDescriptions/Merge Equivalent Ifs To ORed Condition/before.java.template new file mode 100644 index 000000000000..ee8d7a205a96 --- /dev/null +++ b/plugins/IntentionPowerPak/src/intentionDescriptions/Merge Equivalent Ifs To ORed Condition/before.java.template @@ -0,0 +1,11 @@ +public class X { + boolean f(boolean a, boolean b) { + if (!a) { + return true; + } + else if (b) { + return true; + } + return false; + } +} \ No newline at end of file diff --git a/plugins/IntentionPowerPak/src/intentionDescriptions/Merge Equivalent Ifs To ORed Condition/description.html b/plugins/IntentionPowerPak/src/intentionDescriptions/Merge Equivalent Ifs To ORed Condition/description.html new file mode 100644 index 000000000000..38f5f5fd2e2d --- /dev/null +++ b/plugins/IntentionPowerPak/src/intentionDescriptions/Merge Equivalent Ifs To ORed Condition/description.html @@ -0,0 +1,10 @@ + + +This intention merges if-else statement into a single if statement, +if their bodies are identical.
+
+ +

+Powered by IntentionPowerPack + + diff --git a/plugins/IntentionPowerPak/src/intentionDescriptions/Merge Nested Ifs To ANDed Condition/after.java.template b/plugins/IntentionPowerPak/src/intentionDescriptions/Merge Nested Ifs To ANDed Condition/after.java.template new file mode 100644 index 000000000000..53d45e760ecc --- /dev/null +++ b/plugins/IntentionPowerPak/src/intentionDescriptions/Merge Nested Ifs To ANDed Condition/after.java.template @@ -0,0 +1,8 @@ +public class X { + boolean f(boolean a, boolean b) { + if (!a && b) { + return true; + } + return false; + } +} \ No newline at end of file diff --git a/plugins/IntentionPowerPak/src/intentionDescriptions/Merge Nested Ifs To ANDed Condition/before.java.template b/plugins/IntentionPowerPak/src/intentionDescriptions/Merge Nested Ifs To ANDed Condition/before.java.template new file mode 100644 index 000000000000..79b9c792d0aa --- /dev/null +++ b/plugins/IntentionPowerPak/src/intentionDescriptions/Merge Nested Ifs To ANDed Condition/before.java.template @@ -0,0 +1,10 @@ +public class X { + boolean f(boolean a, boolean b) { + if (!a) { + if (b) { + return true; + } + } + return false; + } +} \ No newline at end of file diff --git a/plugins/IntentionPowerPak/src/intentionDescriptions/Merge Nested Ifs To ANDed Condition/description.html b/plugins/IntentionPowerPak/src/intentionDescriptions/Merge Nested Ifs To ANDed Condition/description.html new file mode 100644 index 000000000000..f8dfe11b44d9 --- /dev/null +++ b/plugins/IntentionPowerPak/src/intentionDescriptions/Merge Nested Ifs To ANDed Condition/description.html @@ -0,0 +1,9 @@ + + +This intention merges if-else statement inside then-branch of another if-else into one.
+
+ +

+Powered by IntentionPowerPack + + diff --git a/plugins/IntentionPowerPak/src/intentionDescriptions/Negate Comparison/after.java.template b/plugins/IntentionPowerPak/src/intentionDescriptions/Negate Comparison/after.java.template new file mode 100644 index 000000000000..526959ed7441 --- /dev/null +++ b/plugins/IntentionPowerPak/src/intentionDescriptions/Negate Comparison/after.java.template @@ -0,0 +1,5 @@ +public class X { + void f(int a, int b) { + if (a != b) return; + } +} \ No newline at end of file diff --git a/plugins/IntentionPowerPak/src/intentionDescriptions/Negate Comparison/before.java.template b/plugins/IntentionPowerPak/src/intentionDescriptions/Negate Comparison/before.java.template new file mode 100644 index 000000000000..225a46535f4f --- /dev/null +++ b/plugins/IntentionPowerPak/src/intentionDescriptions/Negate Comparison/before.java.template @@ -0,0 +1,5 @@ +public class X { + void f(int a, int b) { + if (!(a == b)) return; + } +} \ No newline at end of file diff --git a/plugins/IntentionPowerPak/src/intentionDescriptions/Negate Comparison/description.html b/plugins/IntentionPowerPak/src/intentionDescriptions/Negate Comparison/description.html new file mode 100644 index 000000000000..aa3f3ef4628c --- /dev/null +++ b/plugins/IntentionPowerPak/src/intentionDescriptions/Negate Comparison/description.html @@ -0,0 +1,13 @@ + + +This intention converts boolean comparasion expression a op b into + +!(a negop b).
+Where op and negop are mutually inverse comparasion operators, like == and !=. + +
+ +

+Powered by IntentionPowerPack + + diff --git a/plugins/IntentionPowerPak/src/intentionDescriptions/Remove Boolean Equality/after.java.template b/plugins/IntentionPowerPak/src/intentionDescriptions/Remove Boolean Equality/after.java.template new file mode 100644 index 000000000000..c3d8f71e22c0 --- /dev/null +++ b/plugins/IntentionPowerPak/src/intentionDescriptions/Remove Boolean Equality/after.java.template @@ -0,0 +1,5 @@ +public class X { + void f(boolean a) { + if (a) return; + } +} \ No newline at end of file diff --git a/plugins/IntentionPowerPak/src/intentionDescriptions/Remove Boolean Equality/before.java.template b/plugins/IntentionPowerPak/src/intentionDescriptions/Remove Boolean Equality/before.java.template new file mode 100644 index 000000000000..729a3bef0c38 --- /dev/null +++ b/plugins/IntentionPowerPak/src/intentionDescriptions/Remove Boolean Equality/before.java.template @@ -0,0 +1,5 @@ +public class X { + void f(boolean a) { + if (a == true) return; + } +} \ No newline at end of file diff --git a/plugins/IntentionPowerPak/src/intentionDescriptions/Remove Boolean Equality/description.html b/plugins/IntentionPowerPak/src/intentionDescriptions/Remove Boolean Equality/description.html new file mode 100644 index 000000000000..438f8b2ab557 --- /dev/null +++ b/plugins/IntentionPowerPak/src/intentionDescriptions/Remove Boolean Equality/description.html @@ -0,0 +1,9 @@ + + +This intention simplifies comparasion of boolean expression with boolean literal true or false. + + +

+Powered by IntentionPowerPack + + diff --git a/plugins/IntentionPowerPak/src/intentionDescriptions/Remove Pointless Conditional/after.java.template b/plugins/IntentionPowerPak/src/intentionDescriptions/Remove Pointless Conditional/after.java.template new file mode 100644 index 000000000000..a521f7753e01 --- /dev/null +++ b/plugins/IntentionPowerPak/src/intentionDescriptions/Remove Pointless Conditional/after.java.template @@ -0,0 +1,5 @@ +public class X { + boolean f(boolean a) { + return !a; + } +} \ No newline at end of file diff --git a/plugins/IntentionPowerPak/src/intentionDescriptions/Remove Pointless Conditional/before.java.template b/plugins/IntentionPowerPak/src/intentionDescriptions/Remove Pointless Conditional/before.java.template new file mode 100644 index 000000000000..7f45f7d87861 --- /dev/null +++ b/plugins/IntentionPowerPak/src/intentionDescriptions/Remove Pointless Conditional/before.java.template @@ -0,0 +1,5 @@ +public class X { + boolean f(boolean a) { + return !a ? true : false; + } +} \ No newline at end of file diff --git a/plugins/IntentionPowerPak/src/intentionDescriptions/Remove Pointless Conditional/description.html b/plugins/IntentionPowerPak/src/intentionDescriptions/Remove Pointless Conditional/description.html new file mode 100644 index 000000000000..fa51f8ed2390 --- /dev/null +++ b/plugins/IntentionPowerPak/src/intentionDescriptions/Remove Pointless Conditional/description.html @@ -0,0 +1,9 @@ + + +This intention simplifies conditional operator ?: whose branches are boolean literals. + + +

+Powered by IntentionPowerPack + + diff --git a/plugins/IntentionPowerPak/src/intentionDescriptions/Remove Unnecessary Parentheses/after.java.template b/plugins/IntentionPowerPak/src/intentionDescriptions/Remove Unnecessary Parentheses/after.java.template new file mode 100644 index 000000000000..286b7f258199 --- /dev/null +++ b/plugins/IntentionPowerPak/src/intentionDescriptions/Remove Unnecessary Parentheses/after.java.template @@ -0,0 +1,5 @@ +public class X { + boolean f(boolean a) { + return a; + } +} \ No newline at end of file diff --git a/plugins/IntentionPowerPak/src/intentionDescriptions/Remove Unnecessary Parentheses/before.java.template b/plugins/IntentionPowerPak/src/intentionDescriptions/Remove Unnecessary Parentheses/before.java.template new file mode 100644 index 000000000000..c9a9dfeb5f0a --- /dev/null +++ b/plugins/IntentionPowerPak/src/intentionDescriptions/Remove Unnecessary Parentheses/before.java.template @@ -0,0 +1,5 @@ +public class X { + boolean f(boolean a) { + return (a); + } +} \ No newline at end of file diff --git a/plugins/IntentionPowerPak/src/intentionDescriptions/Remove Unnecessary Parentheses/description.html b/plugins/IntentionPowerPak/src/intentionDescriptions/Remove Unnecessary Parentheses/description.html new file mode 100644 index 000000000000..f65a8587d560 --- /dev/null +++ b/plugins/IntentionPowerPak/src/intentionDescriptions/Remove Unnecessary Parentheses/description.html @@ -0,0 +1,9 @@ + + +This intention removes parentheses when when they are redundant.
+
+ +

+Powered by IntentionPowerPack + + diff --git a/plugins/IntentionPowerPak/src/intentionDescriptions/Replace AssertEquals With AssertLiteral/after.java.template b/plugins/IntentionPowerPak/src/intentionDescriptions/Replace AssertEquals With AssertLiteral/after.java.template new file mode 100644 index 000000000000..cc758c92c666 --- /dev/null +++ b/plugins/IntentionPowerPak/src/intentionDescriptions/Replace AssertEquals With AssertLiteral/after.java.template @@ -0,0 +1,5 @@ +public class XTest { + void testFeature() { + assertFalse(isFeatureWork()); + } +} \ No newline at end of file diff --git a/plugins/IntentionPowerPak/src/intentionDescriptions/Replace AssertEquals With AssertLiteral/before.java.template b/plugins/IntentionPowerPak/src/intentionDescriptions/Replace AssertEquals With AssertLiteral/before.java.template new file mode 100644 index 000000000000..17ffdc79ce17 --- /dev/null +++ b/plugins/IntentionPowerPak/src/intentionDescriptions/Replace AssertEquals With AssertLiteral/before.java.template @@ -0,0 +1,5 @@ +public class XTest { + void testFeature() { + assertEquals(false, isFeatureWork()); + } +} \ No newline at end of file diff --git a/plugins/IntentionPowerPak/src/intentionDescriptions/Replace AssertEquals With AssertLiteral/description.html b/plugins/IntentionPowerPak/src/intentionDescriptions/Replace AssertEquals With AssertLiteral/description.html new file mode 100644 index 000000000000..5bbbe09210b1 --- /dev/null +++ b/plugins/IntentionPowerPak/src/intentionDescriptions/Replace AssertEquals With AssertLiteral/description.html @@ -0,0 +1,11 @@ + + +This intention is JUnit specific.
+It replaces an assertEquals()call with an equivalent assertTrue(), assertFalse(), or assertNull() method call, +if possible. +
+ +

+Powered by IntentionPowerPack + + diff --git a/plugins/IntentionPowerPak/src/intentionDescriptions/Replace AssertLiteral With AssertEquals/after.java.template b/plugins/IntentionPowerPak/src/intentionDescriptions/Replace AssertLiteral With AssertEquals/after.java.template new file mode 100644 index 000000000000..bf5774b82960 --- /dev/null +++ b/plugins/IntentionPowerPak/src/intentionDescriptions/Replace AssertLiteral With AssertEquals/after.java.template @@ -0,0 +1,5 @@ +public class XTest { + void testFeature() { + assertEquals(false, isFeatureWork()); + } +} \ No newline at end of file diff --git a/plugins/IntentionPowerPak/src/intentionDescriptions/Replace AssertLiteral With AssertEquals/before.java.template b/plugins/IntentionPowerPak/src/intentionDescriptions/Replace AssertLiteral With AssertEquals/before.java.template new file mode 100644 index 000000000000..7697126e1bd1 --- /dev/null +++ b/plugins/IntentionPowerPak/src/intentionDescriptions/Replace AssertLiteral With AssertEquals/before.java.template @@ -0,0 +1,5 @@ +public class XTest { + void testFeature() { + assertFalse(isFeatureWork()); + } +} \ No newline at end of file diff --git a/plugins/IntentionPowerPak/src/intentionDescriptions/Replace AssertLiteral With AssertEquals/description.html b/plugins/IntentionPowerPak/src/intentionDescriptions/Replace AssertLiteral With AssertEquals/description.html new file mode 100644 index 000000000000..f12fefbd8189 --- /dev/null +++ b/plugins/IntentionPowerPak/src/intentionDescriptions/Replace AssertLiteral With AssertEquals/description.html @@ -0,0 +1,10 @@ + + +This intention is JUnit specific.
+It replaces an assertTrue(), assertFalse() or assertNull() method call with an equivalent assertEquals(). +
+ +

+Powered by IntentionPowerPack + + diff --git a/plugins/IntentionPowerPak/src/intentionDescriptions/Replace Assignment With Operator Assignment/after.java.template b/plugins/IntentionPowerPak/src/intentionDescriptions/Replace Assignment With Operator Assignment/after.java.template new file mode 100644 index 000000000000..d24486699ebb --- /dev/null +++ b/plugins/IntentionPowerPak/src/intentionDescriptions/Replace Assignment With Operator Assignment/after.java.template @@ -0,0 +1,5 @@ +public class X { + void f(boolean a, boolean b) { + a |= b; + } +} \ No newline at end of file diff --git a/plugins/IntentionPowerPak/src/intentionDescriptions/Replace Assignment With Operator Assignment/before.java.template b/plugins/IntentionPowerPak/src/intentionDescriptions/Replace Assignment With Operator Assignment/before.java.template new file mode 100644 index 000000000000..d14d5bd770f7 --- /dev/null +++ b/plugins/IntentionPowerPak/src/intentionDescriptions/Replace Assignment With Operator Assignment/before.java.template @@ -0,0 +1,5 @@ +public class X { + void f(boolean a, boolean b) { + a = a | b; + } +} \ No newline at end of file diff --git a/plugins/IntentionPowerPak/src/intentionDescriptions/Replace Assignment With Operator Assignment/description.html b/plugins/IntentionPowerPak/src/intentionDescriptions/Replace Assignment With Operator Assignment/description.html new file mode 100644 index 000000000000..05ab4447c73d --- /dev/null +++ b/plugins/IntentionPowerPak/src/intentionDescriptions/Replace Assignment With Operator Assignment/description.html @@ -0,0 +1,9 @@ + + +This intention replaces variable assignment statement with assignment operator.
+
+ +

+Powered by IntentionPowerPack + + diff --git a/plugins/IntentionPowerPak/src/intentionDescriptions/Replace Conditional With If Else/after.java.template b/plugins/IntentionPowerPak/src/intentionDescriptions/Replace Conditional With If Else/after.java.template new file mode 100644 index 000000000000..04d39b2bba12 --- /dev/null +++ b/plugins/IntentionPowerPak/src/intentionDescriptions/Replace Conditional With If Else/after.java.template @@ -0,0 +1,10 @@ +public class X { + int f(boolean a) { + if (a) { + return 0; + } + else { + return 1; + } + } +} \ No newline at end of file diff --git a/plugins/IntentionPowerPak/src/intentionDescriptions/Replace Conditional With If Else/before.java.template b/plugins/IntentionPowerPak/src/intentionDescriptions/Replace Conditional With If Else/before.java.template new file mode 100644 index 000000000000..0e4c822c1e6a --- /dev/null +++ b/plugins/IntentionPowerPak/src/intentionDescriptions/Replace Conditional With If Else/before.java.template @@ -0,0 +1,5 @@ +public class X { + int f(boolean a) { + return a ? 0 : 1; + } +} \ No newline at end of file diff --git a/plugins/IntentionPowerPak/src/intentionDescriptions/Replace Conditional With If Else/description.html b/plugins/IntentionPowerPak/src/intentionDescriptions/Replace Conditional With If Else/description.html new file mode 100644 index 000000000000..b276ca8d7850 --- /dev/null +++ b/plugins/IntentionPowerPak/src/intentionDescriptions/Replace Conditional With If Else/description.html @@ -0,0 +1,9 @@ + + +This intention replaces conditional operator with if-else statement. + + +

+Powered by IntentionPowerPack + + diff --git a/plugins/IntentionPowerPak/src/intentionDescriptions/Replace Equality With Equals/after.java.template b/plugins/IntentionPowerPak/src/intentionDescriptions/Replace Equality With Equals/after.java.template new file mode 100644 index 000000000000..0d3e3d605ed5 --- /dev/null +++ b/plugins/IntentionPowerPak/src/intentionDescriptions/Replace Equality With Equals/after.java.template @@ -0,0 +1,5 @@ +public class X { + boolean f(Object o) { + return o.equals(this); + } +} \ No newline at end of file diff --git a/plugins/IntentionPowerPak/src/intentionDescriptions/Replace Equality With Equals/before.java.template b/plugins/IntentionPowerPak/src/intentionDescriptions/Replace Equality With Equals/before.java.template new file mode 100644 index 000000000000..9f012f7f967b --- /dev/null +++ b/plugins/IntentionPowerPak/src/intentionDescriptions/Replace Equality With Equals/before.java.template @@ -0,0 +1,5 @@ +public class X { + boolean f(Object o) { + return o == this; + } +} \ No newline at end of file diff --git a/plugins/IntentionPowerPak/src/intentionDescriptions/Replace Equality With Equals/description.html b/plugins/IntentionPowerPak/src/intentionDescriptions/Replace Equality With Equals/description.html new file mode 100644 index 000000000000..78a657274784 --- /dev/null +++ b/plugins/IntentionPowerPak/src/intentionDescriptions/Replace Equality With Equals/description.html @@ -0,0 +1,9 @@ + + +This intention replaces == equality operator with equals() method call. + + +

+Powered by IntentionPowerPack + + diff --git a/plugins/IntentionPowerPak/src/intentionDescriptions/Replace Equality With Safe Equals/after.java.template b/plugins/IntentionPowerPak/src/intentionDescriptions/Replace Equality With Safe Equals/after.java.template new file mode 100644 index 000000000000..14130a074ce8 --- /dev/null +++ b/plugins/IntentionPowerPak/src/intentionDescriptions/Replace Equality With Safe Equals/after.java.template @@ -0,0 +1,5 @@ +public class X { + boolean f(Object o) { + return o == null ? o1 == null : o.equals(o1); + } +} \ No newline at end of file diff --git a/plugins/IntentionPowerPak/src/intentionDescriptions/Replace Equality With Safe Equals/before.java.template b/plugins/IntentionPowerPak/src/intentionDescriptions/Replace Equality With Safe Equals/before.java.template new file mode 100644 index 000000000000..545d1eab2a09 --- /dev/null +++ b/plugins/IntentionPowerPak/src/intentionDescriptions/Replace Equality With Safe Equals/before.java.template @@ -0,0 +1,5 @@ +public class X { + boolean f(Object o, Object o1) { + return o == o1; + } +} \ No newline at end of file diff --git a/plugins/IntentionPowerPak/src/intentionDescriptions/Replace Equality With Safe Equals/description.html b/plugins/IntentionPowerPak/src/intentionDescriptions/Replace Equality With Safe Equals/description.html new file mode 100644 index 000000000000..d0e0f18cc0d9 --- /dev/null +++ b/plugins/IntentionPowerPak/src/intentionDescriptions/Replace Equality With Safe Equals/description.html @@ -0,0 +1,9 @@ + + +This intention replaces == equality operator with safe equals() method call. + + +

+Powered by IntentionPowerPack + + diff --git a/plugins/IntentionPowerPak/src/intentionDescriptions/Replace Equals With Equality/after.java.template b/plugins/IntentionPowerPak/src/intentionDescriptions/Replace Equals With Equality/after.java.template new file mode 100644 index 000000000000..6af69ad29666 --- /dev/null +++ b/plugins/IntentionPowerPak/src/intentionDescriptions/Replace Equals With Equality/after.java.template @@ -0,0 +1,5 @@ +public class X { + boolean f(Object o) { + return o == this; + } +} \ No newline at end of file diff --git a/plugins/IntentionPowerPak/src/intentionDescriptions/Replace Equals With Equality/before.java.template b/plugins/IntentionPowerPak/src/intentionDescriptions/Replace Equals With Equality/before.java.template new file mode 100644 index 000000000000..277a9e230d02 --- /dev/null +++ b/plugins/IntentionPowerPak/src/intentionDescriptions/Replace Equals With Equality/before.java.template @@ -0,0 +1,5 @@ +public class X { + boolean f(Object o) { + return o.equals(this); + } +} \ No newline at end of file diff --git a/plugins/IntentionPowerPak/src/intentionDescriptions/Replace Equals With Equality/description.html b/plugins/IntentionPowerPak/src/intentionDescriptions/Replace Equals With Equality/description.html new file mode 100644 index 000000000000..01c52b744b21 --- /dev/null +++ b/plugins/IntentionPowerPak/src/intentionDescriptions/Replace Equals With Equality/description.html @@ -0,0 +1,9 @@ + + +This intention replaces equals() method call with == equality operator. + + +

+Powered by IntentionPowerPack + + diff --git a/plugins/IntentionPowerPak/src/intentionDescriptions/Replace If Else With Conditional/after.java.template b/plugins/IntentionPowerPak/src/intentionDescriptions/Replace If Else With Conditional/after.java.template new file mode 100644 index 000000000000..75ee1f5ae00d --- /dev/null +++ b/plugins/IntentionPowerPak/src/intentionDescriptions/Replace If Else With Conditional/after.java.template @@ -0,0 +1,5 @@ +public class X { + boolean f(boolean a) { + return a?3:4; + } +} \ No newline at end of file diff --git a/plugins/IntentionPowerPak/src/intentionDescriptions/Replace If Else With Conditional/before.java.template b/plugins/IntentionPowerPak/src/intentionDescriptions/Replace If Else With Conditional/before.java.template new file mode 100644 index 000000000000..8ac3bae841fc --- /dev/null +++ b/plugins/IntentionPowerPak/src/intentionDescriptions/Replace If Else With Conditional/before.java.template @@ -0,0 +1,8 @@ +public class X { + int f(boolean a) { + if (a) { + return 3; + } + return 4; + } +} \ No newline at end of file diff --git a/plugins/IntentionPowerPak/src/intentionDescriptions/Replace If Else With Conditional/description.html b/plugins/IntentionPowerPak/src/intentionDescriptions/Replace If Else With Conditional/description.html new file mode 100644 index 000000000000..62ce95689720 --- /dev/null +++ b/plugins/IntentionPowerPak/src/intentionDescriptions/Replace If Else With Conditional/description.html @@ -0,0 +1,10 @@ + + +This intention replaces an if-else statement +with an equivalent statement using a conditional expression, if possible.
+
+ +

+Powered by IntentionPowerPack + + diff --git a/plugins/IntentionPowerPak/src/intentionDescriptions/Replace If With Switch/after.java.template b/plugins/IntentionPowerPak/src/intentionDescriptions/Replace If With Switch/after.java.template new file mode 100644 index 000000000000..ed928a5b1319 --- /dev/null +++ b/plugins/IntentionPowerPak/src/intentionDescriptions/Replace If With Switch/after.java.template @@ -0,0 +1,12 @@ +public class X { + int f(int a) { + switch (a) { + case 0: + return 1; + case 9: + return 8; + default: + return 2; + } + } +} \ No newline at end of file diff --git a/plugins/IntentionPowerPak/src/intentionDescriptions/Replace If With Switch/before.java.template b/plugins/IntentionPowerPak/src/intentionDescriptions/Replace If With Switch/before.java.template new file mode 100644 index 000000000000..4f2d2a7501b8 --- /dev/null +++ b/plugins/IntentionPowerPak/src/intentionDescriptions/Replace If With Switch/before.java.template @@ -0,0 +1,11 @@ +public class X { + int f(int a) { + if (a == 0) { + return 1; + } else if (a == 9) { + return 8; + } else { + return 2; + } + } +} \ No newline at end of file diff --git a/plugins/IntentionPowerPak/src/intentionDescriptions/Replace If With Switch/description.html b/plugins/IntentionPowerPak/src/intentionDescriptions/Replace If With Switch/description.html new file mode 100644 index 000000000000..3972ad79f1ae --- /dev/null +++ b/plugins/IntentionPowerPak/src/intentionDescriptions/Replace If With Switch/description.html @@ -0,0 +1,9 @@ + + +This intention replaces series of if-else statements with an equivalent switch statement.
+
+ +

+Powered by IntentionPowerPack + + diff --git a/plugins/IntentionPowerPak/src/intentionDescriptions/Replace Multiply with Shift/after.java.template b/plugins/IntentionPowerPak/src/intentionDescriptions/Replace Multiply with Shift/after.java.template new file mode 100644 index 000000000000..d8326f8600f9 --- /dev/null +++ b/plugins/IntentionPowerPak/src/intentionDescriptions/Replace Multiply with Shift/after.java.template @@ -0,0 +1,5 @@ +public class X { + void f(int a) { + a = a << 5; + } +} \ No newline at end of file diff --git a/plugins/IntentionPowerPak/src/intentionDescriptions/Replace Multiply with Shift/before.java.template b/plugins/IntentionPowerPak/src/intentionDescriptions/Replace Multiply with Shift/before.java.template new file mode 100644 index 000000000000..afe3e3b3c7c7 --- /dev/null +++ b/plugins/IntentionPowerPak/src/intentionDescriptions/Replace Multiply with Shift/before.java.template @@ -0,0 +1,5 @@ +public class X { + void f(int a) { + a = a * 32; + } +} \ No newline at end of file diff --git a/plugins/IntentionPowerPak/src/intentionDescriptions/Replace Multiply with Shift/description.html b/plugins/IntentionPowerPak/src/intentionDescriptions/Replace Multiply with Shift/description.html new file mode 100644 index 000000000000..00dc5807edf5 --- /dev/null +++ b/plugins/IntentionPowerPak/src/intentionDescriptions/Replace Multiply with Shift/description.html @@ -0,0 +1,9 @@ + + +This intention replaces multiplication operator with integer shift operator <<. + + +

+Powered by IntentionPowerPack + + diff --git a/plugins/IntentionPowerPak/src/intentionDescriptions/Replace Plus With StringBuffer Append/after.java.template b/plugins/IntentionPowerPak/src/intentionDescriptions/Replace Plus With StringBuffer Append/after.java.template new file mode 100644 index 000000000000..5c6b11913b7b --- /dev/null +++ b/plugins/IntentionPowerPak/src/intentionDescriptions/Replace Plus With StringBuffer Append/after.java.template @@ -0,0 +1,5 @@ +public class X { + String f() { + return new StringBuffer().append("1").append("2").toString(); + } +} \ No newline at end of file diff --git a/plugins/IntentionPowerPak/src/intentionDescriptions/Replace Plus With StringBuffer Append/before.java.template b/plugins/IntentionPowerPak/src/intentionDescriptions/Replace Plus With StringBuffer Append/before.java.template new file mode 100644 index 000000000000..1dbd1ab1669b --- /dev/null +++ b/plugins/IntentionPowerPak/src/intentionDescriptions/Replace Plus With StringBuffer Append/before.java.template @@ -0,0 +1,5 @@ +public class X { + String f() { + return "1" + "2"; + } +} \ No newline at end of file diff --git a/plugins/IntentionPowerPak/src/intentionDescriptions/Replace Plus With StringBuffer Append/description.html b/plugins/IntentionPowerPak/src/intentionDescriptions/Replace Plus With StringBuffer Append/description.html new file mode 100644 index 000000000000..a15f351b95d7 --- /dev/null +++ b/plugins/IntentionPowerPak/src/intentionDescriptions/Replace Plus With StringBuffer Append/description.html @@ -0,0 +1,9 @@ + + +This intention replaces String + concatenation operator with StringBuffer.append().
+
+ +

+Powered by IntentionPowerPack + + diff --git a/plugins/IntentionPowerPak/src/intentionDescriptions/Replace Qualified Name With Import/after.java.template b/plugins/IntentionPowerPak/src/intentionDescriptions/Replace Qualified Name With Import/after.java.template new file mode 100644 index 000000000000..404639712bea --- /dev/null +++ b/plugins/IntentionPowerPak/src/intentionDescriptions/Replace Qualified Name With Import/after.java.template @@ -0,0 +1,7 @@ +import java.util.ArrayList; + +public class X { + Object createList() { + return new ArrayList(); + } +} \ No newline at end of file diff --git a/plugins/IntentionPowerPak/src/intentionDescriptions/Replace Qualified Name With Import/before.java.template b/plugins/IntentionPowerPak/src/intentionDescriptions/Replace Qualified Name With Import/before.java.template new file mode 100644 index 000000000000..dea26cb27120 --- /dev/null +++ b/plugins/IntentionPowerPak/src/intentionDescriptions/Replace Qualified Name With Import/before.java.template @@ -0,0 +1,5 @@ +public class X { + Object createList() { + return new java.util.ArrayList(); + } +} \ No newline at end of file diff --git a/plugins/IntentionPowerPak/src/intentionDescriptions/Replace Qualified Name With Import/description.html b/plugins/IntentionPowerPak/src/intentionDescriptions/Replace Qualified Name With Import/description.html new file mode 100644 index 000000000000..0e7593077113 --- /dev/null +++ b/plugins/IntentionPowerPak/src/intentionDescriptions/Replace Qualified Name With Import/description.html @@ -0,0 +1,10 @@ + + +This intention adds import + statement for qualified Java class reference.
+
+ +

+Powered by IntentionPowerPack + + diff --git a/plugins/IntentionPowerPak/src/intentionDescriptions/Replace Shift with Multiply/after.java.template b/plugins/IntentionPowerPak/src/intentionDescriptions/Replace Shift with Multiply/after.java.template new file mode 100644 index 000000000000..17ad098b5b0e --- /dev/null +++ b/plugins/IntentionPowerPak/src/intentionDescriptions/Replace Shift with Multiply/after.java.template @@ -0,0 +1,5 @@ +public class X { + void f(int a) { + a = a * 32; + } +} \ No newline at end of file diff --git a/plugins/IntentionPowerPak/src/intentionDescriptions/Replace Shift with Multiply/before.java.template b/plugins/IntentionPowerPak/src/intentionDescriptions/Replace Shift with Multiply/before.java.template new file mode 100644 index 000000000000..876b023d4a27 --- /dev/null +++ b/plugins/IntentionPowerPak/src/intentionDescriptions/Replace Shift with Multiply/before.java.template @@ -0,0 +1,5 @@ +public class X { + void f(int a) { + a = a << 5; + } +} \ No newline at end of file diff --git a/plugins/IntentionPowerPak/src/intentionDescriptions/Replace Shift with Multiply/description.html b/plugins/IntentionPowerPak/src/intentionDescriptions/Replace Shift with Multiply/description.html new file mode 100644 index 000000000000..fe577e61cea8 --- /dev/null +++ b/plugins/IntentionPowerPak/src/intentionDescriptions/Replace Shift with Multiply/description.html @@ -0,0 +1,9 @@ + + +This intention replaces integer shift operator << with multiplication operator. + + +

+Powered by IntentionPowerPack + + diff --git a/plugins/IntentionPowerPak/src/intentionDescriptions/Replace Switch With If/after.java.template b/plugins/IntentionPowerPak/src/intentionDescriptions/Replace Switch With If/after.java.template new file mode 100644 index 000000000000..b66c023c7cd8 --- /dev/null +++ b/plugins/IntentionPowerPak/src/intentionDescriptions/Replace Switch With If/after.java.template @@ -0,0 +1,9 @@ +public class X { + int f(int a) { + if (a == 0) { + return 1; + } else { + return 2; + } + } +} \ No newline at end of file diff --git a/plugins/IntentionPowerPak/src/intentionDescriptions/Replace Switch With If/before.java.template b/plugins/IntentionPowerPak/src/intentionDescriptions/Replace Switch With If/before.java.template new file mode 100644 index 000000000000..c6438b42a2b2 --- /dev/null +++ b/plugins/IntentionPowerPak/src/intentionDescriptions/Replace Switch With If/before.java.template @@ -0,0 +1,8 @@ +public class X { + int f(int a) { + switch (a) { + case 0: return 1; + default: return 2; + } + } +} \ No newline at end of file diff --git a/plugins/IntentionPowerPak/src/intentionDescriptions/Replace Switch With If/description.html b/plugins/IntentionPowerPak/src/intentionDescriptions/Replace Switch With If/description.html new file mode 100644 index 000000000000..25e2c6562c8d --- /dev/null +++ b/plugins/IntentionPowerPak/src/intentionDescriptions/Replace Switch With If/description.html @@ -0,0 +1,9 @@ + + +This intention replaces switch statement with the series of if-else statements.
+
+ +

+Powered by IntentionPowerPack + + diff --git a/plugins/IntentionPowerPak/src/intentionDescriptions/Replace With Java Style Array Declaration/after.java.template b/plugins/IntentionPowerPak/src/intentionDescriptions/Replace With Java Style Array Declaration/after.java.template new file mode 100644 index 000000000000..626bf4b610da --- /dev/null +++ b/plugins/IntentionPowerPak/src/intentionDescriptions/Replace With Java Style Array Declaration/after.java.template @@ -0,0 +1,5 @@ +public class X { + void f() { + int[] a = null; + } +} \ No newline at end of file diff --git a/plugins/IntentionPowerPak/src/intentionDescriptions/Replace With Java Style Array Declaration/before.java.template b/plugins/IntentionPowerPak/src/intentionDescriptions/Replace With Java Style Array Declaration/before.java.template new file mode 100644 index 000000000000..bc2d21b3e2a7 --- /dev/null +++ b/plugins/IntentionPowerPak/src/intentionDescriptions/Replace With Java Style Array Declaration/before.java.template @@ -0,0 +1,5 @@ +public class X { + void f() { + int a[] = null; + } +} \ No newline at end of file diff --git a/plugins/IntentionPowerPak/src/intentionDescriptions/Replace With Java Style Array Declaration/description.html b/plugins/IntentionPowerPak/src/intentionDescriptions/Replace With Java Style Array Declaration/description.html new file mode 100644 index 000000000000..e4c76bb7333f --- /dev/null +++ b/plugins/IntentionPowerPak/src/intentionDescriptions/Replace With Java Style Array Declaration/description.html @@ -0,0 +1,9 @@ + + +This intention replaces C-style array declaration with Java-style.
+
+ +

+Powered by IntentionPowerPack + + diff --git a/plugins/IntentionPowerPak/src/intentionDescriptions/Simplify If Else/after.java.template b/plugins/IntentionPowerPak/src/intentionDescriptions/Simplify If Else/after.java.template new file mode 100644 index 000000000000..286b7f258199 --- /dev/null +++ b/plugins/IntentionPowerPak/src/intentionDescriptions/Simplify If Else/after.java.template @@ -0,0 +1,5 @@ +public class X { + boolean f(boolean a) { + return a; + } +} \ No newline at end of file diff --git a/plugins/IntentionPowerPak/src/intentionDescriptions/Simplify If Else/before.java.template b/plugins/IntentionPowerPak/src/intentionDescriptions/Simplify If Else/before.java.template new file mode 100644 index 000000000000..c23f51396417 --- /dev/null +++ b/plugins/IntentionPowerPak/src/intentionDescriptions/Simplify If Else/before.java.template @@ -0,0 +1,8 @@ +public class X { + boolean f(boolean a) { + if (a) { + return true; + } + return false; + } +} \ No newline at end of file diff --git a/plugins/IntentionPowerPak/src/intentionDescriptions/Simplify If Else/description.html b/plugins/IntentionPowerPak/src/intentionDescriptions/Simplify If Else/description.html new file mode 100644 index 000000000000..0266db5a3fa9 --- /dev/null +++ b/plugins/IntentionPowerPak/src/intentionDescriptions/Simplify If Else/description.html @@ -0,0 +1,9 @@ + + +This intention simplifies an unnecessary if-else statement.
+
+ +

+Powered by IntentionPowerPack + + diff --git a/plugins/IntentionPowerPak/src/intentionDescriptions/Split Else If/after.java.template b/plugins/IntentionPowerPak/src/intentionDescriptions/Split Else If/after.java.template new file mode 100644 index 000000000000..154000353e52 --- /dev/null +++ b/plugins/IntentionPowerPak/src/intentionDescriptions/Split Else If/after.java.template @@ -0,0 +1,15 @@ +public class X { + int f(int a) { + if (a == 0) { + return 0; + } + else { + if (a == 1) { + return 2; + } + else { + return 18; + } + } + } +} \ No newline at end of file diff --git a/plugins/IntentionPowerPak/src/intentionDescriptions/Split Else If/before.java.template b/plugins/IntentionPowerPak/src/intentionDescriptions/Split Else If/before.java.template new file mode 100644 index 000000000000..6ed0aff7990d --- /dev/null +++ b/plugins/IntentionPowerPak/src/intentionDescriptions/Split Else If/before.java.template @@ -0,0 +1,13 @@ +public class X { + int f(int a) { + if (a == 0) { + return 0; + } + else if (a == 1) { + return 2; + } + else { + return 18; + } + } +} \ No newline at end of file diff --git a/plugins/IntentionPowerPak/src/intentionDescriptions/Split Else If/description.html b/plugins/IntentionPowerPak/src/intentionDescriptions/Split Else If/description.html new file mode 100644 index 000000000000..d1f1a0bb11e8 --- /dev/null +++ b/plugins/IntentionPowerPak/src/intentionDescriptions/Split Else If/description.html @@ -0,0 +1,9 @@ + + +This intention splits else branch of the if-else statement.
+
+ +

+Powered by IntentionPowerPack + + diff --git a/plugins/IntentionPowerPak/test/com/siyeh/ipp/ManualTestClass.java b/plugins/IntentionPowerPak/test/com/siyeh/ipp/ManualTestClass.java new file mode 100644 index 000000000000..d407aa18ab8a --- /dev/null +++ b/plugins/IntentionPowerPak/test/com/siyeh/ipp/ManualTestClass.java @@ -0,0 +1,1256 @@ +package com.siyeh.ipp; + +import java.io.EOFException; +import java.io.IOException; + +// Note: this class never gets compiled. It's simply here to hold a +//bunch of manual test cases + +public class ManualTestClass +{ + int foo[]; + int[] bar[]; + + public void testInteger() + { + // convert between octal, hex, and decimal + int foo = 31; + + // convert between octal, hex, and decimal + long bar = 0x1fL; + +// convert between octal, hex, and decimal + int foo2 = 31000000000000000000000000000000000000000000000; + +// convert between octal, hex, and decimal + long bar2 = 31000000000000000000000000000000000000000000000L; + + } + + public void testShift() + { + int x = 1; + int y = 2; + + // test that this will go to shift and back + x = y * 8; + + // test that this doesn't do anything + x = y * 7; + + // test that this will go to shift and back + x *= 8; + + // test that this doesn't do anything + x *= 7; + + // test that this will go to shift and back + x = y / 8; + + // test that this doesn't do anything + x = y / 7; + + // test that this will go to shift and back + x /= 8; + + // test that this doesn't do anything + x /= 7; + } + + public void testFQNames() + { + // test that this will be transformed + java.util.HashMap hashMap = new java.util.HashMap(); + } + + public void testOpAssign() + { + int a = 0; + int[] b = new int[1]; + + // test that this will be shortened + a = a + 3; + + // test that this will be shortened + a = a * 3; + + // test that this will be shortened + a = a - 3; + + // test that this will be shortened + a = a % 3; + + // test that this will be shortened + a = a / 3; + + // test that this will be shortened + a = (a) / 3; + + // test that this will be shortened + b[a] = b[a] / 3; + + // test that this will be shortened + b[a] = b[(a)] / 3; + + // test that this does nothing + b[a++] = b[a++] / 3; + } + + public void testAnd() + { + boolean foo = true; + boolean bar = true; + boolean baz = true; + + // test that this will be changed + if(foo && bar) + { + + } + // test that this will be changed + if(foo && bar && baz) + { + + } + + // test that this will be changed + if(!foo && bar && !baz) + { + + } + + // test both of these + if((foo && bar) && baz) + { + + } + + // test that this will be changed + if(3 < 4 && 5 != 2) + { + + } + } + + public void testOr() + { + boolean foo = true; + boolean bar = true; + boolean baz = true; + + // test that this will be changed + if(foo || bar) + { + + } + // test that this will be changed + if(foo || bar || baz) + { + + } + + // test that this will be changed + if(!foo || bar || !baz) + { + + } + + // test both of these + if((foo || bar) || baz) + { + + } + } + + public void testBoolEquality() + { + boolean foo = true; + + // test that this collapses to if(foo) + if(foo == true) + { + + } // test that this collapses to if(!foo) + if(foo == false) + { + + } // test that this collapses to if(!foo) + if(foo != true) + { + + } // test that this collapses to if(foo) + if(foo != false) + { + + } // test that this collapses to if(foo) + if(true == foo) + { + + } + // test that this collapses to if(!foo) + if(false == foo) + { + + } // test that this collapses to if(!foo) + if(true != foo) + { + + } // test that this collapses to if(foo) + if(false != foo) + { + } + // test that this collapses to if(foo) + if(true == 3 > 4) + { + } + // test that this collapses to if(foo) + if(true != 3 > 4) + { + } + + } + + public void testEquality() + { + String foo = "foo"; + String bar = "bar"; + int foo2 = 100; + int baz2 = 3; + + // test turning this into .equals and back + if(foo == bar) + { + + } + + // test that this doesn't have a "change to equals" intention + if(foo2 == baz2) + { + + } + + + // test that this does have a "change to equals" intention + if("foo" + "bar" == "bar" + "foo") + { + + } + + // test turning this into ! .equals and back + if(foo != bar) + { + + } + + // test that this doesn't have a "change to ! equals" intention + if(foo2 != baz2) + { + + } + + } + + public void testFlipEquals() + { + String foo = "foo"; + String bar = "bar"; + + // test flipping this + if(foo.equals(bar)) + { + + } + // test flipping this + if("foo".equals("foo" + "bar")) + { + + } + // test flipping this + if(foo.equalsIgnoreCase(bar)) + { + + } + } + + public void testJUnit() + { + boolean foo = true; + String bar = "foo"; + + // test changing this to assertEquals and back + assertTrue("foo", foo); + + // test changing this to assertEquals and back + assertTrue(foo); + + // test changing this to assertEquals and back + assertFalse("foo", foo); + + // test changing this to assertEquals and back + assertEquals(false, foo); + + // test changing this to assertEquals and back + assertNull("foo", bar); + + // test changing this to assertEquals and back + assertNull(bar); + + // test changing this to assertTrue and back + assertEquals("foo", true, foo); + + // test changing this to assertTrue and back + assertEquals(true, foo); + + // test changing this to assertNull and back + assertEquals("foo", null, bar); + + // test changing this to assertNull and back + assertEquals(null, bar); + + + // test changing this to assertFalse and back + assertTrue(foo); + + // test changing this to assertTrue and back + assertFalse("foo", foo); + + String baz1 = "foo"; + String baz2 = "bar"; + + // test changing this to assertTrue and back + assertEquals(baz1, baz2); + + // test changing this to assertTrue and back + assertEquals("test", true, baz1.equals(baz2)); + + int int1 = 3; + int int2 = 4; + // test changing this to assertTrue and back + assertEquals(int1, int2); + + // test changing this to assertTrue and back + assertEquals("test", int1, int2); + + } + + public void testMergeAndIf() + { + boolean foo = true; + boolean bar = true; + + //test merge these + if(foo) + { + if(bar) + { + System.out.println("test2"); + } + } + + //test merge these + if(foo) + if(bar) + System.out.println("test2"); + + //test merge these + if(foo) + { + if(bar) + System.out.println("test2"); + } + + //test merge these + if(foo) + if(bar) + { + System.out.println("test2"); + } + + //test that these don't merge + if(foo) + { + if(bar) + { + System.out.println("test2"); + } + else + { + System.out.println("test3"); + } + } + + //test that these don't merge + if(foo) + { + if(bar) + { + System.out.println("test2"); + } + } + else + { + System.out.println("test3"); + } + } + + public void testMergeOrIf() + { + boolean foo = true; + boolean bar = true; + if(foo) + { + System.out.println("1"); + } + else if(bar) + { + System.out.println("1"); + } + else + { + System.out.println("2"); + } + + // test that these don't merge + if(foo) + { + System.out.println("1"); + } + else if(bar) + { + System.out.println("3"); + } + else + { + System.out.println("2"); + } + // test that these don't merge + if(foo) + { + System.out.println("1"); + } + else if(bar) + { + } + else + { + System.out.println("2"); + } + } + + public void testFlipConditional() + { + boolean foo = true; + boolean bar = true; + int x = 3; + + //test flipping this + x = foo?3:4; + System.out.println("x = " + x); + x = foo != bar?3:4; + System.out.println("x = " + x); + } + + public void testSwitchToIf() throws InterruptedException + { + int x = 0; + // test changing this to if-else + switch(x) + { + case (3): + case (4): + System.out.println("3"); + System.out.println("4"); + break; + case (5): + case (6): + System.out.println("5"); + System.out.println("6"); + break; + } + + // test changing this to if-else + switch(x) + { + case (3): + case (4): + System.out.println("3"); + System.out.println("4"); + break; + case (5): + case (6): + System.out.println("5"); + System.out.println("6"); + break; + default: + case (7): + System.out.println("default"); + break; + } + + // test changing this to if-else + switch(x) + { + case (3): + case (4): + //test comment + System.out.println("3"); + //test comment3 + System.out.println("4"); + //test comment2 + break; + default: + case (7): + System.out.println("default"); + break; + case (5): + case (6): + System.out.println("5"); + System.out.println("6"); + break; + } + + // test changing this to if-else (fallthrough) + switch(x) + { + case (3): + case (4): + System.out.println("3"); + System.out.println("4"); + case (5): + case (6): + System.out.println("5"); + System.out.println("6"); + break; + default: + case (7): + System.out.println("default"); + break; + } + // test changing this to if-else (fallthrough) + switch(x) + { + case (3): + case (4): + System.out.println("3"); + System.out.println("4"); + break; + case (5): + case (6): + System.out.println("5"); + System.out.println("6"); + default: + case (7): + System.out.println("default"); + break; + } + + // test changing this to if-else (fallthrough) + switch(x) + { + case (3): + case (4): + System.out.println("3"); + System.out.println("4"); + case (5): + case (6): + System.out.println("5"); + System.out.println("6"); + default: + case (7): + System.out.println("default"); + break; + } + + + // test changing this to if-else (side effect on switch expression) + int i; + Label: + switch(x++) + { + case (3): + case (4): + System.out.println("3"); + System.out.println("4"); + break; + case (5): + case (6): + System.out.println("5"); + System.out.println("6"); + break; + default: + case (7): + System.out.println("default"); + break; + } + + // test changing this to if-else (nested break) + switch(x) + { + case (3): + case (4): + System.out.println("3"); + System.out.println("4"); + if(true) + { + break; + } + break; + case (5): + case (6): + System.out.println("5"); + System.out.println("6"); + break; + default: + case (7): + System.out.println("default"); + break; + } + + // test changing this to if-else (declaration between branches) + switch(x) + { + case (3): + case (4): + int y; + Object foo; + System.out.println("3"); + System.out.println("4"); + break; + case (5): + case (6): + foo.wait(0); + System.out.println("5"); + System.out.println("6"); + break; + default: + case (7): + System.out.println("y = " + y); + System.out.println("default"); + break; + } + + } + + public void testFlipComparison() + { + int foo = 3; + int bar = 4; + + //flip this + if(3 > 4) + { + + } + //flip this + if(3 >= 4) + { + + } + //flip this + if(3 < 4) + { + + } + //flip this + if(3 <= 4) + { + + } + //flip this + if(3 == 4) + { + + } + //flip this + if(3 != 4) + { + + } + } + + public void testNegateComparison() + { + int foo = 3; + int bar = 4; + + //negate this + if(3 > 4) + { + + } + //negate this + if(3 >= 4) + { + + } + //negate this + if(3 < 4) + { + + } + //negate this + if(3 <= 4) + { + + } + //negate this + if(3 == 4) + { + + } + //negate this + if(3 != 4) + { + + } + } + + public void testRemoveConditional() + { + boolean foo = true; + boolean baz = false; + + // test removing this conditional + boolean bar = foo?true:false; + + // test removing this conditional + bar = foo?false:true; + + //test removing this conditional + bar = foo?(false):(true); + + // test that this conditional can't be removed + bar = foo?true:true; + + // test that this conditional can't be removed + bar = foo?false:false; + } + + public void testRemoveIf() + { + boolean foo = false; + boolean bar = true; + + // test removing this if + if(!foo) + { + bar = true; + } + else + { + bar = false; + } + + // test removing this if + if(!foo) + { + bar = false; + } + else + { + bar = true; + } + + // test that this if can't be removed + if(foo) + { + bar = true; + } + else + { + bar = true; + } + + // test that this if can't be removed + if(!foo) + { + bar = false; + } + else + { + bar = false; + } + } + + public boolean testRemoveIfReturn1() + { + boolean foo = true; + // test removing this + if(!foo) + { + return true; + } + else + { + return false; + } + } + + public boolean testRemoveIfReturn2() + { + boolean foo = true; + // test removing this + if(!foo) + { + return false; + } + else + { + return true; + } + } + + public boolean testRemoveIfReturn3() + { + boolean foo = true; + // test that this if can't be removed + if(!foo) + { + return true; + } + else + { + return true; + } + } + + public boolean testRemoveIfReturn() + { + boolean foo = true; + // test that this if can't be removed + if(!foo) + { + return false; + } + else + { + return false; + } + } + + public boolean testRemoveIfImplicitReturn1() + { + boolean foo = true; + // test removing this + if(!foo) + { + return true; + } + return false; + } + + public boolean testRemoveIfImplicitReturn2() + { + boolean foo = true; + // test removing this + if(!foo) + { + return false; + } + return true; + } + + public boolean testRemoveIfImplicitReturn3() + { + boolean foo = true; + // test that this if can't be removed + if(!foo) + { + return true; + } + return true; + } + + public boolean testRemoveIfImplicitReturn() + { + boolean foo = true; + // test that this if can't be removed + if(!foo) + { + return false; + } + return false; + } + + public int testReplaceIfImplicitReturnWithConditional() + { + boolean foo = true; + if(!foo) + { + return 3; + } + return 4; + } + + public void testReplaceConditionalWithIfAssign() + { + boolean foo = true; + int a; + // test replacing this with if-then, and back again + a = foo ? 3 : 4; + } + + public void testReplaceConditionalWithIfDeclaration() + { + boolean foo = true; + // test replacing this with if-then + int a = foo?3:4; + } + + public int testReplaceConditionalWithIfReturn() + { + boolean foo = true; + // test replacing this with if-then, and back again + return foo?3:4; + } + + public void testIfToSwitch() + { + final int x = 2; + Label: + if(x == 4 || x == 3) + { + // test comment + System.out.println("1"); + } + else if(x == 5 || x == 6) + { + System.out.println("2"); + } + else + { + System.out.println("3"); + } + + // test that the first and ssecond blocks remain wrapped + if(x == 4 || x == 3) + { + int y = 3; + System.out.println("1"); + } + else if(x == 5 || x == 6) + { + int y = 4; + System.out.println("2"); + } + else + { + System.out.println("3"); + } + + // test that the first block remains wrapped, but the second doesn't + if(x == 4 || x == 3) + { + int y = 3; + System.out.println("1"); + } + else if(x == 5 || x == 6) + { + for(int y = 0; y < 100; y++) + { + System.out.println("Barangus!"); + } + System.out.println("2"); + } + else + { + System.out.println("3"); + } + + for(; ;) + { + if(x == 4 || x == 3) + { + // test comment + System.out.println("1"); + break; + } + else if(x == 5 || x == 6) + { + System.out.println("2"); + } + else + { + System.out.println("3"); + } + } + } + + public void testFlipAnd() + { + boolean foo = true; + boolean bar = false; + boolean baz = false; + + // flip these + if(foo && bar) + { + System.out.println("1"); + } + // flip these + if(foo && bar && baz) + { + System.out.println("1"); + } + } + + public void testFlipOr() + { + boolean foo = true; + boolean bar = false; + boolean baz = false; + + // flip these + if(foo || bar) + { + System.out.println("1"); + } + // flip these + if(foo || bar || baz) + { + System.out.println("1"); + } + } + + public void flipCommutative() + { + "bar".equals("foo"); + "foo".equalsIgnoreCase("bar"); + "foo".compareTo("bar"); + } + + public void testDetailException() throws IOException + { + // check that this is detailed + try + { + if(true) + { + throw new NullPointerException(); + } + throw new ArrayIndexOutOfBoundsException(); + } + catch(Exception e) + { + System.out.println("Barangus!"); + } + + // check that this is detailed, and the exceptions sorted correctly + try + { + if(true) + { + throw new IOException(); + } + throw new EOFException(); + } + catch(Exception e) + { + System.out.println("Barangus!"); + } + + // check that this gets no intention + try + { + if(true) + { + throw new NullPointerException(); + } + throw new ArrayIndexOutOfBoundsException(); + } + catch(NullPointerException e) + { + System.out.println("Barangus!"); + } + catch(ArrayIndexOutOfBoundsException e) + { + System.out.println("Barangus!"); + } + + + // check that this doesn't get detailed + try + { + if(true) + { + throw new IOException(); + } + throw new EOFException(); + } + catch(Error e) + { + System.out.println("Barangus!"); + } + + } + + public void testDetailMethodExceptions() + { + try + { + if(true) + { + foo(); + } + throw new ArrayIndexOutOfBoundsException(); + } + catch(Exception e) + { + System.out.println("Barangus!"); + } + } + + private void foo() throws IOException + { + throw new IOException(); + } + + public void testSimplifyDeclaration() + { + // test simplifying this + int foo[]; + + // test simplifying this + int bar[] = new int[3]; + + // test simplifying this + int[] baz[] = new int[3][]; + + // test simplifying this + int bar2[] = new int[3], bar3[] = new int[4]; + + // test simplifying this + int baz2[] = new int[3], baz3[]; + + // test that this doesn't simplify + int baz4[] = new int[3], baz5; + } + + public void testSimplifyParam(int foo[], int[] bar[], int[] baz) + { + + } + + public void testConditionalDeclaration() + { + boolean foo = bar()?true:false; + } + + public boolean bar() + { + return true; + } + + public void testConcatenation() + { + System.out.println("foo" + "bar" + "baz"); + final String fooString = "foo"; + System.out.println(fooString + "bar" + "baz"); + System.out.println(fooString + 1 + 2); + System.out.println((fooString + 1) + 2); + System.out.println(fooString + (1 + 2)); + final StringBuffer buffer = new StringBuffer(); + buffer.append("foo" + "bar" + "baz"); + } + + public boolean testExpandBoolean() + { + boolean foo = true; + boolean bar = false; + bar = foo; + if (bar) { + return true; + } else { + return false; + } + } + + public void testSplitElseIf() + { + if(bar()) + { + System.out.println("1"); + } + else if(!bar()) + { + System.out.println("2"); + } + + if(bar()) + { + System.out.println("1"); + } + else if(!bar()) + { + System.out.println("2"); + } + else if(!bar() && bar()) + { + System.out.println("3"); + } + + if(bar()) + { + System.out.println("1"); + } + else + { + System.out.println("2"); + } + } + + private void assertNull(Object s, String value) + { + boolean a = bar(); + boolean b = bar(); + if(!(((a || b)))) + { + // Do something + } + + } + + private void assertNull(Object value) + { + } + + private void assertEquals(String s, Object b, Object foo) + { + } + + private void assertEquals(Object b, Object foo) + { + } + + private void assertEquals(String s, boolean b, boolean foo) + { + } + + private void assertEquals(boolean b, boolean foo) + { + } + + private void assertTrue(String message, boolean b) + { + } + + private void assertTrue(boolean b) + { + } + + private void assertFalse(String message, boolean b) + { + } + + private void assertFalse(boolean b) + { + } + + private void assertEquals(int int1, int int2) + { + } + + private void assertEquals(String message, int int1, int int2) + { + } +} diff --git a/plugins/IntentionPowerPak/test/com/siyeh/ipp/RenameReference.java b/plugins/IntentionPowerPak/test/com/siyeh/ipp/RenameReference.java new file mode 100644 index 000000000000..57b6bbc7fcac --- /dev/null +++ b/plugins/IntentionPowerPak/test/com/siyeh/ipp/RenameReference.java @@ -0,0 +1,13 @@ +package com.siyeh.ipp; + +public class RenameReference +{ + public void test() + { + boolean test = true; + if(test || "my".equalsIgNoreCase("bad")) + { + System.out.println("bla"); + } + } +} diff --git a/plugins/devkit/META-INF/plugin.xml b/plugins/devkit/META-INF/plugin.xml new file mode 100644 index 000000000000..31bb99ae3754 --- /dev/null +++ b/plugins/devkit/META-INF/plugin.xml @@ -0,0 +1,51 @@ + + + Plugin DevKit + IntelliJ IDEA plugins development kit + 0.0.1 + JetBrains + + + + + org.jetbrains.idea.devkit.DevKitPlugin + + + org.jetbrains.idea.devkit.run.PluginConfigurationType + + + org.jetbrains.idea.devkit.sandbox.SandboxManager + + + org.jetbrains.idea.devkit.sandbox.SandboxConfigurable + + + org.jetbrains.idea.devkit.module.PluginTemplatesFactory + + + + + + org.jetbrains.idea.devkit.module.ModuleSandboxManager + + + org.jetbrains.idea.devkit.module.PluginModuleEditorsProvider + + + com.intellij.j2ee.make.ModuleBuildProperties + org.jetbrains.idea.devkit.build.PluginModuleBuildProperties + + + com.intellij.j2ee.make.ModuleBuildDescriptor + org.jetbrains.idea.devkit.build.PluginModuleBuildDescriptor + + + org.jetbrains.idea.devkit.module.PluginModuleProperties + + + diff --git a/plugins/devkit/devkit.iml b/plugins/devkit/devkit.iml new file mode 100644 index 000000000000..4df68dceaab9 --- /dev/null +++ b/plugins/devkit/devkit.iml @@ -0,0 +1,39 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/devkit/resources/fileTemplates/j2ee/plugin.xml.ft b/plugins/devkit/resources/fileTemplates/j2ee/plugin.xml.ft new file mode 100644 index 000000000000..37b02a0a6b0d --- /dev/null +++ b/plugins/devkit/resources/fileTemplates/j2ee/plugin.xml.ft @@ -0,0 +1,8 @@ + + + Plugin name here + short description of the plugin + 1.0 + YourCompany + + \ No newline at end of file diff --git a/plugins/devkit/resources/fileTemplates/j2ee/plugin.xml.html b/plugins/devkit/resources/fileTemplates/j2ee/plugin.xml.html new file mode 100644 index 000000000000..a62406199790 --- /dev/null +++ b/plugins/devkit/resources/fileTemplates/j2ee/plugin.xml.html @@ -0,0 +1,11 @@ + + + + + + +
This is a built-in template used by IDEA each time you create + the new IntelliJ IDEA plugin module. +
+ + \ No newline at end of file diff --git a/plugins/devkit/src/DevKitPlugin.java b/plugins/devkit/src/DevKitPlugin.java new file mode 100644 index 000000000000..da1b56365397 --- /dev/null +++ b/plugins/devkit/src/DevKitPlugin.java @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2004 JetBrains s.r.o. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * -Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * -Redistribution in binary form must reproduct the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the distribution. + * + * Neither the name of JetBrains or IntelliJ IDEA + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. JETBRAINS AND ITS LICENSORS SHALL NOT + * BE LIABLE FOR ANY DAMAGES OR LIABILITIES SUFFERED BY LICENSEE AS A RESULT + * OF OR RELATING TO USE, MODIFICATION OR DISTRIBUTION OF THE SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL JETBRAINS OR ITS LICENSORS BE LIABLE FOR ANY LOST + * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, + * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY + * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE SOFTWARE, EVEN + * IF JETBRAINS HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + * + */ +package org.jetbrains.idea.devkit; + +import com.intellij.openapi.components.ApplicationComponent; +import com.intellij.openapi.module.ModuleTypeManager; +import org.jetbrains.idea.devkit.module.PluginModuleType; + +public class DevKitPlugin implements ApplicationComponent { + public String getComponentName() { + return "DevKit.Plugin"; + } + + public void initComponent() { + ModuleTypeManager.getInstance().registerModuleType(PluginModuleType.getInstance()); + } + + public void disposeComponent() { + } +} \ No newline at end of file diff --git a/plugins/devkit/src/build/PluginModuleBuildProperties.java b/plugins/devkit/src/build/PluginModuleBuildProperties.java new file mode 100644 index 000000000000..d3546bdcd8f4 --- /dev/null +++ b/plugins/devkit/src/build/PluginModuleBuildProperties.java @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2000-2004 by JetBrains s.r.o. All Rights Reserved. + * Use is subject to license terms. + */ +package org.jetbrains.idea.devkit.build; + +import com.intellij.j2ee.make.ModuleBuildProperties; +import com.intellij.openapi.module.Module; +import com.intellij.openapi.module.ModuleComponent; +import org.jetbrains.idea.devkit.module.ModuleSandboxManager; + +public class PluginModuleBuildProperties extends ModuleBuildProperties implements ModuleComponent { + private Module myModule; + + public PluginModuleBuildProperties(Module module) { + myModule = module; + } + + public String getArchiveExtension() { + return "jar"; + } + + public String getJarPath() { + return getSandboxManager().getSandbox().getSandboxHome() + "/plugins/" + myModule.getName(); + } + + public String getExplodedPath() { + return getSandboxManager().getSandbox().getSandboxHome() + "/plugins/" + myModule.getName(); + } + + private ModuleSandboxManager getSandboxManager() { + return ModuleSandboxManager.getInstance(myModule); + } + + public Module getModule() { + return myModule; + } + + public boolean isJarEnabled() { + return false; + } + + public boolean isExplodedEnabled() { + return isBuildActive(); + } + + public boolean isBuildOnFrameDeactivation() { + //TODO + return isBuildActive(); + } + + public boolean isSyncExplodedDir() { + //TODO + return isBuildActive(); + } + + private boolean isBuildActive() { + return !getSandboxManager().isUnderIDEAProject(); + } + + public void projectOpened() {} + + public void projectClosed() {} + + public void moduleAdded() {} + + public String getComponentName() { + return "DevKit.ModuleBuildProperties"; + } + + public void initComponent() {} + + public void disposeComponent() {} +} \ No newline at end of file diff --git a/plugins/devkit/src/module/PluginDescriptorMetaData.java b/plugins/devkit/src/module/PluginDescriptorMetaData.java new file mode 100644 index 000000000000..8163b1ff8b44 --- /dev/null +++ b/plugins/devkit/src/module/PluginDescriptorMetaData.java @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2000-2004 by JetBrains s.r.o. All Rights Reserved. + * Use is subject to license terms. + */ +package org.jetbrains.idea.devkit.module; + +import com.intellij.j2ee.j2eeDom.DeploymentDescriptorMetaData; +import com.intellij.openapi.module.ModuleType; + +public class PluginDescriptorMetaData implements DeploymentDescriptorMetaData { + private final static String VERSION = "1.0"; + + public String[] getAvailableVersions() { + return new String[] {VERSION}; + } + + public String getTemplateNameAccordingToVersion(String version) { + return "plugin.xml"; + } + + public String getDefaultVersion() { + return VERSION; + } + + public String getDefaultFileName() { + return "plugin.xml"; + } + + public String getDefaultDirectoryName() { + return "META-INF"; + } + + public String getTitle() { + return "IntelliJ IDEA Plugin Descriptor"; + } + + public ModuleType[] getSuitableTypes() { + return new ModuleType[] {PluginModuleType.getInstance()}; + } +} \ No newline at end of file diff --git a/plugins/devkit/src/module/PluginModuleBuilder.java b/plugins/devkit/src/module/PluginModuleBuilder.java new file mode 100644 index 000000000000..67e873cc2df9 --- /dev/null +++ b/plugins/devkit/src/module/PluginModuleBuilder.java @@ -0,0 +1,15 @@ +/* + * Copyright (c) 2000-2004 by JetBrains s.r.o. All Rights Reserved. + * Use is subject to license terms. + */ +package org.jetbrains.idea.devkit.module; + +import com.intellij.ide.util.projectWizard.JavaModuleBuilder; +import com.intellij.openapi.module.ModuleType; + +public class PluginModuleBuilder extends JavaModuleBuilder{ + + public ModuleType getModuleType() { + return PluginModuleType.getInstance(); + } +} diff --git a/plugins/devkit/src/module/PluginModuleEditorsProvider.java b/plugins/devkit/src/module/PluginModuleEditorsProvider.java new file mode 100644 index 000000000000..a840f4736a6e --- /dev/null +++ b/plugins/devkit/src/module/PluginModuleEditorsProvider.java @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2000-2004 by JetBrains s.r.o. All Rights Reserved. + * Use is subject to license terms. + */ +package org.jetbrains.idea.devkit.module; + +import com.intellij.openapi.module.Module; +import com.intellij.openapi.module.ModuleComponent; +import com.intellij.openapi.module.ModuleConfigurationEditor; +import com.intellij.openapi.roots.ModifiableRootModel; +import com.intellij.openapi.roots.ui.configuration.DefaultModuleConfigurationEditorFactory; +import com.intellij.openapi.roots.ui.configuration.ModuleConfigurationEditorProvider; +import com.intellij.openapi.roots.ui.configuration.ModuleConfigurationState; + +public class PluginModuleEditorsProvider implements ModuleComponent, ModuleConfigurationEditorProvider{ + public String getComponentName() { + return "DevKit.PluginModuleEditorsProvider"; + } + + + public ModuleConfigurationEditor[] createEditors(ModuleConfigurationState state) { + final DefaultModuleConfigurationEditorFactory editorFactory = DefaultModuleConfigurationEditorFactory.getInstance(); + final ModifiableRootModel rootModel = state.getRootModel(); + final Module module = rootModel.getModule(); + return new ModuleConfigurationEditor[] { + editorFactory.createModuleContentRootsEditor(state), + editorFactory.createLibrariesEditor(state), + editorFactory.createDependenciesEditor(state), + editorFactory.createOrderEntriesEditor(state), + editorFactory.createJavadocEditor(state), + new PluginModuleConfEditor(state.getProject(), module, state.getModulesProvider(), rootModel) + }; + } + + public void projectOpened() {} + public void projectClosed() {} + public void moduleAdded() {} + public void initComponent() {} + public void disposeComponent() {} +} \ No newline at end of file diff --git a/plugins/devkit/src/module/PluginModuleType.java b/plugins/devkit/src/module/PluginModuleType.java new file mode 100644 index 000000000000..c7a97a216aa4 --- /dev/null +++ b/plugins/devkit/src/module/PluginModuleType.java @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2004 JetBrains s.r.o. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * -Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * -Redistribution in binary form must reproduct the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the distribution. + * + * Neither the name of JetBrains or IntelliJ IDEA + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. JETBRAINS AND ITS LICENSORS SHALL NOT + * BE LIABLE FOR ANY DAMAGES OR LIABILITIES SUFFERED BY LICENSEE AS A RESULT + * OF OR RELATING TO USE, MODIFICATION OR DISTRIBUTION OF THE SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL JETBRAINS OR ITS LICENSORS BE LIABLE FOR ANY LOST + * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, + * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY + * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE SOFTWARE, EVEN + * IF JETBRAINS HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + * + */ +package org.jetbrains.idea.devkit.module; + +import com.intellij.ide.util.projectWizard.ModuleWizardStep; +import com.intellij.ide.util.projectWizard.ProjectWizardStepFactory; +import com.intellij.ide.util.projectWizard.WizardContext; +import com.intellij.openapi.module.ModuleType; +import com.intellij.openapi.roots.ui.configuration.ModulesProvider; +import com.intellij.openapi.util.IconLoader; + +import javax.swing.*; + +public class PluginModuleType extends ModuleType { + private static final Icon PLUGIN_MODULE_ICON = IconLoader.getIcon("/general/pluginManager.png"); + private static final Icon PLUGIN_MODULE_NODE_ICON = IconLoader.getIcon("/nodes/plugin.png"); + private static final Icon ADD_PLUGIN_MODULE_ICON = IconLoader.getIcon("/add_plugin_modulewizard.png"); + private static PluginModuleType ourInstance = new PluginModuleType(); + + private PluginModuleType() { + super("PLUGIN_MODULE"); + } + + public static PluginModuleType getInstance() { + return ourInstance; + } + + public final boolean isJ2EE() { + return false; + } + + public ModuleWizardStep[] createWizardSteps(WizardContext wizardContext, PluginModuleBuilder pluginModuleBuilder, ModulesProvider modulesProvider) { + final ProjectWizardStepFactory stepFactory = ProjectWizardStepFactory.getInstance(); + final ModuleWizardStep nameAndLocationStep = stepFactory.createNameAndLocationStep(wizardContext, pluginModuleBuilder, modulesProvider, ADD_PLUGIN_MODULE_ICON, null); + return new ModuleWizardStep[] { + nameAndLocationStep, + stepFactory.createSourcePathsStep(nameAndLocationStep, pluginModuleBuilder, ADD_PLUGIN_MODULE_ICON, null), + stepFactory.createOutputPathPathsStep(nameAndLocationStep, pluginModuleBuilder, ADD_PLUGIN_MODULE_ICON, null), + }; + } + + public PluginModuleBuilder createModuleBuilder() { + return new PluginModuleBuilder(); + } + + public String getName() { + return "Plugin Module"; + } + + public String getDescription() { + //TODO: better description + return "Useful for IDEA plugin development"; + } + + public Icon getBigIcon() { + return PLUGIN_MODULE_ICON; + } + + public Icon getNodeIcon(boolean isOpened) { + return PLUGIN_MODULE_NODE_ICON; + } +} \ No newline at end of file diff --git a/plugins/devkit/src/run/PluginConfigurationType.java b/plugins/devkit/src/run/PluginConfigurationType.java new file mode 100644 index 000000000000..b3114e8eb33a --- /dev/null +++ b/plugins/devkit/src/run/PluginConfigurationType.java @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2004 JetBrains s.r.o. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * -Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * -Redistribution in binary form must reproduct the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the distribution. + * + * Neither the name of JetBrains or IntelliJ IDEA + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. JETBRAINS AND ITS LICENSORS SHALL NOT + * BE LIABLE FOR ANY DAMAGES OR LIABILITIES SUFFERED BY LICENSEE AS A RESULT + * OF OR RELATING TO USE, MODIFICATION OR DISTRIBUTION OF THE SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL JETBRAINS OR ITS LICENSORS BE LIABLE FOR ANY LOST + * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, + * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY + * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE SOFTWARE, EVEN + * IF JETBRAINS HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + * + */ +package org.jetbrains.idea.devkit.run; + +import com.intellij.execution.configurations.ConfigurationFactory; +import com.intellij.execution.configurations.ConfigurationType; +import com.intellij.openapi.util.IconLoader; + +import javax.swing.*; + +public class PluginConfigurationType implements ConfigurationType { + private static final Icon ICON = IconLoader.getIcon("/nodes/plugin.png"); + + public String getDisplayName() { + return "Plugin"; + } + + public String getConfigurationTypeDescription() { + return "Plugin Sandbox Environment"; + } + + public Icon getIcon() { + return ICON; + } + + public ConfigurationFactory[] getConfigurationFactories() { + return new ConfigurationFactory[] {new PluginRunConfigurationFactory(this)}; + } + + public String getComponentName() { + return "#org.jetbrains.idea.devkit.run.PluginConfigurationType"; + } + + public void initComponent() { + } + + public void disposeComponent() { + } +} \ No newline at end of file diff --git a/plugins/devkit/src/run/PluginRunConfiguration.java b/plugins/devkit/src/run/PluginRunConfiguration.java new file mode 100644 index 000000000000..d81cdb6473e9 --- /dev/null +++ b/plugins/devkit/src/run/PluginRunConfiguration.java @@ -0,0 +1,214 @@ +/* + * Copyright (c) 2004 JetBrains s.r.o. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * -Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * -Redistribution in binary form must reproduct the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the distribution. + * + * Neither the name of JetBrains or IntelliJ IDEA + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. JETBRAINS AND ITS LICENSORS SHALL NOT + * BE LIABLE FOR ANY DAMAGES OR LIABILITIES SUFFERED BY LICENSEE AS A RESULT + * OF OR RELATING TO USE, MODIFICATION OR DISTRIBUTION OF THE SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL JETBRAINS OR ITS LICENSORS BE LIABLE FOR ANY LOST + * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, + * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY + * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE SOFTWARE, EVEN + * IF JETBRAINS HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + * + */ +package org.jetbrains.idea.devkit.run; + +import com.intellij.execution.CantRunException; +import com.intellij.execution.ExecutionException; +import com.intellij.execution.configurations.*; +import com.intellij.execution.filters.TextConsoleBuidlerFactory; +import com.intellij.execution.runners.JavaProgramRunner; +import com.intellij.execution.runners.RunnerInfo; +import com.intellij.openapi.actionSystem.DataContext; +import com.intellij.openapi.module.Module; +import com.intellij.openapi.module.ModuleManager; +import com.intellij.openapi.options.SettingsEditor; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.projectRoots.ProjectJdk; +import com.intellij.openapi.roots.ModuleRootManager; +import com.intellij.openapi.util.InvalidDataException; +import com.intellij.openapi.util.JDOMExternalizable; +import com.intellij.openapi.util.SystemInfo; +import com.intellij.openapi.util.WriteExternalException; +import org.jdom.Element; +import org.jetbrains.idea.devkit.module.PluginModuleType; +import org.jetbrains.idea.devkit.sandbox.Sandbox; +import org.jetbrains.idea.devkit.sandbox.SandboxManager; + +import java.util.ArrayList; +import java.util.List; + +public class PluginRunConfiguration extends RunConfigurationBase { + private List myModuleNames = new ArrayList(); + private String mySandboxName = ""; + + private String getSandboxPath() { + return getSandbox().getSandboxHome(); + } + + private String getBasePath() { + return getSandbox().getIdeaHome(); + } + + public Sandbox getSandbox() { + return SandboxManager.getInstance().findByName(mySandboxName); + } + + public void setSandbox(Sandbox box) { + mySandboxName = box == null ? "" : box.getName(); + } + + public static final String INTERNAL_BUILD_MARK = "__BUILD_NUMBER__"; + + public PluginRunConfiguration(final Project project, final ConfigurationFactory factory, final String name) { + super(project, factory, name); + } + + public SettingsEditor getConfigurationEditor() { + return new PluginRunConfigurationEditor(); + } + + public JDOMExternalizable createRunnerSettings(ConfigurationInfoProvider provider) { + return null; + } + + public SettingsEditor getRunnerSettingsEditor(JavaProgramRunner runner) { + return null; + } + + public RunProfileState getState(DataContext context, + RunnerInfo runnerInfo, + RunnerSettings runnerSettings, + ConfigurationPerRunnerSettings configurationSettings) throws ExecutionException { + final JavaCommandLineState state = new JavaCommandLineState(runnerSettings, configurationSettings) { + protected JavaParameters createJavaParameters() throws ExecutionException { + final JavaParameters params = new JavaParameters(); + + ParametersList vm = params.getVMParametersList(); + + String libPath = getBasePath() + "/lib"; + vm.add("-Xbootclasspath/p:" + libPath + "/boot.jar"); + + vm.defineProperty("idea.config.path", getSandboxPath() + "/config"); + vm.defineProperty("idea.system.path", getSandboxPath() + "/system"); + vm.defineProperty("idea.plugins.path", getSandboxPath() + "/plugins"); + + if (SystemInfo.isMac) { + vm.defineProperty("idea.smooth.progress", "false"); + vm.defineProperty("apple.laf.useScreenMenuBar", "true"); + } + + params.setWorkingDirectory(getBasePath() + "/bin/"); + + Module[] modules = getModules(); + if (modules.length == 0) { + throw new CantRunException("No plugin modules selected"); + } + + //TODO: Should run against same JRE IDEA runs against, right? + final ModuleRootManager rootManager = ModuleRootManager.getInstance(modules[0]); + final ProjectJdk jdk = rootManager.getJdk(); + if (jdk == null) { + throw CantRunException.noJdkForModule(modules[0]); + } + params.setJdk(jdk); + + params.getClassPath().addFirst(libPath + "/log4j.jar"); + params.getClassPath().addFirst(libPath + "/openapi.jar"); + params.getClassPath().addFirst(libPath + "/idea.jar"); + + params.setMainClass("com.intellij.idea.Main"); + + return params; + } + }; + + state.setConsoleBuilder(TextConsoleBuidlerFactory.getInstance().createBuilder(getProject())); + state.setModulesToCompile(getModules()); + return state; + } + + public void checkConfiguration() throws RuntimeConfigurationException { + /* + final Module module = getModule(); + if (module != null) { + if (module.getModuleType() != PluginModuleType.getInstance()) { + throw new RuntimeConfigurationError("Module " + module.getName() + " is of wrong type. Should be 'Plugin Module'."); + } + + if (ModuleRootManager.getInstance(module).getJdk() == null) { + throw new RuntimeConfigurationWarning("No JDK specified for module \"" + module.getName() + "\""); + } + else { + return; + } + } + else { + if (MODULE_NAME == null || MODULE_NAME.trim().length() == 0) { + throw new RuntimeConfigurationError("Module not specified"); + } + else { + throw new RuntimeConfigurationError("Module \"" + MODULE_NAME + "\" doesn't exist in project"); + } + } + */ + } + + public void setModules(Module[] modules) { + myModuleNames.clear(); + for (int i = 0; i < modules.length; i++) { + myModuleNames.add(modules[i].getName()); + } + } + + public Module[] getModules() { + List modules = new ArrayList(); + Module[] allModules = ModuleManager.getInstance(getProject()).getModules(); + for (int i = 0; i < allModules.length; i++) { + Module module = allModules[i]; + if (module.getModuleType() == PluginModuleType.getInstance() && myModuleNames.contains(module.getName())) { + modules.add(module); + } + } + return modules.toArray(new Module[modules.size()]); + } + + public void readExternal(Element element) throws InvalidDataException { + Element sandbox = element.getChild("sandbox"); + mySandboxName = sandbox == null ? "" : sandbox.getAttributeValue("name"); + List children = element.getChildren("module"); + for (int i = 0; i < children.size(); i++) { + Element moduleElement = (Element)children.get(i); + myModuleNames.add(moduleElement.getAttributeValue("name")); + } + } + + public void writeExternal(Element element) throws WriteExternalException { + Element sandbox = new Element("sandbox"); + sandbox.setAttribute("name", mySandboxName); + element.addContent(sandbox); + for (int i = 0; i < myModuleNames.size(); i++) { + Element moduleElement = new Element("module"); + moduleElement.setAttribute("name", myModuleNames.get(i)); + element.addContent(moduleElement); + } + } +} \ No newline at end of file diff --git a/plugins/devkit/src/run/PluginRunConfigurationEditor.java b/plugins/devkit/src/run/PluginRunConfigurationEditor.java new file mode 100644 index 000000000000..34d77ce50a7c --- /dev/null +++ b/plugins/devkit/src/run/PluginRunConfigurationEditor.java @@ -0,0 +1,174 @@ +/* + * Copyright (c) 2004 JetBrains s.r.o. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * -Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * -Redistribution in binary form must reproduct the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the distribution. + * + * Neither the name of JetBrains or IntelliJ IDEA + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. JETBRAINS AND ITS LICENSORS SHALL NOT + * BE LIABLE FOR ANY DAMAGES OR LIABILITIES SUFFERED BY LICENSEE AS A RESULT + * OF OR RELATING TO USE, MODIFICATION OR DISTRIBUTION OF THE SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL JETBRAINS OR ITS LICENSORS BE LIABLE FOR ANY LOST + * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, + * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY + * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE SOFTWARE, EVEN + * IF JETBRAINS HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + * + */ +package org.jetbrains.idea.devkit.run; + +import com.intellij.openapi.module.Module; +import com.intellij.openapi.options.ConfigurationException; +import com.intellij.openapi.options.SettingsEditor; +import com.intellij.openapi.options.ShowSettingsUtil; +import com.intellij.openapi.project.Project; +import com.intellij.ui.ComboboxWithBrowseButton; +import org.jetbrains.idea.devkit.module.PluginModuleType; +import org.jetbrains.idea.devkit.sandbox.Sandbox; +import org.jetbrains.idea.devkit.sandbox.SandboxConfigurable; +import org.jetbrains.idea.devkit.sandbox.SandboxManager; + +import javax.swing.*; +import java.awt.*; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.util.ArrayList; + +public class PluginRunConfigurationEditor extends SettingsEditor { + private EditorPanel myEditor; + private Project myProject; + + public void resetEditorFrom(PluginRunConfiguration prc) { + myProject = prc.getProject(); + Sandbox sandbox = prc.getSandbox(); + myEditor.setSelectedBox(sandbox); + updateModules(sandbox); + myEditor.setModules(prc.getModules()); + } + + private void updateModules(Sandbox sandbox) { + if (myProject != null && sandbox != null) { + myEditor.setModulesList(sandbox.getModules(myProject)); + } + else { + myEditor.setModulesList(new Module[0]); + } + } + + public void applyEditorTo(PluginRunConfiguration prc) throws ConfigurationException { + prc.setSandbox(myEditor.getSelectedBox()); + prc.setModules(myEditor.getModules()); + } + + public JComponent createEditor() { + myEditor = new EditorPanel(); + return myEditor.getComponent(); + } + + private class EditorPanel { + private JPanel myWholePanel; + private ComboboxWithBrowseButton mySandboxCombo; + private JList myModules; + + public EditorPanel() { + mySandboxCombo.getComboBox().setRenderer(new DefaultListCellRenderer() { + public Component getListCellRendererComponent(JList jList, Object o, int i, boolean b, boolean b1) { + super.getListCellRendererComponent(jList, o, i, b, b1); + if (o != null) { + setText(((Sandbox)o).getName()); + } + return this; + } + }); + + mySandboxCombo.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent event) { + Sandbox selected = getSelectedBox(); + ShowSettingsUtil.getInstance().editConfigurable(myWholePanel, SandboxConfigurable.getInstance()); + mySandboxCombo.getComboBox().setModel(new DefaultComboBoxModel(SandboxManager.getInstance().getRegisteredSandboxes())); + setSelectedBox(selected); + } + }); + + myModules.setCellRenderer(new DefaultListCellRenderer() { + public Component getListCellRendererComponent(JList jList, Object o, int i, boolean b, boolean b1) { + super.getListCellRendererComponent(jList, o, i, b, b1); + if (o != null) { + Module module = (Module)o; + setText(module.getName()); + setIcon(PluginModuleType.getInstance().getNodeIcon(false)); + } + return this; + } + }); + + + mySandboxCombo.getComboBox().setModel(new DefaultComboBoxModel(SandboxManager.getInstance().getRegisteredSandboxes())); + mySandboxCombo.getComboBox().addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent event) { + updateModules((Sandbox)mySandboxCombo.getComboBox().getSelectedItem()); + } + }); + } + + public void setSelectedBox(Sandbox box) { + mySandboxCombo.getComboBox().setSelectedItem(box); + } + + public Sandbox getSelectedBox() { + return (Sandbox)mySandboxCombo.getComboBox().getSelectedItem(); + } + + public JComponent getComponent() { + return myWholePanel; + } + + public Module[] getModules() { + Object[] values = myModules.getSelectedValues(); + if (values == null) return new Module[0]; + Module[] modules = new Module[values.length]; + for (int i = 0; i < modules.length; i++) { + modules[i] = (Module)values[i]; + } + return modules; + } + + public void setModules(Module[] modules) { + ArrayList allModules = new ArrayList(); + ListModel model = myModules.getModel(); + for (int i = 0; i < model.getSize(); i++) { + allModules.add((Module)model.getElementAt(i)); + } + + for (int i = 0; i < modules.length; i++) { + int idx = allModules.indexOf(modules[i]); + myModules.getSelectionModel().addSelectionInterval(idx, idx); + } + } + + public void setModulesList(Module[] modules) { + DefaultListModel model = new DefaultListModel(); + for (int i = 0; i < modules.length; i++) { + model.addElement(modules[i]); + } + myModules.setModel(model); + } + } + + public void disposeEditor() { + } +} \ No newline at end of file diff --git a/plugins/svn4idea/META-INF/plugin.xml b/plugins/svn4idea/META-INF/plugin.xml new file mode 100644 index 000000000000..69a1146249a3 --- /dev/null +++ b/plugins/svn4idea/META-INF/plugin.xml @@ -0,0 +1,57 @@ + + Subversion + Subversion Integration + 1.0 + QintSoft + + + + + + + + com.qintsoft.svn4idea.SvnVcs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/svn4idea/README.txt b/plugins/svn4idea/README.txt new file mode 100644 index 000000000000..69d82cef44b4 --- /dev/null +++ b/plugins/svn4idea/README.txt @@ -0,0 +1,24 @@ +This Idea plugin integrates Idea with Subversion. + +The plugin tries to be as tightly integrated with Idea as possible. + +Like the CVS integration it uses Idea's project view to display the workspace. +Changed files are color coded in the project view and the editor just as in the CVS integration. + +All files & directories in the project directory, that are in the subversion repository are tracked during +move and rename operations. + +Files & directories created through Idea in the projects source path are automatically tracked. +You can configure whether the new files shall be added to the +subversion repository (Always, Ask, Never). + +Additional directories to be tracked for newly created files can be entered in +the "Additional Path" list on the configuration page. + +Files & directories in a subversion repository which are deleted through Idea are automatically tracked. +You can configure whether the deleted files shall also be deleted from the subversion repository (Always, Ask, Never). + +Subversion operations can be trieggered from the Subversion menu (tools/Subversion) or from the context menu. + +For exended subversion operations (administration, blaming, properties etc) you can start the SvnUp +dialog from the Subversion menu (tools/Subversion/SvnUp). diff --git a/plugins/svn4idea/build/build.xml b/plugins/svn4idea/build/build.xml new file mode 100644 index 000000000000..8abab18079ca --- /dev/null +++ b/plugins/svn4idea/build/build.xml @@ -0,0 +1,85 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/plugins/svn4idea/svn4idea.iml b/plugins/svn4idea/svn4idea.iml new file mode 100644 index 000000000000..37e6f71c2a4d --- /dev/null +++ b/plugins/svn4idea/svn4idea.iml @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +