diff options
author | Tor Norbye <tnorbye@google.com> | 2014-09-18 13:38:58 -0700 |
---|---|---|
committer | Tor Norbye <tnorbye@google.com> | 2014-09-18 13:38:58 -0700 |
commit | b5fb31ef6a38f19404859755dbd2e345215b97bf (patch) | |
tree | e8787c45e494dfcc558faf0f75956f8785c39b94 /plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com | |
parent | e222a9e1e66670a56e926a6b0f3e10231eeeb1fb (diff) | |
parent | e782c57d74000722f9db4c9426317410520670c6 (diff) | |
download | idea-b5fb31ef6a38f19404859755dbd2e345215b97bf.tar.gz |
Merge remote-tracking branch 'aosp/upstream-master' into merge
Conflicts:
.idea/libraries/asm_tools.xml
.idea/libraries/bouncy_castle.xml
.idea/libraries/builder_model.xml
.idea/libraries/commons_compress.xml
.idea/libraries/easymock_tools.xml
.idea/libraries/freemarker_2_3_20.xml
.idea/libraries/guava_tools.xml
.idea/libraries/kxml2.xml
.idea/libraries/lombok_ast.xml
.idea/libraries/mockito.xml
.idea/modules.xml
.idea/vcs.xml
build/scripts/layouts.gant
updater/src/com/intellij/updater/Runner.java
Change-Id: I8e1c173e00cd76c855b8a98543b0a0edfdd99d12
Diffstat (limited to 'plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com')
19 files changed, 787 insertions, 582 deletions
diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/InspectionGadgetsBundle.properties b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/InspectionGadgetsBundle.properties index 1df72421fd4d..949ae7667e76 100644 --- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/InspectionGadgetsBundle.properties +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/InspectionGadgetsBundle.properties @@ -445,8 +445,8 @@ use.processbuilder.class.problem.descriptor=Use of <code>#ref</code> is non-port use.sun.classes.display.name=Use of sun.* classes use.sun.classes.problem.descriptor=Use of Sun-supplied class <code>#ref</code> is non-portable #loc abstract.class.with.only.one.direct.inheritor.display.name=Abstract class which has only one direct inheritor -anonymous.inner.may.be.named.static.inner.class.display.name=Anonymous inner class may be a named static inner class -anonymous.inner.may.be.named.static.inner.class.problem.descriptor=Anonymous inner class <code>#ref</code> may be a named static inner class #loc +anonymous.inner.may.be.named.static.inner.class.display.name=Anonymous class may be a named 'static' inner class +anonymous.inner.may.be.named.static.inner.class.problem.descriptor=Anonymous class <code>#ref</code> may be a named 'static' inner class #loc array.length.in.loop.condition.display.name=Array.length in loop condition array.length.in.loop.condition.problem.descriptor=Check of array <code>#ref</code> in loop condition #loc large.array.allocation.no.outofmemoryerror.display.name=Large array allocation with no OutOfMemoryError check @@ -992,7 +992,8 @@ constant.on.lhs.of.comparison.problem.descriptor=<code>#ref</code>: constant on constant.on.rhs.of.comparison.problem.descriptor=<code>#ref</code>: constant on right side of comparison #loc control.flow.statement.without.braces.problem.descriptor=<code>#ref</code> without braces #loc missorted.modifiers.problem.descriptor=Missorted modifiers <code>#ref</code> #loc -c.style.array.declaration.problem.descriptor=C-style array declaration <code>#ref</code> #loc +cstyle.array.variable.declaration.problem.descriptor=C-style array declaration of {0, choice, 1#field|2#parameter|3#local variable} <code>#ref</code> #loc +cstyle.array.method.declaration.problem.descriptor=C-style array declaration of the return type of method <code>#ref()</code>#loc multiple.declaration.problem.descriptor=Multiple variables in one declaration #loc multiple.typed.declaration.problem.descriptor=Variables of different types in one declaration #loc serializable.inner.class.has.serial.version.uid.field.problem.descriptor=Inner class <code>#ref</code> does not define a 'serialVersionUID' field #loc @@ -1290,7 +1291,7 @@ call.to.simple.getter.in.class.inline.quickfix=Inline call to getter call.to.simple.setter.in.class.ignore.option=Ignore setter calls on other objects call.to.private.setter.in.class.option=Only report when setter is private call.to.simple.setter.in.class.inline.quickfix=Inline call to setter -make.static.quickfix=Make static +make.static.quickfix=Make 'static' length.one.strings.in.concatenation.replace.quickfix=Replace with character multiply.or.divide.by.power.of.two.replace.quickfix=Replace with shift boolean.expression.can.be.simplified.problem.descriptor=<code>#ref</code> can be simplified to ''{0}'' #loc @@ -1366,6 +1367,8 @@ implicit.call.to.super.make.explicit.quickfix=Make call to 'super()' explicit missorted.modifiers.require.option=Require annotations to be sorted before keywords missorted.modifiers.sort.quickfix=Sort modifiers nested.method.call.ignore.option=Ignore nested method calls in field initializers +ignore.calls.to.static.methods=Ignore calls to static methods +ignore.calls.to.property.getters=Ignore calls to property getters redundant.field.initialization.remove.quickfix=Remove initializer redundant.implements.remove.quickfix=Remove redundant interface declaration unnecessary.constructor.remove.quickfix=Remove redundant constructor @@ -1691,8 +1694,8 @@ char.used.in.arithmetic.context.cast.quickfix=Insert cast to {0} unnecessary.constant.array.creation.expression.display.name=Constant array creation expression can be replaced with array initializer unnecessary.constant.array.creation.expression.problem.descriptor=<code>#ref</code> can be replaced with array initializer expression #loc unnecessary.constant.array.creation.expression.quickfix=Replace with array initializer expression -ambiguous.method.call.display.name=Inherited method called, while local method might have been expected -ambiguous.method.call.problem.descriptor=Method <code>#ref()</code> from superclass ''{0}'' called, when method from class ''{1}'' might have been expected #loc +ambiguous.method.call.display.name=Call to inherited method looks like call to local method +ambiguous.method.call.problem.descriptor=Call to method <code>#ref()</code> from superclass ''{0}'' looks like call to method from class ''{1}'' #loc ambiguous.method.call.quickfix=Add 'super' qualifier to method call change.modifier.quickfix=Make ''{0}'' the.whole.project=the whole project @@ -1969,10 +1972,10 @@ throws.runtime.exception.problem.descriptor=Unchecked exception <code>#ref</code throws.runtime.exception.quickfix=Remove ''{0}'' from ''throws'' clause throws.runtime.exception.move.quickfix=Move ''{0}'' to Javadoc ''@throws'' tag empty.class.ignore.parameterization.option=Ignore class if it is a parameterization of a super type -ambiguous.field.access.display.name=Inherited field accessed while local variable, parameter or field access from surrounding class might be expected -ambiguous.field.access.hides.local.variable.problem.descriptor=Field <code>#ref</code> from superclass ''{0}'' accessed, while local variable access might be expected #loc -ambiguous.field.access.hides.parameter.problem.descriptor=Field <code>#ref</code> from superclass ''{0}'' accessed, while parameter access might be expected #loc -ambiguous.field.access.hides.field.problem.descriptor=Field <code>#ref</code> from superclass ''{0}'' accessed, while field access from surrounding class might be expected #loc +ambiguous.field.access.display.name=Access of inherited field looks like access of element in surrounding code +ambiguous.field.access.hides.local.variable.problem.descriptor=Access of field <code>#ref</code> from superclass ''{0}'' looks like access of local variable #loc +ambiguous.field.access.hides.parameter.problem.descriptor=Access of field <code>#ref</code> from superclass ''{0}'' looks like access of parameter #loc +ambiguous.field.access.hides.field.problem.descriptor=Access of field <code>#ref</code> from superclass ''{0}'' looks access of field from surrounding class #loc ambiguous.field.access.quickfix=Add 'super' qualifier to field access string.builder.replaceable.by.string.quickfix=Replace 'StringBuilder' with 'String' string.buffer.replaceable.by.string.quickfix=Replace 'StringBuffer' with 'String' @@ -2111,3 +2114,6 @@ junit3.method.naming.convention.display.name=JUnit 3 test method naming conventi junit3.method.naming.convention.problem.descriptor.short=JUnit 3 test method name <code>#ref</code> is too short ({0} < {1}) #loc junit3.method.naming.convention.problem.descriptor.long=JUnit 3 test method name <code>#ref</code> is too long ({0} > {1}) #loc junit3.method.naming.convention.problem.descriptor.regex.mismatch=JUnit 3 test method name <code>#ref</code> doesn''t match regex ''{0}'' #loc +introduce.holder.class.quickfix=Introduce holder class +double.brace.initialization.display.name=Double brace initialization +double.brace.initialization.quickfix=Replace with regular initialization diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/bugs/ResultSetIndexZeroInspection.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/bugs/ResultSetIndexZeroInspection.java index 626d4508e731..a72f297e483c 100644 --- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/bugs/ResultSetIndexZeroInspection.java +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/bugs/ResultSetIndexZeroInspection.java @@ -1,5 +1,5 @@ /* - * Copyright 2003-2012 Dave Griffith, Bas Leijdekkers + * Copyright 2003-2014 Dave Griffith, Bas Leijdekkers * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -87,11 +87,11 @@ public class ResultSetIndexZeroInspection extends BaseInspection { final PsiExpression qualifier = methodExpression.getQualifierExpression(); if (resultSet) { if (TypeUtils.expressionHasTypeOrSubtype(qualifier, "java.sql.ResultSet")) { - registerError(argument, Boolean.valueOf(resultSet)); + registerError(argument, Boolean.TRUE); } - } else { + } else if (arguments.length > 1) { if (TypeUtils.expressionHasTypeOrSubtype(qualifier, "java.sql.PreparedStatement")) { - registerError(argument, Boolean.valueOf(resultSet)); + registerError(argument, Boolean.FALSE); } } } diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/bugs/StringEqualityInspection.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/bugs/StringEqualityInspection.java index 0ac07245fd8f..f94f495993d7 100644 --- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/bugs/StringEqualityInspection.java +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/bugs/StringEqualityInspection.java @@ -1,5 +1,5 @@ /* - * Copyright 2003-2012 Dave Griffith, Bas Leijdekkers + * Copyright 2003-2014 Dave Griffith, Bas Leijdekkers * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,7 +18,6 @@ package com.siyeh.ig.bugs; import com.intellij.psi.PsiBinaryExpression; import com.intellij.psi.PsiExpression; import com.intellij.psi.PsiJavaToken; -import com.intellij.psi.PsiKeyword; import com.siyeh.InspectionGadgetsBundle; import com.siyeh.ig.BaseInspection; import com.siyeh.ig.BaseInspectionVisitor; @@ -73,12 +72,7 @@ public class StringEqualityInspection extends BaseInspection { if (rhs == null || !ExpressionUtils.hasStringType(rhs)) { return; } - final String lhsText = lhs.getText(); - if (PsiKeyword.NULL.equals(lhsText)) { - return; - } - final String rhsText = rhs.getText(); - if (PsiKeyword.NULL.equals(rhsText)) { + if (ExpressionUtils.isNullLiteral(lhs) || ExpressionUtils.isNullLiteral(rhs)) { return; } final PsiJavaToken sign = expression.getOperationSign(); diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/classlayout/ClassWithOnlyPrivateConstructorsInspectionBase.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/classlayout/ClassWithOnlyPrivateConstructorsInspectionBase.java index 6d091699ce82..b6583b4ede75 100644 --- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/classlayout/ClassWithOnlyPrivateConstructorsInspectionBase.java +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/classlayout/ClassWithOnlyPrivateConstructorsInspectionBase.java @@ -54,6 +54,9 @@ public class ClassWithOnlyPrivateConstructorsInspectionBase extends BaseInspecti @Override public void visitClass(PsiClass aClass) { super.visitClass(aClass); + if (aClass.isEnum()) { + return; + } final PsiMethod[] constructors = aClass.getConstructors(); if (constructors.length == 0) { return; diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/controlflow/LoopConditionNotUpdatedInsideLoopInspection.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/controlflow/LoopConditionNotUpdatedInsideLoopInspection.java index 46969fd5bcfc..57c635b7d461 100644 --- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/controlflow/LoopConditionNotUpdatedInsideLoopInspection.java +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/controlflow/LoopConditionNotUpdatedInsideLoopInspection.java @@ -1,5 +1,5 @@ /* - * Copyright 2006-2013 Bas Leijdekkers + * Copyright 2006-2014 Bas Leijdekkers * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -24,6 +24,7 @@ import com.siyeh.InspectionGadgetsBundle; import com.siyeh.ig.BaseInspection; import com.siyeh.ig.BaseInspectionVisitor; import com.siyeh.ig.psiutils.BoolUtils; +import com.siyeh.ig.psiutils.ExpressionUtils; import com.siyeh.ig.psiutils.IteratorUtils; import com.siyeh.ig.psiutils.VariableAccessUtils; import org.jetbrains.annotations.NotNull; @@ -118,8 +119,7 @@ public class LoopConditionNotUpdatedInsideLoopInspection if (condition == null) { return false; } - if (PsiUtil.isConstantExpression(condition) || - PsiKeyword.NULL.equals(condition.getText())) { + if (PsiUtil.isConstantExpression(condition) || ExpressionUtils.isNullLiteral(condition)) { return true; } if (condition instanceof PsiInstanceOfExpression) { diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/initialization/DoubleBraceInitializationInspection.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/initialization/DoubleBraceInitializationInspection.java new file mode 100644 index 000000000000..bdf58e720d8d --- /dev/null +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/initialization/DoubleBraceInitializationInspection.java @@ -0,0 +1,216 @@ +/* + * Copyright 2000-2014 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.siyeh.ig.initialization; + +import com.intellij.codeInspection.ProblemDescriptor; +import com.intellij.openapi.project.Project; +import com.intellij.psi.*; +import com.intellij.psi.util.PsiTreeUtil; +import com.siyeh.InspectionGadgetsBundle; +import com.siyeh.ig.BaseInspection; +import com.siyeh.ig.BaseInspectionVisitor; +import com.siyeh.ig.InspectionGadgetsFix; +import com.siyeh.ig.psiutils.ParenthesesUtils; +import org.jetbrains.annotations.Nls; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * @author Bas Leijdekkers + */ +public class DoubleBraceInitializationInspection extends BaseInspection { + @Nls + @NotNull + @Override + public String getDisplayName() { + return InspectionGadgetsBundle.message("double.brace.initialization.display.name"); + } + + @NotNull + @Override + protected String buildErrorString(Object... infos) { + return InspectionGadgetsBundle.message("double.brace.initialization.display.name"); + } + + @Nullable + @Override + protected InspectionGadgetsFix buildFix(Object... infos) { + final PsiClass aClass = (PsiClass)infos[0]; + final PsiElement parent = PsiTreeUtil.skipParentsOfType(aClass, PsiNewExpression.class, ParenthesesUtils.class); + if (!(parent instanceof PsiVariable) && !(parent instanceof PsiAssignmentExpression)) { + return null; + } + return new DoubleBraceInitializationFix(); + } + + private static class DoubleBraceInitializationFix extends InspectionGadgetsFix { + + @NotNull + @Override + public String getName() { + return InspectionGadgetsBundle.message("double.brace.initialization.quickfix"); + } + + @NotNull + @Override + public String getFamilyName() { + return getName(); + } + + @Override + protected void doFix(Project project, ProblemDescriptor descriptor) { + final PsiElement element = descriptor.getPsiElement().getParent(); + if (!(element instanceof PsiAnonymousClass)) { + return; + } + final PsiAnonymousClass aClass = (PsiAnonymousClass)element; + final PsiElement parent = aClass.getParent(); + if (!(parent instanceof PsiNewExpression)) { + return; + } + final PsiNewExpression newExpression = (PsiNewExpression)parent; + final PsiElement ancestor = PsiTreeUtil.skipParentsOfType(newExpression, ParenthesesUtils.class); + final String qualifierText; + if (ancestor instanceof PsiVariable) { + qualifierText = ((PsiVariable)ancestor).getName(); + } + else if (ancestor instanceof PsiAssignmentExpression) { + final PsiAssignmentExpression assignmentExpression = (PsiAssignmentExpression)ancestor; + final PsiExpression lhs = ParenthesesUtils.stripParentheses(assignmentExpression.getLExpression()); + if (!(lhs instanceof PsiReferenceExpression)) { + return; + } + final PsiReferenceExpression referenceExpression = (PsiReferenceExpression)lhs; + final PsiElement target = referenceExpression.resolve(); + if (!(target instanceof PsiVariable)) { + return; + } + qualifierText = referenceExpression.getText(); + } + else { + return; + } + final PsiElementFactory factory = JavaPsiFacade.getElementFactory(project); + final PsiJavaCodeReferenceElement baseClassReference = aClass.getBaseClassReference(); + final PsiElement baseClassTarget = baseClassReference.resolve(); + if (!(baseClassTarget instanceof PsiClass)) { + return; + } + final PsiExpressionList argumentList = aClass.getArgumentList(); + if (argumentList == null) { + return; + } + qualifyReferences(aClass, (PsiClass) baseClassTarget, qualifierText); + final PsiClassInitializer initializer = aClass.getInitializers()[0]; + final PsiCodeBlock body = initializer.getBody(); + PsiElement child = body.getLastBodyElement(); + final PsiElement stop = body.getFirstBodyElement(); + final PsiElement anchor = PsiTreeUtil.getParentOfType(aClass, PsiMember.class, PsiStatement.class); + if (anchor == null) { + return; + } + if (anchor instanceof PsiMember) { + final PsiMember member = (PsiMember)anchor; + final PsiClassInitializer newInitializer = factory.createClassInitializer(); + if (member.hasModifierProperty(PsiModifier.STATIC)) { + final PsiModifierList modifierList = newInitializer.getModifierList(); + if (modifierList != null) { + modifierList.setModifierProperty(PsiModifier.STATIC, true); + } + } + final PsiCodeBlock initializerBody = newInitializer.getBody(); + while (child != null && !child.equals(stop)) { + initializerBody.add(child); + child = child.getPrevSibling(); + } + member.getParent().addAfter(newInitializer, member); + } + else { + final PsiElement container = anchor.getParent(); + while (child != null && !child.equals(stop)) { + container.addAfter(child, anchor); + child = child.getPrevSibling(); + } + } + final PsiExpression newNewExpression = + factory.createExpressionFromText("new " + baseClassReference.getText() + argumentList.getText(), aClass); + newExpression.replace(newNewExpression); + } + + private static void qualifyReferences(PsiElement element, final PsiClass target, final String qualifierText) { + final PsiElementFactory factory = JavaPsiFacade.getElementFactory(element.getProject()); + element.accept(new JavaRecursiveElementVisitor() { + @Override + public void visitReferenceExpression(PsiReferenceExpression expression) { + super.visitReferenceExpression(expression); + if (expression.getQualifierExpression() != null) { + return; + } + final PsiElement expressionTarget = expression.resolve(); + if (!(expressionTarget instanceof PsiMember)) { + return; + } + final PsiMember member = (PsiMember)expressionTarget; + final PsiClass containingClass = member.getContainingClass(); + if (!target.equals(containingClass)) { + return; + } + final PsiExpression newExpression = factory.createExpressionFromText(qualifierText + '.' + expression.getText(), expression); + expression.replace(newExpression); + } + }); + } + } + + @Override + public BaseInspectionVisitor buildVisitor() { + return new DoubleBraceInitializationVisitor(); + } + + private static class DoubleBraceInitializationVisitor extends BaseInspectionVisitor { + + @Override + public void visitAnonymousClass(PsiAnonymousClass aClass) { + super.visitAnonymousClass(aClass); + final PsiClassInitializer[] initializers = aClass.getInitializers(); + if (initializers.length != 1) { + return; + } + final PsiClassInitializer initializer = initializers[0]; + if (initializer.hasModifierProperty(PsiModifier.STATIC)) { + // don't warn on broken code + return; + } + final PsiField[] fields = aClass.getFields(); + if (fields.length != 0) { + return; + } + final PsiMethod[] methods = aClass.getMethods(); + if (methods.length != 0) { + return; + } + final PsiClass[] innerClasses = aClass.getInnerClasses(); + if (innerClasses.length != 0) { + return; + } + final PsiJavaCodeReferenceElement reference = aClass.getBaseClassReference(); + if (reference.resolve() == null) { + return; + } + registerClassError(aClass, aClass); + } + } +} diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/initialization/NonThreadSafeLazyInitializationInspection.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/initialization/NonThreadSafeLazyInitializationInspection.java deleted file mode 100644 index 2e0bebac17b9..000000000000 --- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/initialization/NonThreadSafeLazyInitializationInspection.java +++ /dev/null @@ -1,246 +0,0 @@ -/* - * Copyright 2003-2007 Dave Griffith, Bas Leijdekkers - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.siyeh.ig.initialization; - -import com.intellij.codeInspection.ProblemDescriptor; -import com.intellij.openapi.project.Project; -import com.intellij.psi.*; -import com.intellij.psi.search.searches.ReferencesSearch; -import com.intellij.psi.tree.IElementType; -import com.intellij.psi.util.PsiTreeUtil; -import com.intellij.psi.util.PsiUtil; -import com.intellij.util.IncorrectOperationException; -import com.intellij.util.Processor; -import com.siyeh.InspectionGadgetsBundle; -import com.siyeh.ig.BaseInspection; -import com.siyeh.ig.BaseInspectionVisitor; -import com.siyeh.ig.InspectionGadgetsFix; -import org.jetbrains.annotations.NonNls; -import org.jetbrains.annotations.NotNull; - -import java.util.Collection; - -public class NonThreadSafeLazyInitializationInspection - extends BaseInspection { - - @Override - @NotNull - public String getDisplayName() { - return InspectionGadgetsBundle.message( - "non.thread.safe.lazy.initialization.display.name"); - } - - @Override - @NotNull - public String buildErrorString(Object... infos) { - return InspectionGadgetsBundle.message( - "non.thread.safe.lazy.initialization.problem.descriptor"); - } - - @Override - public BaseInspectionVisitor buildVisitor() { - return new UnsafeSafeLazyInitializationVisitor(); - } - - private static class UnsafeSafeLazyInitializationVisitor - extends BaseInspectionVisitor { - - @Override - public void visitAssignmentExpression( - @NotNull PsiAssignmentExpression expression) { - super.visitAssignmentExpression(expression); - final PsiExpression lhs = expression.getLExpression(); - if (!(lhs instanceof PsiReferenceExpression)) { - return; - } - final PsiReference reference = (PsiReference)lhs; - final PsiElement referent = reference.resolve(); - if (!(referent instanceof PsiField)) { - return; - } - final PsiField field = (PsiField)referent; - if (!field.hasModifierProperty(PsiModifier.STATIC)) { - return; - } - if (isInStaticInitializer(expression)) { - return; - } - if (isInSynchronizedContext(expression)) { - return; - } - if (!isLazy(expression, (PsiReferenceExpression)lhs)) { - return; - } - boolean assignedOnce = isAssignedOnce(referent); - boolean safeToDelete = isSafeToDeleteIfStatement(expression); - registerError(lhs, assignedOnce && safeToDelete); - } - - private static boolean isAssignedOnce(PsiElement referent) { - final int[] writeCount = new int[1]; - return ReferencesSearch.search(referent).forEach(new Processor<PsiReference>() { - @Override - public boolean process(PsiReference reference) { - PsiElement element = reference.getElement(); - if (!(element instanceof PsiExpression)) { - return true; - } - if (!PsiUtil.isAccessedForWriting((PsiExpression)element)) { - return true; - } - return ++writeCount[0] != 2; - } - }); - } - - private static boolean isSafeToDeleteIfStatement(PsiElement expression) { - PsiIfStatement ifStatement = PsiTreeUtil.getParentOfType(expression, PsiIfStatement.class); - if (ifStatement.getElseBranch() != null) { - return false; - } - PsiStatement thenBranch = ifStatement.getThenBranch(); - if (thenBranch == null) return false; - if (!(thenBranch instanceof PsiBlockStatement)) { - return true; - } - return ((PsiBlockStatement)thenBranch).getCodeBlock().getStatements().length == 1; - } - - private static boolean isLazy(PsiAssignmentExpression expression, - PsiReferenceExpression lhs) { - final PsiIfStatement ifStatement = - PsiTreeUtil.getParentOfType(expression, - PsiIfStatement.class); - if (ifStatement == null) { - return false; - } - final PsiExpression condition = ifStatement.getCondition(); - if (condition == null) { - return false; - } - return isNullComparison(condition, lhs); - } - - private static boolean isNullComparison( - PsiExpression condition, PsiReferenceExpression reference) { - if (!(condition instanceof PsiBinaryExpression)) { - return false; - } - final PsiBinaryExpression comparison = - (PsiBinaryExpression)condition; - final IElementType tokenType = comparison.getOperationTokenType(); - if (!tokenType.equals(JavaTokenType.EQEQ)) { - return false; - } - final PsiExpression lhs = comparison.getLOperand(); - final PsiExpression rhs = comparison.getROperand(); - if (rhs == null) { - return false; - } - final String lhsText = lhs.getText(); - final String rhsText = rhs.getText(); - if (!PsiKeyword.NULL.equals(lhsText) && - !PsiKeyword.NULL.equals(rhsText)) { - return false; - } - final String referenceText = reference.getText(); - return referenceText.equals(lhsText) || - referenceText.equals(rhsText); - } - - private static boolean isInSynchronizedContext(PsiElement element) { - final PsiSynchronizedStatement syncBlock = - PsiTreeUtil.getParentOfType(element, - PsiSynchronizedStatement.class); - if (syncBlock != null) { - return true; - } - final PsiMethod method = - PsiTreeUtil.getParentOfType(element, - PsiMethod.class); - return method != null && - method.hasModifierProperty(PsiModifier.SYNCHRONIZED) - && method.hasModifierProperty(PsiModifier.STATIC); - } - - private static boolean isInStaticInitializer(PsiElement element) { - final PsiClassInitializer initializer = - PsiTreeUtil.getParentOfType(element, - PsiClassInitializer.class); - return initializer != null && - initializer.hasModifierProperty(PsiModifier.STATIC); - } - } - - @Override - protected InspectionGadgetsFix buildFix(Object... infos) { - boolean isApplicable = ((Boolean)infos[0]).booleanValue(); - return isApplicable ? new IntroduceHolderFix() : null; - } - - private static class IntroduceHolderFix extends InspectionGadgetsFix { - @Override - protected void doFix(Project project, ProblemDescriptor descriptor) throws IncorrectOperationException { - PsiReferenceExpression expression = (PsiReferenceExpression)descriptor.getPsiElement(); - PsiElement resolved = expression.resolve(); - if (!(resolved instanceof PsiField)) return; - PsiField field = (PsiField)resolved; - String holderName = suggestHolderName(field); - @NonNls String text = "private static class " + holderName - + " {" + - "private static final " + field.getType().getCanonicalText() + " " + - field.getName() + " = " + ((PsiAssignmentExpression)expression.getParent()).getRExpression().getText() + ";" - + "}"; - PsiElementFactory elementFactory = JavaPsiFacade.getInstance(field.getProject()).getElementFactory(); - PsiClass holder = elementFactory.createClassFromText(text, field).getInnerClasses()[0]; - PsiMethod method = PsiTreeUtil.getParentOfType(expression, PsiMethod.class); - method.getParent().addBefore(holder, method); - - PsiIfStatement ifStatement = PsiTreeUtil.getParentOfType(expression, PsiIfStatement.class); - ifStatement.delete(); - - final PsiExpression holderReference = elementFactory.createExpressionFromText(holderName + "." + field.getName(), field); - Collection<PsiReference> references = ReferencesSearch.search(field).findAll(); - for (PsiReference reference : references) { - PsiElement element = reference.getElement(); - element.replace(holderReference); - } - field.delete(); - } - - @NonNls - private static String suggestHolderName(PsiField field) { - String string = field.getType().getDeepComponentType().getPresentableText(); - final int index = string.indexOf('<'); - if (index != -1) { - string = string.substring(0, index); - } - return string + "Holder"; - } - - @Override - @NotNull - public String getName() { - return "Introduce holder class"; - } - - @NotNull - @Override - public String getFamilyName() { - return getName(); - } - } -}
\ No newline at end of file diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/initialization/NonThreadSafeLazyInitializationInspectionBase.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/initialization/NonThreadSafeLazyInitializationInspectionBase.java new file mode 100644 index 000000000000..f29c461bcf64 --- /dev/null +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/initialization/NonThreadSafeLazyInitializationInspectionBase.java @@ -0,0 +1,132 @@ +/* + * Copyright 2003-2014 Dave Griffith, Bas Leijdekkers + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.siyeh.ig.initialization; + +import com.intellij.psi.*; +import com.intellij.psi.tree.IElementType; +import com.intellij.psi.util.PsiTreeUtil; +import com.siyeh.InspectionGadgetsBundle; +import com.siyeh.ig.BaseInspection; +import com.siyeh.ig.BaseInspectionVisitor; +import com.siyeh.ig.psiutils.ExpressionUtils; +import com.siyeh.ig.psiutils.VariableAccessUtils; +import org.jetbrains.annotations.NotNull; + +public class NonThreadSafeLazyInitializationInspectionBase extends BaseInspection { + + @Override + @NotNull + public String getDisplayName() { + return InspectionGadgetsBundle.message( + "non.thread.safe.lazy.initialization.display.name"); + } + + @Override + @NotNull + public String buildErrorString(Object... infos) { + return InspectionGadgetsBundle.message( + "non.thread.safe.lazy.initialization.problem.descriptor"); + } + + @Override + public BaseInspectionVisitor buildVisitor() { + return new UnsafeSafeLazyInitializationVisitor(); + } + + private static class UnsafeSafeLazyInitializationVisitor + extends BaseInspectionVisitor { + + @Override + public void visitAssignmentExpression( + @NotNull PsiAssignmentExpression expression) { + super.visitAssignmentExpression(expression); + final PsiExpression lhs = expression.getLExpression(); + if (!(lhs instanceof PsiReferenceExpression)) { + return; + } + final PsiReferenceExpression reference = (PsiReferenceExpression)lhs; + final PsiElement referent = reference.resolve(); + if (!(referent instanceof PsiField)) { + return; + } + final PsiField field = (PsiField)referent; + if (!field.hasModifierProperty(PsiModifier.STATIC)) { + return; + } + if (isInStaticInitializer(expression)) { + return; + } + if (isInSynchronizedContext(expression)) { + return; + } + final PsiStatement statement = PsiTreeUtil.getParentOfType(expression, PsiStatement.class); + final PsiElement parent = + PsiTreeUtil.skipParentsOfType(statement, PsiCodeBlock.class, PsiBlockStatement.class); + if (!(parent instanceof PsiIfStatement)) { + return; + } + final PsiIfStatement ifStatement = (PsiIfStatement)parent; + final PsiExpression condition = ifStatement.getCondition(); + if (condition == null|| !isNullComparison(condition, field)) { + return; + } + registerError(lhs, ifStatement, field); + } + + private static boolean isNullComparison(PsiExpression condition, PsiVariable variable) { + if (!(condition instanceof PsiBinaryExpression)) { + return false; + } + final PsiBinaryExpression comparison = (PsiBinaryExpression)condition; + final IElementType tokenType = comparison.getOperationTokenType(); + if (!tokenType.equals(JavaTokenType.EQEQ)) { + return false; + } + final PsiExpression lhs = comparison.getLOperand(); + final PsiExpression rhs = comparison.getROperand(); + if (ExpressionUtils.isNullLiteral(rhs)) { + return VariableAccessUtils.evaluatesToVariable(lhs, variable); + } + else if (ExpressionUtils.isNullLiteral(lhs)) { + return VariableAccessUtils.evaluatesToVariable(rhs, variable); + } + return false; + } + + private static boolean isInSynchronizedContext(PsiElement element) { + final PsiSynchronizedStatement syncBlock = + PsiTreeUtil.getParentOfType(element, + PsiSynchronizedStatement.class); + if (syncBlock != null) { + return true; + } + final PsiMethod method = + PsiTreeUtil.getParentOfType(element, + PsiMethod.class); + return method != null && + method.hasModifierProperty(PsiModifier.SYNCHRONIZED) + && method.hasModifierProperty(PsiModifier.STATIC); + } + + private static boolean isInStaticInitializer(PsiElement element) { + final PsiClassInitializer initializer = + PsiTreeUtil.getParentOfType(element, + PsiClassInitializer.class); + return initializer != null && + initializer.hasModifierProperty(PsiModifier.STATIC); + } + } +}
\ No newline at end of file diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/j2me/AnonymousInnerClassMayBeStaticInspectionBase.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/j2me/AnonymousInnerClassMayBeStaticInspectionBase.java deleted file mode 100644 index 4ea6a4c7290f..000000000000 --- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/j2me/AnonymousInnerClassMayBeStaticInspectionBase.java +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Copyright 2000-2013 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.siyeh.ig.j2me; - -import com.intellij.psi.*; -import com.intellij.psi.util.PsiTreeUtil; -import com.siyeh.InspectionGadgetsBundle; -import com.siyeh.ig.BaseInspection; -import com.siyeh.ig.BaseInspectionVisitor; -import com.siyeh.ig.performance.InnerClassReferenceVisitor; -import org.jetbrains.annotations.NotNull; - -public class AnonymousInnerClassMayBeStaticInspectionBase extends BaseInspection { - @Override - @NotNull - public String getDisplayName() { - return InspectionGadgetsBundle.message( - "anonymous.inner.may.be.named.static.inner.class.display.name"); - } - - @Override - @NotNull - public String buildErrorString(Object... infos) { - return InspectionGadgetsBundle.message( - "anonymous.inner.may.be.named.static.inner.class.problem.descriptor"); - } - - @Override - public BaseInspectionVisitor buildVisitor() { - return new AnonymousInnerClassMayBeStaticVisitor(); - } - - private static class AnonymousInnerClassMayBeStaticVisitor - extends BaseInspectionVisitor { - - @Override - public void visitClass(@NotNull PsiClass aClass) { - if (!(aClass instanceof PsiAnonymousClass)) { - return; - } - if (aClass instanceof PsiEnumConstantInitializer) { - return; - } - final PsiMember containingMember = - PsiTreeUtil.getParentOfType(aClass, PsiMember.class); - if (containingMember == null || - containingMember.hasModifierProperty(PsiModifier.STATIC)) { - return; - } - final PsiAnonymousClass anAnonymousClass = - (PsiAnonymousClass)aClass; - final InnerClassReferenceVisitor visitor = - new InnerClassReferenceVisitor(anAnonymousClass); - anAnonymousClass.accept(visitor); - if (!visitor.canInnerClassBeStatic()) { - return; - } - registerClassError(aClass); - } - } -} diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/javadoc/MissingPackageInfoInspection.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/javadoc/MissingPackageInfoInspectionBase.java index 1305663d7710..dcd737d983fd 100644 --- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/javadoc/MissingPackageInfoInspection.java +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/javadoc/MissingPackageInfoInspectionBase.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2013 JetBrains s.r.o. + * Copyright 2000-2014 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -40,7 +40,7 @@ import java.util.List; /** * @author Bas Leijdekkers */ -public class MissingPackageInfoInspection extends BaseGlobalInspection { +public class MissingPackageInfoInspectionBase extends BaseGlobalInspection { @Nls @NotNull @@ -105,12 +105,12 @@ public class MissingPackageInfoInspection extends BaseGlobalInspection { @Nullable @Override public LocalInspectionTool getSharedLocalInspectionTool() { - return new LocalMissingPackageInfoInspection(this); + return new LocalMissingPackageInfoInspectionBase(this); } - private static class LocalMissingPackageInfoInspection extends BaseSharedLocalInspection<MissingPackageInfoInspection> { + protected static class LocalMissingPackageInfoInspectionBase extends BaseSharedLocalInspection<MissingPackageInfoInspectionBase> { - public LocalMissingPackageInfoInspection(MissingPackageInfoInspection settingsDelegate) { + public LocalMissingPackageInfoInspectionBase(MissingPackageInfoInspectionBase settingsDelegate) { super(settingsDelegate); } diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/memory/AnonymousInnerClassMayBeStaticInspectionBase.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/memory/AnonymousInnerClassMayBeStaticInspectionBase.java new file mode 100644 index 000000000000..974646bdcb2a --- /dev/null +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/memory/AnonymousInnerClassMayBeStaticInspectionBase.java @@ -0,0 +1,110 @@ +/* + * Copyright 2000-2014 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.siyeh.ig.memory; + +import com.intellij.psi.*; +import com.intellij.psi.util.PsiTreeUtil; +import com.intellij.psi.util.PsiUtil; +import com.siyeh.InspectionGadgetsBundle; +import com.siyeh.ig.BaseInspection; +import com.siyeh.ig.BaseInspectionVisitor; +import org.jetbrains.annotations.NotNull; + +public class AnonymousInnerClassMayBeStaticInspectionBase extends BaseInspection { + @Override + @NotNull + public String getDisplayName() { + return InspectionGadgetsBundle.message( + "anonymous.inner.may.be.named.static.inner.class.display.name"); + } + + @Override + @NotNull + public String buildErrorString(Object... infos) { + return InspectionGadgetsBundle.message( + "anonymous.inner.may.be.named.static.inner.class.problem.descriptor"); + } + + @Override + public BaseInspectionVisitor buildVisitor() { + return new AnonymousInnerClassMayBeStaticVisitor(); + } + + private static class AnonymousInnerClassMayBeStaticVisitor + extends BaseInspectionVisitor { + + @Override + public void visitAnonymousClass(@NotNull PsiAnonymousClass anonymousClass) { + if (anonymousClass instanceof PsiEnumConstantInitializer) { + return; + } + final PsiMember containingMember = PsiTreeUtil.getParentOfType(anonymousClass, PsiMember.class); + if (containingMember == null || containingMember.hasModifierProperty(PsiModifier.STATIC)) { + return; + } + final PsiJavaCodeReferenceElement reference = anonymousClass.getBaseClassReference(); + if (reference.resolve() == null) { + // don't warn on broken code + return; + } + final PsiClass containingClass = PsiTreeUtil.getParentOfType(anonymousClass, PsiClass.class); + if (containingClass == null) { + return; + } + if (containingClass.getContainingClass() != null && !containingClass.hasModifierProperty(PsiModifier.STATIC)) { + // strictly speaking can be named static inner class but not when part of the current containing class + return; + } + final InnerClassReferenceVisitor visitor = new InnerClassReferenceVisitor(anonymousClass); + anonymousClass.accept(visitor); + if (!visitor.canInnerClassBeStatic()) { + return; + } + if (hasReferenceToLocalClass(anonymousClass)) { + return; + } + registerClassError(anonymousClass); + } + + private static boolean hasReferenceToLocalClass(PsiAnonymousClass anonymousClass) { + final LocalClassReferenceVisitor visitor = new LocalClassReferenceVisitor(); + anonymousClass.accept(visitor); + return visitor.hasReferenceToLocalClass(); + } + + private static class LocalClassReferenceVisitor extends JavaRecursiveElementVisitor { + + private boolean referenceToLocalClass = false; + + @Override + public void visitReferenceElement(PsiJavaCodeReferenceElement reference) { + super.visitReferenceElement(reference); + if (reference.getQualifier() != null) { + return; + } + final PsiElement target = reference.resolve(); + if (!(target instanceof PsiClass) || !PsiUtil.isLocalClass((PsiClass)target)) { + return; + } + referenceToLocalClass = true; + } + + public boolean hasReferenceToLocalClass() { + return referenceToLocalClass; + } + } + } +} diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/performance/InnerClassMayBeStaticInspection.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/memory/InnerClassMayBeStaticInspection.java index 2599327e4d7d..f588b120b8d5 100644 --- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/performance/InnerClassMayBeStaticInspection.java +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/memory/InnerClassMayBeStaticInspection.java @@ -1,5 +1,5 @@ /* - * Copyright 2003-2013 Dave Griffith, Bas Leijdekkers + * Copyright 2003-2014 Dave Griffith, Bas Leijdekkers * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.siyeh.ig.performance; +package com.siyeh.ig.memory; import com.intellij.codeInsight.FileModificationService; import com.intellij.codeInspection.ProblemDescriptor; diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/memory/InnerClassReferenceVisitor.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/memory/InnerClassReferenceVisitor.java new file mode 100644 index 000000000000..6f1f817a7735 --- /dev/null +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/memory/InnerClassReferenceVisitor.java @@ -0,0 +1,126 @@ +/* + * Copyright 2003-2014 Dave Griffith, Bas Leijdekkers + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.siyeh.ig.memory; + +import com.intellij.psi.*; +import com.intellij.psi.util.InheritanceUtil; +import com.intellij.psi.util.PsiTreeUtil; +import com.siyeh.ig.psiutils.ParenthesesUtils; +import org.jetbrains.annotations.NotNull; + +class InnerClassReferenceVisitor extends JavaRecursiveElementVisitor { + + private final PsiClass innerClass; + private boolean referencesStaticallyAccessible = true; + + public InnerClassReferenceVisitor(@NotNull PsiClass innerClass) { + this.innerClass = innerClass; + } + + public boolean canInnerClassBeStatic() { + final PsiClass superClass = innerClass.getSuperClass(); + if (!isClassStaticallyAccessible(superClass)) { + return false; + } + return referencesStaticallyAccessible; + } + + private boolean isClassStaticallyAccessible(PsiClass aClass) { + if (PsiTreeUtil.isAncestor(innerClass, aClass, false) || aClass.hasModifierProperty(PsiModifier.STATIC)) { + return true; + } + final PsiClass containingClass = aClass.getContainingClass(); + return containingClass == null || InheritanceUtil.isInheritorOrSelf(innerClass, containingClass, true); + } + + @Override + public void visitThisExpression(@NotNull PsiThisExpression expression) { + if (!referencesStaticallyAccessible) { + return; + } + super.visitThisExpression(expression); + if (hasContainingClassQualifier(expression)) { + referencesStaticallyAccessible = false; + } + } + + @Override + public void visitSuperExpression(@NotNull PsiSuperExpression expression) { + if (!referencesStaticallyAccessible) { + return; + } + super.visitSuperExpression(expression); + if (hasContainingClassQualifier(expression)) { + referencesStaticallyAccessible = false; + } + } + + private boolean hasContainingClassQualifier(PsiQualifiedExpression expression) { + final PsiJavaCodeReferenceElement qualifier = expression.getQualifier(); + if (qualifier == null) { + return false; + } + return !innerClass.equals(qualifier.resolve()); + } + + @Override + public void visitReferenceExpression(PsiReferenceExpression expression) { + if (!referencesStaticallyAccessible) { + return; + } + super.visitReferenceExpression(expression); + final PsiExpression qualifierExpression = ParenthesesUtils.stripParentheses(expression.getQualifierExpression()); + if (qualifierExpression != null) { + return; + } + final PsiElement target = expression.resolve(); + if (target instanceof PsiLocalVariable || target instanceof PsiParameter) { + return; + } + if (target instanceof PsiMethod || target instanceof PsiField) { + final PsiMember member = (PsiMember)target; + if (member.hasModifierProperty(PsiModifier.STATIC) || PsiTreeUtil.isAncestor(innerClass, member, true)) { + return; + } + if (!member.hasModifierProperty(PsiModifier.PRIVATE)) { + final PsiClass containingClass = member.getContainingClass(); + if (InheritanceUtil.isInheritorOrSelf(innerClass, containingClass, true)) { + return; + } + } + referencesStaticallyAccessible = false; + } + } + + @Override + public void visitNewExpression(PsiNewExpression expression) { + if (!referencesStaticallyAccessible) { + return; + } + super.visitNewExpression(expression); + final PsiJavaCodeReferenceElement classReference = expression.getClassOrAnonymousClassReference(); + if (classReference == null) { + return; + } + final PsiElement target = classReference.resolve(); + if (!(target instanceof PsiClass)) { + return; + } + if (!isClassStaticallyAccessible((PsiClass)target)) { + referencesStaticallyAccessible = false; + } + } +} diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/performance/InnerClassReferenceVisitor.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/performance/InnerClassReferenceVisitor.java deleted file mode 100644 index 45d89b4a4b1d..000000000000 --- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/performance/InnerClassReferenceVisitor.java +++ /dev/null @@ -1,149 +0,0 @@ -/* - * Copyright 2003-2013 Dave Griffith, Bas Leijdekkers - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.siyeh.ig.performance; - -import com.intellij.psi.*; -import com.intellij.psi.util.InheritanceUtil; -import com.intellij.psi.util.PsiTreeUtil; -import com.siyeh.ig.psiutils.ClassUtils; -import org.jetbrains.annotations.NotNull; - -public class InnerClassReferenceVisitor extends JavaRecursiveElementVisitor { - - private final PsiClass innerClass; - private boolean referencesStaticallyAccessible = true; - - public InnerClassReferenceVisitor(PsiClass innerClass) { - this.innerClass = innerClass; - } - - public boolean canInnerClassBeStatic() { - return referencesStaticallyAccessible; - } - - private boolean isClassStaticallyAccessible(PsiClass aClass) { - if (PsiTreeUtil.isAncestor(innerClass, aClass, false)) { - return true; - } - if (aClass.getContainingClass() != null) { - return aClass.hasModifierProperty(PsiModifier.STATIC); - } - if (InheritanceUtil.isInheritorOrSelf(innerClass, aClass, true)) { - return true; - } - PsiClass classScope = aClass; - final PsiClass outerClass = ClassUtils.getContainingClass(innerClass); - 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; - } - - @Override - public void visitThisExpression(@NotNull PsiThisExpression expression) { - if (!referencesStaticallyAccessible) { - return; - } - super.visitThisExpression(expression); - if (hasContainingClassQualifier(expression)) { - referencesStaticallyAccessible = false; - } - } - - @Override - public void visitSuperExpression(@NotNull PsiSuperExpression expression) { - if (!referencesStaticallyAccessible) { - return; - } - super.visitSuperExpression(expression); - if (hasContainingClassQualifier(expression)) { - referencesStaticallyAccessible = false; - } - } - - private boolean hasContainingClassQualifier(PsiQualifiedExpression expression) { - final PsiJavaCodeReferenceElement qualifier = expression.getQualifier(); - if (qualifier == null) { - return false; - } - final PsiElement element = qualifier.resolve(); - if (!(element instanceof PsiClass)) { - return false; - } - final PsiClass aClass = (PsiClass)element; - return !aClass.equals(innerClass); - } - - @Override - public void visitReferenceElement(@NotNull PsiJavaCodeReferenceElement reference) { - if (!referencesStaticallyAccessible) { - return; - } - final PsiElement parent = reference.getParent(); - if (parent instanceof PsiThisExpression || parent instanceof PsiSuperExpression) { - return; - } - super.visitReferenceElement(reference); - - final PsiElement qualifier = reference.getQualifier(); - if (qualifier instanceof PsiSuperExpression) { - return; - } - if (qualifier instanceof PsiReferenceExpression) { - final PsiReferenceExpression referenceExpression = (PsiReferenceExpression)qualifier; - final PsiElement resolvedExpression = referenceExpression.resolve(); - if (!(resolvedExpression instanceof PsiField) && !(resolvedExpression instanceof PsiMethod)) { - return; - } - } - final PsiElement element = reference.resolve(); - if (element instanceof PsiMethod || element instanceof PsiField) { - final PsiMember member = (PsiMember)element; - if (member.hasModifierProperty(PsiModifier.STATIC)) { - return; - } - final PsiClass containingClass = member.getContainingClass(); - if (innerClass.equals(containingClass)) { - return; - } - if (member.hasModifierProperty(PsiModifier.PRIVATE)) { - referencesStaticallyAccessible = false; - return; - } - referencesStaticallyAccessible &= isClassStaticallyAccessible(containingClass); - } - else if (element instanceof PsiLocalVariable || element instanceof PsiParameter) { - final PsiElement containingMethod = PsiTreeUtil.getParentOfType(reference, PsiMethod.class); - final PsiElement referencedMethod = PsiTreeUtil.getParentOfType(element, PsiMethod.class); - if (containingMethod != null && referencedMethod != null && !containingMethod.equals(referencedMethod)) { - referencesStaticallyAccessible = false; - } - } - else if (element instanceof PsiClass) { - final PsiClass aClass = (PsiClass)element; - referencesStaticallyAccessible &= isClassStaticallyAccessible(aClass); - } - } -} diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/ClassUtils.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/ClassUtils.java index 40daa3332896..4656d0c4610a 100644 --- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/ClassUtils.java +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/ClassUtils.java @@ -19,6 +19,7 @@ import com.intellij.psi.*; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.util.TypeConversionUtil; import org.jetbrains.annotations.Contract; +import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.Nullable; import java.util.HashSet; @@ -80,7 +81,7 @@ public class ClassUtils { private ClassUtils() {} @Nullable - public static PsiClass findClass(String fqClassName, PsiElement context) { + public static PsiClass findClass(@NonNls String fqClassName, PsiElement context) { return JavaPsiFacade.getInstance(context.getProject()).findClass(fqClassName, context.getResolveScope()); } diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/ExpressionUtils.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/ExpressionUtils.java index fc6d2580b3e9..242bec97a398 100644 --- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/ExpressionUtils.java +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/ExpressionUtils.java @@ -1,5 +1,5 @@ /* - * Copyright 2005-2013 Bas Leijdekkers + * Copyright 2005-2014 Bas Leijdekkers * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -198,11 +198,8 @@ public class ExpressionUtils { } public static boolean isNullLiteral(@Nullable PsiExpression expression) { - if (!(expression instanceof PsiLiteralExpression)) { - return false; - } - final String text = expression.getText(); - return PsiKeyword.NULL.equals(text); + expression = ParenthesesUtils.stripParentheses(expression); + return expression != null && PsiType.NULL.equals(expression.getType()); } public static boolean isZero(@Nullable PsiExpression expression) { diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/style/CStyleArrayDeclarationInspection.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/style/CStyleArrayDeclarationInspection.java index e4e91685878b..fca66288aaef 100644 --- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/style/CStyleArrayDeclarationInspection.java +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/style/CStyleArrayDeclarationInspection.java @@ -1,5 +1,5 @@ /* - * Copyright 2003-2007 Dave Griffith, Bas Leijdekkers + * Copyright 2003-2014 Dave Griffith, Bas Leijdekkers * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,20 +16,24 @@ package com.siyeh.ig.style; import com.intellij.codeInspection.ProblemDescriptor; +import com.intellij.codeInspection.ui.SingleCheckboxOptionsPanel; import com.intellij.openapi.project.Project; -import com.intellij.psi.PsiElement; -import com.intellij.psi.PsiType; -import com.intellij.psi.PsiTypeElement; -import com.intellij.psi.PsiVariable; -import com.intellij.util.IncorrectOperationException; +import com.intellij.psi.*; +import com.intellij.psi.codeStyle.CodeStyleManager; +import com.intellij.psi.tree.IElementType; import com.siyeh.InspectionGadgetsBundle; import com.siyeh.ig.BaseInspection; import com.siyeh.ig.BaseInspectionVisitor; import com.siyeh.ig.InspectionGadgetsFix; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import javax.swing.*; public class CStyleArrayDeclarationInspection extends BaseInspection { + public boolean ignoreVariables = false; + @Override @NotNull public String getDisplayName() { @@ -40,8 +44,18 @@ public class CStyleArrayDeclarationInspection extends BaseInspection { @Override @NotNull protected String buildErrorString(Object... infos) { - return InspectionGadgetsBundle.message( - "c.style.array.declaration.problem.descriptor"); + final Object info = infos[0]; + if (info instanceof PsiMethod) { + return InspectionGadgetsBundle.message("cstyle.array.method.declaration.problem.descriptor"); + } + final int choice = info instanceof PsiField ? 1 : info instanceof PsiParameter ? 2 : 3; + return InspectionGadgetsBundle.message("cstyle.array.variable.declaration.problem.descriptor", Integer.valueOf(choice)); + } + + @Nullable + @Override + public JComponent createOptionsPanel() { + return new SingleCheckboxOptionsPanel("Ignore C-style declarations in variables", this, "ignoreVariables"); } @Override @@ -65,12 +79,38 @@ public class CStyleArrayDeclarationInspection extends BaseInspection { } @Override - public void doFix(Project project, ProblemDescriptor descriptor) - throws IncorrectOperationException { - final PsiElement nameElement = descriptor.getPsiElement(); - final PsiVariable var = (PsiVariable)nameElement.getParent(); - assert var != null; - var.normalizeDeclaration(); + public void doFix(Project project, ProblemDescriptor descriptor) { + final PsiElement element = descriptor.getPsiElement().getParent(); + if (element instanceof PsiVariable) { + final PsiVariable variable = (PsiVariable)element; + variable.normalizeDeclaration(); + CodeStyleManager.getInstance(project).reformat(variable); + } + else if (element instanceof PsiMethod) { + final PsiMethod method = (PsiMethod)element; + final PsiTypeElement returnTypeElement = method.getReturnTypeElement(); + if (returnTypeElement == null) { + return; + } + final PsiType returnType = method.getReturnType(); + if (returnType == null) { + return; + } + PsiElement child = method.getParameterList(); + while (!(child instanceof PsiCodeBlock)) { + final PsiElement element1 = child; + child = child.getNextSibling(); + if (element1 instanceof PsiJavaToken) { + final PsiJavaToken token = (PsiJavaToken)element1; + final IElementType tokenType = token.getTokenType(); + if (JavaTokenType.LBRACKET.equals(tokenType) || JavaTokenType.RBRACKET.equals(tokenType)) { + token.delete(); + } + } + } + final PsiTypeElement typeElement = JavaPsiFacade.getElementFactory(project).createTypeElement(returnType); + returnTypeElement.replace(typeElement); + } } } @@ -79,17 +119,19 @@ public class CStyleArrayDeclarationInspection extends BaseInspection { return new CStyleArrayDeclarationVisitor(); } - private static class CStyleArrayDeclarationVisitor - extends BaseInspectionVisitor { + private class CStyleArrayDeclarationVisitor extends BaseInspectionVisitor { @Override - public void visitVariable(@NotNull PsiVariable var) { - super.visitVariable(var); - final PsiType declaredType = var.getType(); + public void visitVariable(@NotNull PsiVariable variable) { + super.visitVariable(variable); + if (ignoreVariables) { + return; + } + final PsiType declaredType = variable.getType(); if (declaredType.getArrayDimensions() == 0) { return; } - final PsiTypeElement typeElement = var.getTypeElement(); + final PsiTypeElement typeElement = variable.getTypeElement(); if (typeElement == null) { return; // Could be true for enum constants. } @@ -97,7 +139,25 @@ public class CStyleArrayDeclarationInspection extends BaseInspection { if (elementType.equals(declaredType)) { return; } - registerVariableError(var); + registerVariableError(variable, variable); + } + + @Override + public void visitMethod(PsiMethod method) { + super.visitMethod(method); + final PsiType returnType = method.getReturnType(); + if (returnType == null || returnType.getArrayDimensions() == 0) { + return; + } + final PsiTypeElement typeElement = method.getReturnTypeElement(); + if (typeElement == null) { + return; + } + final PsiType type = typeElement.getType(); + if (type.equals(returnType)) { + return; + } + registerMethodError(method, method); } } }
\ No newline at end of file diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/style/NestedMethodCallInspectionBase.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/style/NestedMethodCallInspectionBase.java index 484c1f8fefe0..57659d05923a 100644 --- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/style/NestedMethodCallInspectionBase.java +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/style/NestedMethodCallInspectionBase.java @@ -16,6 +16,7 @@ package com.siyeh.ig.style; import com.intellij.psi.*; +import com.intellij.psi.util.PropertyUtil; import com.intellij.psi.util.PsiTreeUtil; import com.siyeh.InspectionGadgetsBundle; import com.siyeh.ig.BaseInspection; @@ -29,6 +30,12 @@ public class NestedMethodCallInspectionBase extends BaseInspection { */ public boolean m_ignoreFieldInitializations = true; + @SuppressWarnings("PublicField") + public boolean ignoreStaticMethods = false; + + @SuppressWarnings("PublicField") + public boolean ignoreGetterCalls = false; + @Override @NotNull public String getDisplayName() { @@ -82,6 +89,18 @@ public class NestedMethodCallInspectionBase extends BaseInspection { return; } } + final PsiMethod method = expression.resolveMethod(); + if (method == null) { + return; + } + if (ignoreStaticMethods || ignoreGetterCalls) { + if (ignoreStaticMethods && method.hasModifierProperty(PsiModifier.STATIC)) { + return; + } + if (ignoreGetterCalls && PropertyUtil.isSimpleGetter(method)) { + return; + } + } registerMethodCallError(expression); } } diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/threading/DoubleCheckedLockingInspection.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/threading/DoubleCheckedLockingInspection.java index 0036f4a41f99..d9f5242d3ab6 100644 --- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/threading/DoubleCheckedLockingInspection.java +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/threading/DoubleCheckedLockingInspection.java @@ -1,5 +1,5 @@ /* - * Copyright 2003-2010 Dave Griffith, Bas Leijdekkers + * Copyright 2003-2014 Dave Griffith, Bas Leijdekkers * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,7 +20,6 @@ import com.intellij.codeInspection.ui.SingleCheckboxOptionsPanel; import com.intellij.openapi.project.Project; import com.intellij.psi.*; import com.intellij.psi.tree.IElementType; -import com.intellij.util.IncorrectOperationException; import com.siyeh.InspectionGadgetsBundle; import com.siyeh.ig.BaseInspection; import com.siyeh.ig.BaseInspectionVisitor; @@ -74,17 +73,16 @@ public class DoubleCheckedLockingInspection extends BaseInspection { private static class DoubleCheckedLockingFix extends InspectionGadgetsFix { - private final PsiField field; + private final String myFieldName; private DoubleCheckedLockingFix(PsiField field) { - this.field = field; + myFieldName = field.getName(); } @Override @NotNull public String getName() { - return InspectionGadgetsBundle.message( - "double.checked.locking.quickfix", field.getName()); + return InspectionGadgetsBundle.message("double.checked.locking.quickfix", myFieldName); } @NotNull @@ -94,8 +92,21 @@ public class DoubleCheckedLockingInspection extends BaseInspection { } @Override - protected void doFix(Project project, ProblemDescriptor descriptor) - throws IncorrectOperationException { + protected void doFix(Project project, ProblemDescriptor descriptor) { + final PsiElement element = descriptor.getPsiElement(); + final PsiElement parent = element.getParent(); + if (!(parent instanceof PsiIfStatement)) { + return; + } + final PsiIfStatement ifStatement = (PsiIfStatement)parent; + final PsiExpression condition = ifStatement.getCondition(); + if (condition == null) { + return; + } + final PsiField field = findCheckedField(condition); + if (field == null) { + return; + } final PsiModifierList modifierList = field.getModifierList(); if (modifierList == null) { return; @@ -104,13 +115,55 @@ public class DoubleCheckedLockingInspection extends BaseInspection { } } + @Nullable + private static PsiField findCheckedField(PsiExpression expression) { + if (expression instanceof PsiReferenceExpression) { + final PsiReferenceExpression referenceExpression = + (PsiReferenceExpression)expression; + final PsiElement target = referenceExpression.resolve(); + if (!(target instanceof PsiField)) { + return null; + } + return (PsiField)target; + } + else if (expression instanceof PsiBinaryExpression) { + final PsiBinaryExpression binaryExpression = + (PsiBinaryExpression)expression; + final IElementType tokenType = + binaryExpression.getOperationTokenType(); + if (!JavaTokenType.EQEQ.equals(tokenType) + && !JavaTokenType.NE.equals(tokenType)) { + return null; + } + final PsiExpression lhs = binaryExpression.getLOperand(); + final PsiExpression rhs = binaryExpression.getROperand(); + final PsiField field = findCheckedField(lhs); + if (field != null) { + return field; + } + return findCheckedField(rhs); + } + else if (expression instanceof PsiPrefixExpression) { + final PsiPrefixExpression prefixExpression = + (PsiPrefixExpression)expression; + final IElementType tokenType = + prefixExpression.getOperationTokenType(); + if (!JavaTokenType.EXCL.equals(tokenType)) { + return null; + } + return findCheckedField(prefixExpression.getOperand()); + } + else { + return null; + } + } + @Override public BaseInspectionVisitor buildVisitor() { return new DoubleCheckedLockingVisitor(); } - private class DoubleCheckedLockingVisitor - extends BaseInspectionVisitor { + private class DoubleCheckedLockingVisitor extends BaseInspectionVisitor { @Override public void visitIfStatement( @@ -161,48 +214,5 @@ public class DoubleCheckedLockingInspection extends BaseInspection { } registerStatementError(statement, field); } - - @Nullable - private PsiField findCheckedField(PsiExpression expression) { - if (expression instanceof PsiReferenceExpression) { - final PsiReferenceExpression referenceExpression = - (PsiReferenceExpression)expression; - final PsiElement target = referenceExpression.resolve(); - if (!(target instanceof PsiField)) { - return null; - } - return (PsiField)target; - } - else if (expression instanceof PsiBinaryExpression) { - final PsiBinaryExpression binaryExpression = - (PsiBinaryExpression)expression; - final IElementType tokenType = - binaryExpression.getOperationTokenType(); - if (!JavaTokenType.EQEQ.equals(tokenType) - && !JavaTokenType.NE.equals(tokenType)) { - return null; - } - final PsiExpression lhs = binaryExpression.getLOperand(); - final PsiExpression rhs = binaryExpression.getROperand(); - final PsiField field = findCheckedField(lhs); - if (field != null) { - return field; - } - return findCheckedField(rhs); - } - else if (expression instanceof PsiPrefixExpression) { - final PsiPrefixExpression prefixExpression = - (PsiPrefixExpression)expression; - final IElementType tokenType = - prefixExpression.getOperationTokenType(); - if (!JavaTokenType.EXCL.equals(tokenType)) { - return null; - } - return findCheckedField(prefixExpression.getOperand()); - } - else { - return null; - } - } } }
\ No newline at end of file |