diff options
Diffstat (limited to 'plugins/InspectionGadgets/InspectionGadgetsAnalysis')
11 files changed, 381 insertions, 107 deletions
diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/META-INF/InspectionGadgets.xml b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/META-INF/InspectionGadgets.xml index dddb6e1d3988..4becc9723a65 100644 --- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/META-INF/InspectionGadgets.xml +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/META-INF/InspectionGadgets.xml @@ -2489,6 +2489,9 @@ <localInspection language="JAVA" suppressId="LockAcquiredButNotSafelyReleased" shortName="SafeLock" bundle="com.siyeh.InspectionGadgetsBundle" key="safe.lock.display.name" groupBundle="messages.InspectionsBundle" groupKey="group.names.threading.issues" enabledByDefault="false" level="WARNING" implementationClass="com.siyeh.ig.threading.SafeLockInspection"/> + <localInspection language="JAVA" suppressId="SharedThreadLocalRandom" shortName="SharedThreadLocalRandom" bundle="com.siyeh.InspectionGadgetsBundle" + key="shared.thread.local.random.display.name" groupBundle="messages.InspectionsBundle" groupKey="group.names.threading.issues" + enabledByDefault="false" level="WARNING" implementationClass="com.siyeh.ig.threading.SharedThreadLocalRandomInspection"/> <localInspection language="JAVA" shortName="SignalWithoutCorrespondingAwait" bundle="com.siyeh.InspectionGadgetsBundle" key="signal.without.corresponding.await.display.name" groupBundle="messages.InspectionsBundle" groupKey="group.names.threading.issues" enabledByDefault="false" level="WARNING" @@ -2640,6 +2643,10 @@ bundle="com.siyeh.InspectionGadgetsBundle" key="parameter.hides.member.variable.display.name" groupBundle="messages.InspectionsBundle" groupKey="group.names.visibility.issues" enabledByDefault="false" level="WARNING" implementationClass="com.siyeh.ig.visibility.ParameterHidingMemberVariableInspection"/> + <localInspection language="JAVA" suppressId="LambdaParameterHidesMemberVariable" shortName="LambdaParameterHidingMemberVariable" + bundle="com.siyeh.InspectionGadgetsBundle" key="lambda.parameter.hides.member.variable.display.name" + groupBundle="messages.InspectionsBundle" groupKey="group.names.visibility.issues" enabledByDefault="false" + level="WARNING" implementationClass="com.siyeh.ig.visibility.LambdaParameterHidingMemberVariableInspection"/> </extensions> <application-components> diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/InspectionGadgetsBundle.properties b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/InspectionGadgetsBundle.properties index 7f61b374c9a9..013cf2344b2a 100644 --- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/InspectionGadgetsBundle.properties +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/InspectionGadgetsBundle.properties @@ -1157,7 +1157,7 @@ local.variable.naming.convention.problem.descriptor.long=Local variable name <co local.variable.naming.convention.problem.descriptor.regex.mismatch=Local variable name <code>#ref</code> doesn''t match regex ''{0}'' #loc local.variable.naming.convention.ignore.option=Ignore for-loop parameters local.variable.naming.convention.ignore.catch.option=Ignore 'catch' block parameters -method.names.differ.only.by.case.problem.descriptor=Method names <code>#ref</code> and ''{0}'' differ only by case #loc +method.names.differ.only.by.case.problem.descriptor=Method name <code>#ref</code> and method name ''{0}'' differ only by case #loc parameter.name.differs.from.overridden.parameter.ignore.character.option=Ignore if overridden parameter contains only one character parameter.name.differs.from.overridden.parameter.ignore.library.option=Ignore if overridden parameter is from a library parameter.name.differs.from.overridden.parameter.problem.descriptor=Parameter name <code>#ref</code> is different from parameter ''{0}'' overridden #loc @@ -2066,3 +2066,8 @@ implicit.default.charset.usage.constructor.problem.descriptor=<code>new #ref()</ interface.may.be.annotated.functional.display.name=Interface may be annotated @FunctionalInterface interface.may.be.annotated.functional.problem.descriptor=Interface <code>#ref</code> may be annotated with @FunctionalInterface only.report.public.methods.option=Only report 'public' methods +lambda.parameter.hides.member.variable.display.name=Lambda parameter hides field +lambda.parameter.hides.member.variable.problem.descriptor=Lambda parameter <code>#ref</code> hides field in class ''{0}'' #loc +shared.thread.local.random.display.name='ThreadLocalRandom' instance might be shared +shared.thread.local.random.problem.descriptor='ThreadLocalRandom' instance might be shared between threads + diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/fixes/ExtractParameterAsLocalVariableFix.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/fixes/ExtractParameterAsLocalVariableFix.java index 9ef4c14e4a84..31a7987f40f1 100644 --- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/fixes/ExtractParameterAsLocalVariableFix.java +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/fixes/ExtractParameterAsLocalVariableFix.java @@ -1,5 +1,5 @@ /* - * Copyright 2008-2011 Bas Leijdekkers + * Copyright 2008-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. @@ -23,7 +23,6 @@ import com.intellij.psi.codeStyle.JavaCodeStyleManager; import com.intellij.psi.search.SearchScope; import com.intellij.psi.search.searches.ReferencesSearch; import com.intellij.psi.tree.IElementType; -import com.intellij.util.IncorrectOperationException; import com.intellij.util.Query; import com.siyeh.InspectionGadgetsBundle; import com.siyeh.ig.InspectionGadgetsFix; @@ -46,8 +45,7 @@ public class ExtractParameterAsLocalVariableFix } @Override - public void doFix(Project project, ProblemDescriptor descriptor) - throws IncorrectOperationException { + public void doFix(Project project, ProblemDescriptor descriptor) { final PsiReferenceExpression parameterReference = (PsiReferenceExpression)descriptor.getPsiElement(); final PsiElement target = parameterReference.resolve(); @@ -79,6 +77,10 @@ public class ExtractParameterAsLocalVariableFix body = forBody; } } + else if (declarationScope instanceof PsiLambdaExpression) { + final PsiLambdaExpression lambdaExpression = (PsiLambdaExpression)declarationScope; + body = lambdaExpression.getBody(); + } else { return; } @@ -125,15 +127,16 @@ public class ExtractParameterAsLocalVariableFix replaceVariableName(child, firstReference, variableName, parameterName, buffer); } + if (body instanceof PsiExpression) { // expression lambda + buffer.insert(0, "return "); + buffer.append(';'); + } final String replacementText; if (newDeclarationCreated) { replacementText = "{" + buffer + '}'; } else { - final PsiType type = parameterReference.getType(); - if (type == null) { - return; - } + final PsiType type = parameter.getType(); final String className = type.getCanonicalText(); replacementText = '{' + className + ' ' + variableName + " = " + parameterName + ';' + buffer + '}'; @@ -141,8 +144,7 @@ public class ExtractParameterAsLocalVariableFix final PsiElementFactory elementFactory = JavaPsiFacade.getInstance(project).getElementFactory(); final PsiCodeBlock block = - elementFactory.createCodeBlockFromText( - replacementText, null); + elementFactory.createCodeBlockFromText(replacementText, declarationScope); body.replace(block); codeStyleManager.reformat(declarationScope); } diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/ControlFlowUtils.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/ControlFlowUtils.java index 278c07e980c0..3741d260dae6 100644 --- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/ControlFlowUtils.java +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/ControlFlowUtils.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. @@ -35,7 +35,7 @@ public class ControlFlowUtils { } else if (statement instanceof PsiExpressionListStatement || statement instanceof PsiEmptyStatement || statement instanceof PsiAssertStatement || statement instanceof PsiDeclarationStatement || - statement instanceof PsiSwitchLabelStatement) { + statement instanceof PsiSwitchLabelStatement || statement instanceof PsiForeachStatement) { return true; } else if (statement instanceof PsiExpressionStatement) { @@ -63,9 +63,6 @@ public class ControlFlowUtils { else if (statement instanceof PsiForStatement) { return forStatementMayCompleteNormally((PsiForStatement)statement); } - else if (statement instanceof PsiForeachStatement) { - return foreachStatementMayCompleteNormally((PsiForeachStatement)statement); - } else if (statement instanceof PsiWhileStatement) { return whileStatementMayCompleteNormally((PsiWhileStatement)statement); } @@ -130,10 +127,6 @@ public class ControlFlowUtils { return Boolean.TRUE != value; } - private static boolean foreachStatementMayCompleteNormally(@NotNull PsiForeachStatement loopStatement) { - return true; - } - private static boolean switchStatementMayCompleteNormally(@NotNull PsiSwitchStatement switchStatement) { if (statementIsBreakTarget(switchStatement)) { return true; @@ -524,7 +517,7 @@ public class ControlFlowUtils { } } - private static class SystemExitFinder extends JavaRecursiveElementVisitor { + private static class SystemExitFinder extends JavaRecursiveElementWalkingVisitor { private boolean m_found = false; @@ -564,7 +557,7 @@ public class ControlFlowUtils { } } - private static class ReturnFinder extends JavaRecursiveElementVisitor { + private static class ReturnFinder extends JavaRecursiveElementWalkingVisitor { private boolean m_found = false; @@ -587,7 +580,7 @@ public class ControlFlowUtils { } } - private static class BreakFinder extends JavaRecursiveElementVisitor { + private static class BreakFinder extends JavaRecursiveElementWalkingVisitor { private boolean m_found = false; private final PsiStatement m_target; @@ -637,7 +630,7 @@ public class ControlFlowUtils { } } - private static class ContinueFinder extends JavaRecursiveElementVisitor { + private static class ContinueFinder extends JavaRecursiveElementWalkingVisitor { private boolean m_found = false; private final PsiStatement m_target; @@ -687,7 +680,7 @@ public class ControlFlowUtils { } } - private static class MethodCallFinder extends JavaRecursiveElementVisitor { + private static class MethodCallFinder extends JavaRecursiveElementWalkingVisitor { private final String containingClassName; private final PsiType returnType; @@ -728,7 +721,7 @@ public class ControlFlowUtils { } } - private static class ContinueToAncestorFinder extends JavaRecursiveElementVisitor { + private static class ContinueToAncestorFinder extends JavaRecursiveElementWalkingVisitor { private final PsiStatement statement; private boolean found = false; diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/ExpectedTypeUtils.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/ExpectedTypeUtils.java index c14da9f55373..ad5ecc2351f3 100644 --- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/ExpectedTypeUtils.java +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/ExpectedTypeUtils.java @@ -153,86 +153,59 @@ public class ExpectedTypeUtils { } @Override - public void visitBinaryExpression(@NotNull PsiBinaryExpression binaryExpression) { - final PsiExpression rhs = binaryExpression.getROperand(); - if (rhs == null) { - expectedType = null; - return; - } - final PsiExpression lhs = binaryExpression.getLOperand(); - PsiType lhsType = lhs.getType(); - if (lhsType == null) { - expectedType = null; - return; - } - PsiType rhsType = rhs.getType(); - if (rhsType == null) { - expectedType = null; - return; + public void visitPolyadicExpression(@NotNull PsiPolyadicExpression polyadicExpression) { + final PsiExpression[] operands = polyadicExpression.getOperands(); + for (PsiExpression operand : operands) { + if (operand == null || operand.getType() == null) { + expectedType = null; + return; + } } - final IElementType tokenType = binaryExpression.getOperationTokenType(); - final PsiType type = binaryExpression.getType(); + final IElementType tokenType = polyadicExpression.getOperationTokenType(); + final PsiType type = polyadicExpression.getType(); + final PsiType wrappedExpressionType = wrappedExpression.getType(); if (TypeUtils.isJavaLangString(type) || isArithmeticOperation(tokenType) || isBooleanOperation(tokenType)) { expectedType = type; } else if (isShiftOperation(tokenType)) { - if (lhs == wrappedExpression) { - expectedType = unaryNumericPromotion(lhsType); - } - else { - expectedType = unaryNumericPromotion(rhsType); - } + expectedType = unaryNumericPromotion(wrappedExpressionType); } - else if (ComparisonUtils.isEqualityComparison(binaryExpression)) { + else if (ComparisonUtils.isEqualityComparison(polyadicExpression)) { // JLS 15.21.1 Numerical Equality Operators == and != - final PsiType wrappedExpressionType = wrappedExpression.getType(); if (TypeConversionUtil.isPrimitiveAndNotNull(wrappedExpressionType)) { expectedType = wrappedExpressionType; - return; } - if (lhs == wrappedExpression) { - if (TypeConversionUtil.isPrimitiveAndNotNull(rhsType)) { + else if (operands.length > 2) { + expectedType = PsiPrimitiveType.getUnboxedType(wrappedExpressionType); + } + else if (operands[0] == wrappedExpression) { + if (TypeConversionUtil.isPrimitiveAndNotNull(operands[1].getType())) { expectedType = PsiPrimitiveType.getUnboxedType(wrappedExpressionType); - return; } - expectedType = TypeUtils.getObjectType(wrappedExpression); + else { + expectedType = TypeUtils.getObjectType(wrappedExpression); + } } else { - if (TypeConversionUtil.isPrimitiveAndNotNull(lhsType)) { + if (TypeConversionUtil.isPrimitiveAndNotNull(operands[0].getType())) { expectedType = PsiPrimitiveType.getUnboxedType(wrappedExpressionType); - return; - } - expectedType = TypeUtils.getObjectType(wrappedExpression); + } + else { + expectedType = TypeUtils.getObjectType(wrappedExpression); + } } } else if (ComparisonUtils.isComparisonOperation(tokenType)) { - if (lhs == wrappedExpression && !TypeConversionUtil.isPrimitiveAndNotNull(lhsType)) { - lhsType = PsiPrimitiveType.getUnboxedType(lhsType); - if (lhsType == null) { - expectedType = null; - return; - } + if (operands.length != 2) { + expectedType = null; + return; } - if (rhs == wrappedExpression && !TypeConversionUtil.isPrimitiveAndNotNull(rhsType)) { - rhsType = PsiPrimitiveType.getUnboxedType(rhsType); - if (rhsType == null) { - expectedType = null; + else if (!TypeConversionUtil.isPrimitiveAndNotNull(wrappedExpressionType)) { + if (PsiPrimitiveType.getUnboxedType(wrappedExpressionType) == null) { return; } } - // JLS 5.6.2 Binary Numeric Promotion - if (PsiType.DOUBLE.equals(lhsType) || PsiType.DOUBLE.equals(rhsType)) { - expectedType = PsiType.DOUBLE; - } - else if (PsiType.FLOAT.equals(lhsType) || PsiType.FLOAT.equals(rhsType)) { - expectedType = PsiType.FLOAT; - } - else if (PsiType.LONG.equals(lhsType) || PsiType.LONG.equals(rhsType)) { - expectedType = PsiType.LONG; - } - else { - expectedType = PsiType.INT; - } + expectedType = TypeConversionUtil.binaryNumericPromotion(operands[0].getType(), operands[1].getType()); } else { expectedType = null; diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/ImportUtils.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/ImportUtils.java index 6301e83eb0fd..8d52a8619dc5 100644 --- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/ImportUtils.java +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/ImportUtils.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. @@ -19,8 +19,8 @@ import com.intellij.openapi.project.Project; import com.intellij.psi.*; import com.intellij.psi.codeStyle.JavaCodeStyleSettingsFacade; import com.intellij.psi.search.GlobalSearchScope; -import com.intellij.psi.util.InheritanceUtil; import com.intellij.psi.util.*; +import com.intellij.psi.util.InheritanceUtil; import com.siyeh.HardcodedMethodConstants; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; @@ -247,20 +247,22 @@ public class ImportUtils { continue; } final PsiElement element = importReference.resolve(); - if (element == null || !(element instanceof PsiPackage)) { + if (!(element instanceof PsiPackage)) { continue; } final PsiPackage aPackage = (PsiPackage)element; - if (!strict) { - return aPackage.containsClassNamed(shortName); + if (!strict && aPackage.containsClassNamed(shortName)) { + return true; } - final PsiClass[] classes = aPackage.findClassByShortName(shortName, file.getResolveScope()); - for (final PsiClass aClass : classes) { - final String qualifiedClassName = aClass.getQualifiedName(); - if (qualifiedClassName == null || fqName.equals(qualifiedClassName)) { - continue; + else { + final PsiClass[] classes = aPackage.findClassByShortName(shortName, file.getResolveScope()); + for (final PsiClass aClass : classes) { + final String qualifiedClassName = aClass.getQualifiedName(); + if (qualifiedClassName == null || fqName.equals(qualifiedClassName)) { + continue; + } + return containsConflictingReference(file, qualifiedClassName); } - return containsConflictingReference(file, qualifiedClassName); } } return hasJavaLangImportConflict(fqName, file); diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/SideEffectChecker.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/SideEffectChecker.java index af04c02d6e79..5063ef7c2ea7 100644 --- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/SideEffectChecker.java +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/SideEffectChecker.java @@ -1,5 +1,5 @@ /* - * Copyright 2003-2006 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. @@ -31,7 +31,7 @@ public class SideEffectChecker { return visitor.mayHaveSideEffects(); } - private static class SideEffectsVisitor extends JavaRecursiveElementVisitor { + private static class SideEffectsVisitor extends JavaRecursiveElementWalkingVisitor { private boolean mayHaveSideEffects = false; diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/VariableAccessUtils.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/VariableAccessUtils.java index e097d58f8301..b8e7b7c183d8 100644 --- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/VariableAccessUtils.java +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/VariableAccessUtils.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. @@ -20,6 +20,9 @@ import com.intellij.psi.tree.IElementType; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import java.util.Collection; +import java.util.Collections; +import java.util.HashSet; import java.util.Set; public class VariableAccessUtils { @@ -446,4 +449,43 @@ public class VariableAccessUtils { } return child; } + + public static Set<PsiVariable> collectUsedVariables(PsiElement context) { + if (context == null) { + return Collections.emptySet(); + } + final VariableCollectingVisitor visitor = new VariableCollectingVisitor(); + context.accept(visitor); + return visitor.getUsedVariables(); + } + + public static boolean isAnyVariableAssigned(@NotNull Collection<PsiVariable> variables, @Nullable PsiElement context) { + if (context == null) { + return false; + } + final VariableAssignedVisitor visitor = new VariableAssignedVisitor(variables, true); + context.accept(visitor); + return visitor.isAssigned(); + } + + private static class VariableCollectingVisitor extends JavaRecursiveElementVisitor { + + private final Set<PsiVariable> usedVariables = new HashSet(); + + @Override + public void visitReferenceExpression( + PsiReferenceExpression expression) { + super.visitReferenceExpression(expression); + final PsiElement target = expression.resolve(); + if (!(target instanceof PsiVariable)) { + return; + } + final PsiVariable variable = (PsiVariable)target; + usedVariables.add(variable); + } + + public Set<PsiVariable> getUsedVariables() { + return usedVariables; + } + } }
\ No newline at end of file diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/VariableAssignedVisitor.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/VariableAssignedVisitor.java index 0a22ef3fde97..279400f3a653 100644 --- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/VariableAssignedVisitor.java +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/VariableAssignedVisitor.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. @@ -20,16 +20,25 @@ import com.intellij.psi.tree.IElementType; import com.intellij.psi.util.TypeConversionUtil; import org.jetbrains.annotations.NotNull; +import java.util.Collection; +import java.util.Collections; + public class VariableAssignedVisitor extends JavaRecursiveElementWalkingVisitor { - @NotNull private final PsiVariable variable; + @NotNull private final Collection<PsiVariable> variables; private final boolean recurseIntoClasses; private final boolean checkUnaryExpressions; private boolean assigned = false; private PsiElement excludedElement = null; + public VariableAssignedVisitor(@NotNull Collection<PsiVariable> variables, boolean recurseIntoClasses) { + this.variables = variables; + checkUnaryExpressions = true; + this.recurseIntoClasses = recurseIntoClasses; + } + public VariableAssignedVisitor(@NotNull PsiVariable variable, boolean recurseIntoClasses) { - this.variable = variable; + variables = Collections.singleton(variable); final PsiType type = variable.getType(); checkUnaryExpressions = TypeConversionUtil.isNumericType(type); this.recurseIntoClasses = recurseIntoClasses; @@ -58,8 +67,11 @@ public class VariableAssignedVisitor extends JavaRecursiveElementWalkingVisitor } super.visitAssignmentExpression(assignment); final PsiExpression lhs = assignment.getLExpression(); - if (VariableAccessUtils.evaluatesToVariable(lhs, variable)) { - assigned = true; + for (PsiVariable variable : variables) { + if (VariableAccessUtils.evaluatesToVariable(lhs, variable)) { + assigned = true; + break; + } } } @@ -85,8 +97,11 @@ public class VariableAssignedVisitor extends JavaRecursiveElementWalkingVisitor return; } final PsiExpression operand = prefixExpression.getOperand(); - if (VariableAccessUtils.evaluatesToVariable(operand, variable)) { - assigned = true; + for (PsiVariable variable : variables) { + if (VariableAccessUtils.evaluatesToVariable(operand, variable)) { + assigned = true; + break; + } } } @@ -104,8 +119,11 @@ public class VariableAssignedVisitor extends JavaRecursiveElementWalkingVisitor return; } final PsiExpression operand = postfixExpression.getOperand(); - if (VariableAccessUtils.evaluatesToVariable(operand, variable)) { - assigned = true; + for (PsiVariable variable : variables) { + if (VariableAccessUtils.evaluatesToVariable(operand, variable)) { + assigned = true; + break; + } } } diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/threading/SharedThreadLocalRandomInspection.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/threading/SharedThreadLocalRandomInspection.java new file mode 100644 index 000000000000..97adc033c5b1 --- /dev/null +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/threading/SharedThreadLocalRandomInspection.java @@ -0,0 +1,122 @@ +/* + * 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.threading; + +import com.intellij.psi.*; +import com.intellij.psi.util.InheritanceUtil; +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.ParenthesesUtils; +import com.siyeh.ig.psiutils.VariableAccessUtils; +import org.jetbrains.annotations.Nls; +import org.jetbrains.annotations.NonNls; +import org.jetbrains.annotations.NotNull; + +/** + * @author Bas Leijdekkers + */ +public class SharedThreadLocalRandomInspection extends BaseInspection { + @Nls + @NotNull + @Override + public String getDisplayName() { + return InspectionGadgetsBundle.message("shared.thread.local.random.display.name"); + } + + @NotNull + @Override + protected String buildErrorString(Object... infos) { + return InspectionGadgetsBundle.message("shared.thread.local.random.problem.descriptor"); + } + + @Override + public BaseInspectionVisitor buildVisitor() { + return new SharedThreadLocalRandomVisitor(); + } + + private static class SharedThreadLocalRandomVisitor extends BaseInspectionVisitor { + + @Override + public void visitMethodCallExpression(PsiMethodCallExpression expression) { + super.visitMethodCallExpression(expression); + final PsiReferenceExpression methodExpression = expression.getMethodExpression(); + @NonNls final String name = methodExpression.getReferenceName(); + if (!"current".equals(name)) { + return; + } + final PsiMethod method = expression.resolveMethod(); + if (method == null) { + return; + } + final PsiClass aClass = method.getContainingClass(); + if (!InheritanceUtil.isInheritor(aClass, "java.util.concurrent.ThreadLocalRandom")) { + return; + } + if (isArgumentToMethodCall(expression)) { + registerMethodCallError(expression); + } + else { + final PsiVariable variable = assignedToVariable(expression); + if (variable instanceof PsiField) { + registerMethodCallError(expression); + } + else if (variable instanceof PsiLocalVariable) { + final PsiCodeBlock context = PsiTreeUtil.getParentOfType(variable, PsiCodeBlock.class); + if (VariableAccessUtils.variableIsPassedAsMethodArgument(variable, context) || + VariableAccessUtils.variableIsUsedInInnerClass(variable, context)) { + registerMethodCallError(expression); + } + } + } + } + + private static boolean isArgumentToMethodCall(PsiExpression expression) { + final PsiElement parent = ParenthesesUtils.getParentSkipParentheses(expression); + if (!(parent instanceof PsiExpressionList)) { + return false; + } + final PsiElement grandParent = parent.getParent(); + return grandParent instanceof PsiMethodCallExpression; + } + + private static PsiVariable assignedToVariable(PsiMethodCallExpression expression) { + final PsiElement parent = PsiTreeUtil.skipParentsOfType(expression, PsiParenthesizedExpression.class); + if (parent instanceof PsiVariable) { + return (PsiVariable)parent; + } + if (!(parent instanceof PsiAssignmentExpression)) { + return null; + } + final PsiAssignmentExpression assignmentExpression = (PsiAssignmentExpression)parent; + final PsiExpression rhs = assignmentExpression.getRExpression(); + if (!PsiTreeUtil.isAncestor(rhs, expression, false)) { + return null; + } + final PsiExpression lhs = ParenthesesUtils.stripParentheses(assignmentExpression.getLExpression()); + if (!(lhs instanceof PsiReferenceExpression)) { + return null; + } + final PsiReferenceExpression referenceExpression = (PsiReferenceExpression)lhs; + final PsiElement target = referenceExpression.resolve(); + if (!(target instanceof PsiVariable)) { + return null; + } + return (PsiVariable)target; + } + } +} diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/visibility/LambdaParameterHidingMemberVariableInspectionBase.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/visibility/LambdaParameterHidingMemberVariableInspectionBase.java new file mode 100644 index 000000000000..5b245eccc0a0 --- /dev/null +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/visibility/LambdaParameterHidingMemberVariableInspectionBase.java @@ -0,0 +1,110 @@ +/* + * 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.visibility; + +import com.intellij.codeInspection.ui.MultipleCheckboxOptionsPanel; +import com.intellij.psi.*; +import com.siyeh.InspectionGadgetsBundle; +import com.siyeh.ig.BaseInspection; +import com.siyeh.ig.BaseInspectionVisitor; +import com.siyeh.ig.psiutils.ClassUtils; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import javax.swing.*; + +public class LambdaParameterHidingMemberVariableInspectionBase extends BaseInspection { + + @SuppressWarnings("PublicField") + public boolean m_ignoreInvisibleFields = true; + + @Override + @NotNull + public String getID() { + return "LambdaParameterHidesMemberVariable"; + } + + @Override + @NotNull + public String getDisplayName() { + return InspectionGadgetsBundle.message("lambda.parameter.hides.member.variable.display.name"); + } + + @Override + protected boolean buildQuickFixesOnlyForOnTheFlyErrors() { + return true; + } + + @Override + @NotNull + public String buildErrorString(Object... infos) { + final PsiClass aClass = (PsiClass)infos[0]; + return InspectionGadgetsBundle.message("lambda.parameter.hides.member.variable.problem.descriptor", aClass.getName()); + } + + @Override + public JComponent createOptionsPanel() { + final MultipleCheckboxOptionsPanel optionsPanel = new MultipleCheckboxOptionsPanel(this); + optionsPanel.addCheckbox(InspectionGadgetsBundle.message("parameter.hides.member.variable.ignore.superclass.option"), + "m_ignoreInvisibleFields"); + return optionsPanel; + } + + @Override + public BaseInspectionVisitor buildVisitor() { + return new LambdaParameterHidingMemberVariableVisitor(); + } + + private class LambdaParameterHidingMemberVariableVisitor extends BaseInspectionVisitor { + + @Override + public void visitParameter(@NotNull PsiParameter variable) { + super.visitParameter(variable); + final PsiElement declarationScope = variable.getDeclarationScope(); + if (!(declarationScope instanceof PsiLambdaExpression)) { + return; + } + final PsiClass aClass = checkFieldName(variable); + if (aClass == null) { + return; + } + registerVariableError(variable, aClass); + } + + @Nullable + private PsiClass checkFieldName(PsiVariable variable) { + final String variableName = variable.getName(); + if (variableName == null) { + return null; + } + PsiClass aClass = ClassUtils.getContainingClass(variable); + while (aClass != null) { + final PsiField[] fields = aClass.getAllFields(); + for (PsiField field : fields) { + final String fieldName = field.getName(); + if (!variableName.equals(fieldName)) { + continue; + } + if (!m_ignoreInvisibleFields || ClassUtils.isFieldVisible(field, aClass)) { + return aClass; + } + } + aClass = ClassUtils.getContainingClass(aClass); + } + return null; + } + } +}
\ No newline at end of file |