Merge remote-tracking branch 'origin/master'

This commit is contained in:
Yann Cébron
2012-09-12 12:00:59 +02:00
24 changed files with 301 additions and 120 deletions
+4
View File
@@ -25,6 +25,9 @@
</application-components>
<actions>
<action id="images.color.picker" class="org.intellij.images.actions.ColorPickerForImageAction" text="Show Color Picker">
<add-to-group anchor="after" group-id="ProjectViewPopupMenu" relative-to-action="EditSource"/>
</action>
<action class="org.intellij.images.actions.EditExternallyAction"
id="Images.EditExternaly"
icon="ImagesIcons.EditExternaly"
@@ -85,6 +88,7 @@
<separator/>
<reference id="VersionControlsGroup"/>
<separator/>
<reference id="images.color.picker" />
<reference id="Images.EditExternaly"/>
<reference id="ExternalToolsGroup"/>
</group>
@@ -0,0 +1,29 @@
/*
* Copyright 2000-2012 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 org.intellij.images.actions;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.ui.ShowColorPickerAction;
/**
* @author Konstantin Bulenkov
*/
public class ColorPickerForImageAction extends ShowColorPickerAction {
@Override
public void update(AnActionEvent e) {
EditExternallyAction.doUpdate(e);
}
}
@@ -106,6 +106,10 @@ public final class EditExternallyAction extends AnAction {
public void update(AnActionEvent e) {
super.update(e);
doUpdate(e);
}
static void doUpdate(AnActionEvent e) {
VirtualFile[] files = e.getData(PlatformDataKeys.VIRTUAL_FILE_ARRAY);
final boolean isEnabled = isImages(files);
if (e.getPlace().equals(ActionPlaces.PROJECT_VIEW_POPUP)) {
@@ -26,6 +26,7 @@ import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiManager;
import com.intellij.ui.PopupHandler;
import com.intellij.ui.ScrollPaneFactory;
import com.intellij.util.ui.UIUtil;
import org.intellij.images.ImagesBundle;
import org.intellij.images.editor.ImageDocument;
import org.intellij.images.editor.ImageEditor;
@@ -206,6 +207,15 @@ final class ImageEditorUI extends JPanel implements DataProvider {
public Dimension getPreferredSize() {
return imageComponent.getSize();
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (UIUtil.isUnderDarcula()) {
g.setColor(UIUtil.getControlColor().brighter());
g.fillRect(0,0,getWidth(), getHeight());
}
}
}
private final class ImageWheelAdapter implements MouseWheelListener {
@@ -1808,5 +1808,10 @@ public class JavaDocInfoGenerator {
expression.getArgumentList().acceptChildren(this);
myBuffer.append(")");
}
@Override
public void visitLiteralExpression(PsiLiteralExpression expression) {
myBuffer.append(expression.getText());
}
}
}
@@ -952,9 +952,6 @@ class ControlFlowAnalyzer extends JavaElementVisitor {
if (JavaTokenType.PLUS == op && (type == null || !type.equalsToText(CommonClassNames.JAVA_LANG_STRING))) {
return null;
}
else if (op == JavaTokenType.LT || op == JavaTokenType.GT) {
return JavaTokenType.NE;
}
return op;
}
@@ -553,7 +553,7 @@ public class DfaMemoryStateImpl implements DfaMemoryState {
if (dfaCond instanceof DfaUnboxedValue) {
DfaVariableValue dfaVar = ((DfaUnboxedValue)dfaCond).getVariable();
boolean isNegated = dfaVar.isNegated();
DfaVariableValue dfaNormalVar = isNegated ? (DfaVariableValue)dfaVar.createNegated() : dfaVar;
DfaVariableValue dfaNormalVar = isNegated ? dfaVar.createNegated() : dfaVar;
DfaConstValue dfaTrue = myFactory.getConstFactory().getTrue();
final DfaValue boxedTrue = myFactory.getBoxedFactory().createBoxed(dfaTrue);
DfaRelationValue dfaEqualsTrue = myFactory.getRelationFactory().createRelation(dfaNormalVar, boxedTrue, JavaTokenType.EQEQ, isNegated);
@@ -563,7 +563,7 @@ public class DfaMemoryStateImpl implements DfaMemoryState {
if (dfaCond instanceof DfaVariableValue) {
DfaVariableValue dfaVar = (DfaVariableValue)dfaCond;
boolean isNegated = dfaVar.isNegated();
DfaVariableValue dfaNormalVar = isNegated ? (DfaVariableValue)dfaVar.createNegated() : dfaVar;
DfaVariableValue dfaNormalVar = isNegated ? dfaVar.createNegated() : dfaVar;
DfaConstValue dfaTrue = myFactory.getConstFactory().getTrue();
DfaRelationValue dfaEqualsTrue = myFactory.getRelationFactory().createRelation(dfaNormalVar, dfaTrue, JavaTokenType.EQEQ, isNegated);
@@ -576,7 +576,10 @@ public class DfaMemoryStateImpl implements DfaMemoryState {
if (!(dfaCond instanceof DfaRelationValue)) return true;
DfaRelationValue dfaRelation = (DfaRelationValue)dfaCond;
return applyRelationCondition((DfaRelationValue)dfaCond);
}
private boolean applyRelationCondition(DfaRelationValue dfaRelation) {
DfaValue dfaLeft = dfaRelation.getLeftOperand();
DfaValue dfaRight = dfaRelation.getRightOperand();
if (dfaRight == null || dfaLeft == null) return false;
@@ -610,6 +613,14 @@ public class DfaMemoryStateImpl implements DfaMemoryState {
if (dfaLeft instanceof DfaUnknownValue || dfaRight instanceof DfaUnknownValue) return true;
return applyEquivalenceRelation(dfaRelation, dfaLeft, dfaRight);
}
private boolean applyEquivalenceRelation(DfaRelationValue dfaRelation, DfaValue dfaLeft, DfaValue dfaRight) {
boolean isNegated = dfaRelation.isNonEquality();
if (!isNegated && !dfaRelation.isEquality()) {
return true;
}
boolean result = applyRelation(dfaLeft, dfaRight, isNegated);
if (dfaRight instanceof DfaConstValue) {
Object constVal = ((DfaConstValue)dfaRight).getValue();
@@ -34,20 +34,19 @@ import com.intellij.openapi.project.Project;
import com.intellij.psi.*;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.tree.IElementType;
import com.intellij.psi.tree.TokenSet;
import org.jetbrains.annotations.NotNull;
import static com.intellij.psi.JavaTokenType.*;
public class BinopInstruction extends BranchingInstruction {
private static final TokenSet ourSignificantOperations = TokenSet.create(EQEQ, NE, LT, GT, LE, GE, INSTANCEOF_KEYWORD, PLUS);
private final IElementType myOperationSign;
private final Project myProject;
public BinopInstruction(IElementType opSign, PsiElement psiAnchor, @NotNull Project project) {
myProject = project;
if (JavaTokenType.EQEQ == opSign || JavaTokenType.NE == opSign || JavaTokenType.INSTANCEOF_KEYWORD == opSign || JavaTokenType.PLUS == opSign) {
myOperationSign = opSign;
}
else {
myOperationSign = null;
}
myOperationSign = ourSignificantOperations.contains(opSign) ? opSign : null;
setPsiAnchor(psiAnchor);
}
@@ -70,8 +70,8 @@ public abstract class BranchingInstruction extends Instruction {
return "true".equals(text) || "false".equals(text);
}
protected void setPsiAnchor(PsiElement psiAcnchor) {
myExpression = psiAcnchor;
isConstTrue = psiAcnchor != null && isBoolConst(psiAcnchor);
protected void setPsiAnchor(PsiElement psiAnchor) {
myExpression = psiAnchor;
isConstTrue = psiAnchor != null && isBoolConst(psiAnchor);
}
}
@@ -25,7 +25,6 @@
package com.intellij.codeInspection.dataFlow.value;
import com.intellij.openapi.util.Comparing;
import com.intellij.psi.JavaTokenType;
import com.intellij.psi.tree.IElementType;
import com.intellij.util.containers.HashMap;
import org.jetbrains.annotations.NonNls;
@@ -33,6 +32,8 @@ import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import static com.intellij.psi.JavaTokenType.*;
public class DfaRelationValue extends DfaValue {
private DfaValue myLeftOperand;
private DfaValue myRightOperand;
@@ -52,8 +53,8 @@ public class DfaRelationValue extends DfaValue {
@Nullable
public DfaRelationValue createRelation(DfaValue dfaLeft, DfaValue dfaRight, IElementType relation, boolean negated) {
if (dfaRight instanceof DfaTypeValue && JavaTokenType.INSTANCEOF_KEYWORD != relation) return null;
if (JavaTokenType.PLUS == relation) return null;
if (dfaRight instanceof DfaTypeValue && INSTANCEOF_KEYWORD != relation) return null;
if (PLUS == relation) return null;
if (dfaLeft instanceof DfaVariableValue || dfaLeft instanceof DfaBoxedValue || dfaLeft instanceof DfaUnboxedValue
|| dfaRight instanceof DfaVariableValue || dfaRight instanceof DfaBoxedValue || dfaRight instanceof DfaUnboxedValue) {
@@ -79,16 +80,16 @@ public class DfaRelationValue extends DfaValue {
final DfaValue dfaLeft,
final DfaValue dfaRight) {
// To canonical form.
if (JavaTokenType.NE == relation) {
relation = JavaTokenType.EQEQ;
if (NE == relation) {
relation = EQEQ;
negated = !negated;
}
else if (JavaTokenType.LT == relation) {
relation = JavaTokenType.GE;
else if (LT == relation) {
relation = GE;
negated = !negated;
}
else if (JavaTokenType.LE == relation) {
relation = JavaTokenType.GT;
else if (LE == relation) {
relation = GT;
negated = !negated;
}
@@ -115,19 +116,10 @@ public class DfaRelationValue extends DfaValue {
}
private static IElementType getSymmetricOperation(IElementType sign) {
if (JavaTokenType.LT == sign) {
return JavaTokenType.GT;
}
else if (JavaTokenType.GE == sign) {
return JavaTokenType.LE;
}
else if (JavaTokenType.GT == sign) {
return JavaTokenType.LT;
}
else if (JavaTokenType.LE == sign) {
return JavaTokenType.GE;
}
if (LT == sign) return GT;
if (GE == sign) return LE;
if (GT == sign) return LT;
if (LE == sign) return GE;
return sign;
}
}
@@ -168,6 +160,14 @@ public class DfaRelationValue extends DfaValue {
rel.myIsNegated == myIsNegated;
}
public boolean isEquality() {
return myRelation == EQEQ && !myIsNegated;
}
public boolean isNonEquality() {
return myRelation == EQEQ && myIsNegated || myRelation == GT && !myIsNegated || myRelation == GE && myIsNegated;
}
@NonNls public String toString() {
return (isNegated() ? "not " : "") + myLeftOperand + " " + myRelation + " " + myRightOperand;
}
@@ -17,6 +17,7 @@ package com.intellij.psi;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.util.Computable;
import com.intellij.psi.codeStyle.JavaCodeStyleManager;
import com.intellij.psi.infos.MethodCandidateInfo;
import com.intellij.psi.util.*;
import org.jetbrains.annotations.NotNull;
@@ -215,11 +216,16 @@ public class LambdaUtil {
}
}
if (checkReturnType) {
final String uniqueVarName =
JavaCodeStyleManager.getInstance(lambdaExpression.getProject()).suggestUniqueVariableName("l", lambdaExpression, true);
final PsiStatement assignmentFromText = JavaPsiFacade.getElementFactory(lambdaExpression.getProject())
.createStatementFromText(leftType.getCanonicalText() + " " + uniqueVarName + " = " + lambdaExpression.getText(), lambdaExpression);
final PsiLocalVariable localVariable = (PsiLocalVariable)((PsiDeclarationStatement)assignmentFromText).getDeclaredElements()[0];
LOG.assertTrue(psiClass != null);
PsiType methodReturnType = getReturnType(psiClass, methodSignature);
if (methodReturnType != null) {
methodReturnType = resolveResult.getSubstitutor().substitute(methodSignature.getSubstitutor().substitute(methodReturnType));
return checkReturnTypeCompatible(lambdaExpression, methodReturnType) == null;
return checkReturnTypeCompatible((PsiLambdaExpression)localVariable.getInitializer(), methodReturnType) == null;
}
}
return true;
@@ -459,21 +465,21 @@ public class LambdaUtil {
final PsiElement gParent = expressionList.getParent();
if (gParent instanceof PsiCallExpression) {
final PsiCallExpression contextCall = (PsiCallExpression)gParent;
return PsiResolveHelper.ourGuard.doPreventingRecursion(expression, true, new Computable<PsiType>() {
@Override
public PsiType compute() {
final JavaResolveResult resolveResult = contextCall.resolveMethodGenerics();
final PsiElement resolve = resolveResult.getElement();
if (resolve instanceof PsiMethod) {
final PsiParameter[] parameters = ((PsiMethod)resolve).getParameterList().getParameters();
if (lambdaIdx < parameters.length) {
if (!tryToSubstitute) return parameters[lambdaIdx].getType();
return resolveResult.getSubstitutor().substitute(parameters[lambdaIdx].getType());
}
final JavaResolveResult resolveResult = contextCall.resolveMethodGenerics();
final PsiElement resolve = resolveResult.getElement();
if (resolve instanceof PsiMethod) {
final PsiParameter[] parameters = ((PsiMethod)resolve).getParameterList().getParameters();
if (lambdaIdx < parameters.length) {
if (!tryToSubstitute) return parameters[lambdaIdx].getType();
return PsiResolveHelper.ourGuard.doPreventingRecursion(expression, true, new Computable<PsiType>() {
@Override
public PsiType compute() {
return resolveResult.getSubstitutor().substitute(parameters[lambdaIdx].getType());
}
});
}
return null;
}
});
return null;
}
}
}
@@ -507,8 +513,8 @@ public class LambdaUtil {
}
final PsiParameterList parameterList = lambdaExpression.getParameterList();
final boolean add = currentStack.add(parameterList);
try {
currentStack.add(parameterList);
PsiType type = getFunctionalInterfaceType(lambdaExpression, true);
if (type == null) {
type = getFunctionalInterfaceType(lambdaExpression, false);
@@ -528,7 +534,7 @@ public class LambdaUtil {
}
}
finally {
currentStack.remove(parameterList);
if (add) currentStack.remove(parameterList);
}
}
}
@@ -57,7 +57,7 @@ class ReturnTypeCompatibility {
}
public static void main(String[] args) {
call(<error descr="Cyclic inference">i-> {return i;}</error>);
<error descr="Cannot resolve method 'call(<lambda expression>)'">call</error>(i-> {return i;});
}
}
@@ -0,0 +1,38 @@
import org.jetbrains.annotations.NotNull;
import java.io.File;
class Zoo2 {
public static boolean startsWith(@NotNull String path, @NotNull String start, final boolean caseSensitive) {
final int length1 = path.length();
final int length2 = start.length();
if (length2 == 0) return true;
if (length2 > length1) return false;
if (!path.regionMatches(!caseSensitive, 0, start, 0, length2)) return false;
if (length1 == length2) return true;
char last2 = start.charAt(length2 - 1);
char next1;
if (last2 == '/' || last2 == File.separatorChar) {
next1 = path.charAt(length2 - 1);
}
else {
next1 = path.charAt(length2);
}
return next1 == '/' || next1 == File.separatorChar;
}
void foo(Some me, Some other) {
if (me.depth < other.depth) {
System.out.println("less");
} else if (other.depth > me.depth) {
System.out.println("more");
}
}
}
class Some {
final int depth;
Some(int depth) {
this.depth = depth;
}
}
@@ -77,6 +77,7 @@ public class DataFlowInspectionFixtureTest extends JavaCodeInsightFixtureTestCas
public void testEqualsConstant() throws Throwable { doTest(); }
public void testFinalLoopVariableInstanceof() throws Throwable { doTest(); }
public void testGreaterIsNotEquals() throws Throwable { doTest(); }
public void testNotGreaterIsNotEquals() throws Throwable { doTest(); }
public void testChainedFinalFieldsDfa() throws Throwable { doTest(); }
public void testChainedFinalFieldAccessorsDfa() throws Throwable { doTest(); }
@@ -77,11 +77,9 @@ public abstract class AbstractSuppressByNoInspectionCommentFix extends SuppressI
}
@Nullable
protected static String getLineCommentPrefix(final PsiElement comment) {
protected static String getLineCommentPrefix(@NotNull final PsiElement comment) {
final Commenter commenter = LanguageCommenters.INSTANCE.forLanguage(comment.getLanguage());
assert commenter != null;
return commenter.getLineCommentPrefix();
return commenter == null ? null : commenter.getLineCommentPrefix();
}
protected void createSuppression(final Project project,
@@ -57,19 +57,19 @@ public class FileColorManagerImpl extends FileColorManager implements Persistent
static {
ourDefaultColors = new LinkedHashMap<String, Color>();
ourDefaultColors.put("Blue", new Color(220, 240, 255));
ourDefaultColors.put("Blue", new Color(0xdcf0ff));
ourDefaultColors.put("Green", new Color(231, 250, 219));
ourDefaultColors.put("Orange", new Color(246, 224, 202));
ourDefaultColors.put("Rose", new Color(242, 206, 202));
ourDefaultColors.put("Violet", new Color(222, 213, 241));
ourDefaultColors.put("Yellow", new Color(255, 255, 228));
ourDefaultDarkColors = new LinkedHashMap<String, Color>();
ourDefaultDarkColors.put("Blue", new Color(255-220, 255-240, 255-255));
ourDefaultDarkColors.put("Green", new Color(255-231, 255-250, 255-219));
ourDefaultDarkColors.put("Orange", new Color(255-246, 255-224, 255-202));
ourDefaultDarkColors.put("Rose", new Color(255-242, 255-206, 255-202));
ourDefaultDarkColors.put("Violet", new Color(255-222, 255-213, 255-241));
ourDefaultDarkColors.put("Yellow", new Color(255-255, 255-255, 255-228));
ourDefaultDarkColors.put("Blue", new Color(0x2B3557));
ourDefaultDarkColors.put("Green", new Color(0x253B10));
ourDefaultDarkColors.put("Orange", new Color(0xB85E3A));
ourDefaultDarkColors.put("Rose", new Color(0x4B193E));
ourDefaultDarkColors.put("Violet", new Color(0x341657));
ourDefaultDarkColors.put("Yellow", new Color(0x402D10));
}
public FileColorManagerImpl(@NotNull final Project project) {
@@ -1,5 +1,5 @@
/*
* Copyright 2006-2007 Dave Griffith, Bas Leijdekkers
* Copyright 2006-2012 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.
@@ -17,78 +17,77 @@ package com.siyeh.ig.threading;
import com.intellij.psi.*;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.util.containers.OrderedSet;
import com.siyeh.InspectionGadgetsBundle;
import com.siyeh.ig.BaseInspection;
import com.siyeh.ig.BaseInspectionVisitor;
import com.siyeh.ig.psiutils.ExpressionUtils;
import com.siyeh.ig.ui.UiUtils;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public class AccessToStaticFieldLockedOnInstanceInspection
extends BaseInspection {
import javax.swing.*;
public class AccessToStaticFieldLockedOnInstanceInspection extends BaseInspection {
@SuppressWarnings("PublicField") public OrderedSet<String> ignoredClasses = new OrderedSet();
@Override
@NotNull
public String getDisplayName() {
return InspectionGadgetsBundle.message(
"access.to.static.field.locked.on.instance.display.name");
return InspectionGadgetsBundle.message("access.to.static.field.locked.on.instance.display.name");
}
@Override
@NotNull
protected String buildErrorString(Object... infos) {
return InspectionGadgetsBundle.message(
"access.to.static.field.locked.on.instance.problem.descriptor");
return InspectionGadgetsBundle.message("access.to.static.field.locked.on.instance.problem.descriptor");
}
@Nullable
@Override
public JComponent createOptionsPanel() {
return UiUtils.createTreeClassChooserList(ignoredClasses, "Ignored Classes", "Choose class to ignore");
}
@Override
public BaseInspectionVisitor buildVisitor() {
return new AccessToStaticFieldLockedOnInstanceVisitor();
}
private static class AccessToStaticFieldLockedOnInstanceVisitor
extends BaseInspectionVisitor {
private class AccessToStaticFieldLockedOnInstanceVisitor extends BaseInspectionVisitor {
@Override
public void visitReferenceExpression(
@NotNull PsiReferenceExpression expression) {
public void visitReferenceExpression(@NotNull PsiReferenceExpression expression) {
super.visitReferenceExpression(expression);
boolean isLockedOnInstance = false;
boolean isLockedOnClass = false;
final PsiMethod containingMethod =
PsiTreeUtil.getParentOfType(expression, PsiMethod.class);
if (containingMethod != null &&
containingMethod.hasModifierProperty(
PsiModifier.SYNCHRONIZED)) {
if (containingMethod.hasModifierProperty(
PsiModifier.STATIC)) {
final PsiMethod containingMethod = PsiTreeUtil.getParentOfType(expression, PsiMethod.class);
if (containingMethod != null && containingMethod.hasModifierProperty(PsiModifier.SYNCHRONIZED)) {
if (containingMethod.hasModifierProperty(PsiModifier.STATIC)) {
isLockedOnClass = true;
}
else {
isLockedOnInstance = true;
}
}
final PsiClass expressionClass =
PsiTreeUtil.getParentOfType(expression, PsiClass.class);
final PsiClass expressionClass = PsiTreeUtil.getParentOfType(expression, PsiClass.class);
if (expressionClass == null) {
return;
}
PsiElement elementToCheck = expression;
while (true) {
final PsiSynchronizedStatement synchronizedStatement =
PsiTreeUtil.getParentOfType(elementToCheck,
PsiSynchronizedStatement.class);
if (synchronizedStatement == null ||
!PsiTreeUtil.isAncestor(expressionClass,
synchronizedStatement, true)) {
final PsiSynchronizedStatement synchronizedStatement = PsiTreeUtil.getParentOfType(elementToCheck, PsiSynchronizedStatement.class);
if (synchronizedStatement == null || !PsiTreeUtil.isAncestor(expressionClass, synchronizedStatement, true)) {
break;
}
final PsiExpression lockExpression =
synchronizedStatement.getLockExpression();
final PsiExpression lockExpression = synchronizedStatement.getLockExpression();
if (lockExpression instanceof PsiReferenceExpression) {
final PsiReferenceExpression reference =
(PsiReferenceExpression)lockExpression;
final PsiElement referent = reference.resolve();
if (referent instanceof PsiField) {
final PsiField referentField = (PsiField)referent;
if (referentField.hasModifierProperty(
PsiModifier.STATIC)) {
final PsiReferenceExpression reference = (PsiReferenceExpression)lockExpression;
final PsiElement target = reference.resolve();
if (target instanceof PsiField) {
final PsiField lockField = (PsiField)target;
if (lockField.hasModifierProperty(PsiModifier.STATIC)) {
isLockedOnClass = true;
}
else {
@@ -99,8 +98,7 @@ public class AccessToStaticFieldLockedOnInstanceInspection
else if (lockExpression instanceof PsiThisExpression) {
isLockedOnInstance = true;
}
else if (lockExpression instanceof
PsiClassObjectAccessExpression) {
else if (lockExpression instanceof PsiClassObjectAccessExpression) {
isLockedOnClass = true;
}
elementToCheck = synchronizedStatement;
@@ -108,19 +106,28 @@ public class AccessToStaticFieldLockedOnInstanceInspection
if (!isLockedOnInstance || isLockedOnClass) {
return;
}
final PsiElement referent = expression.resolve();
if (!(referent instanceof PsiField)) {
final PsiElement target = expression.resolve();
if (!(target instanceof PsiField)) {
return;
}
final PsiField referredField = (PsiField)referent;
if (!referredField.hasModifierProperty(PsiModifier.STATIC) ||
ExpressionUtils.isConstant(referredField)) {
final PsiField lockedField = (PsiField)target;
if (!lockedField.hasModifierProperty(PsiModifier.STATIC) || ExpressionUtils.isConstant(lockedField)) {
return;
}
final PsiClass containingClass = referredField.getContainingClass();
final PsiClass containingClass = lockedField.getContainingClass();
if (!PsiTreeUtil.isAncestor(containingClass, expression, false)) {
return;
}
if (!ignoredClasses.isEmpty()) {
final PsiType type = lockedField.getType();
if (type instanceof PsiClassType) {
final PsiClassType classType = (PsiClassType)type;
final PsiClass aClass = classType.resolve();
if (aClass != null && ignoredClasses.contains(aClass.getQualifiedName())) {
return;
}
}
}
registerError(expression);
}
}
@@ -6,6 +6,8 @@ Locking a <b>static</b> field on instance data does not prevent the field from b
modified by other instances, and thus may result in surprising race conditions.
<!-- tooltip end -->
<p>
Use the table below to specify classes to ignore. Any static fields of the types specified will be ignored by this inspection.
<p>
<small>Powered by InspectionGadgets</small>
</body>
</html>
@@ -1,10 +1,12 @@
package com.siyeh.igtest.threading;
package com.siyeh.igtest.threading.access_to_static_field_locked_on_instance_data;
import java.util.List;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
public class AccessToStaticFieldLockedOnInstanceDataInspection {
public class AccessToStaticFieldLockedOnInstanceData {
private static int foo;
private static final List LIST = new java.util.ArrayList(); // pretend this is immutable
public static synchronized void test1()
{
@@ -25,13 +27,13 @@ public class AccessToStaticFieldLockedOnInstanceDataInspection {
{
foo = 3;
System.out.println(foo);
LIST.get(0);
}
}
}
class StaticFieldNotLockedOnInstanceData
{
private static final Object printer_ = new Object();
;
private final Executor executor_ = Executors.newCachedThreadPool();
private final Object lock_ = new Object();
@@ -0,0 +1,31 @@
<?xml version="1.0" encoding="UTF-8"?>
<problems>
<problem>
<file>AccessToStaticFieldLockedOnInstanceData.java</file>
<line>19</line>
<problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Access to static field locked on instance data</problem_class>
<description>Access to static field &lt;code&gt;foo&lt;/code&gt; locked on instance data #loc</description>
</problem>
<problem>
<file>AccessToStaticFieldLockedOnInstanceData.java</file>
<line>20</line>
<problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Access to static field locked on instance data</problem_class>
<description>Access to static field &lt;code&gt;foo&lt;/code&gt; locked on instance data #loc</description>
</problem>
<problem>
<file>AccessToStaticFieldLockedOnInstanceData.java</file>
<line>28</line>
<problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Access to static field locked on instance data</problem_class>
<description>Access to static field &lt;code&gt;foo&lt;/code&gt; locked on instance data #loc</description>
</problem>
<problem>
<file>AccessToStaticFieldLockedOnInstanceData.java</file>
<line>29</line>
<problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Access to static field locked on instance data</problem_class>
<description>Access to static field &lt;code&gt;foo&lt;/code&gt; locked on instance data #loc</description>
</problem>
</problems>
@@ -0,0 +1,12 @@
package com.siyeh.ig.threading;
import com.siyeh.ig.IGInspectionTestCase;
public class AccessToStaticFieldLockedOnInstanceInspectionTest extends IGInspectionTestCase {
public void test() throws Exception {
final AccessToStaticFieldLockedOnInstanceInspection tool = new AccessToStaticFieldLockedOnInstanceInspection();
tool.ignoredClasses.add("java.util.List");
doTest("com/siyeh/igtest/threading/access_to_static_field_locked_on_instance_data", tool);
}
}
@@ -382,12 +382,7 @@ public class ControlFlowBuilder extends GroovyRecursiveElementVisitor {
addNodeAndCheckPending(throwInstruction);
interruptFlow();
final PsiType type = RecursionManager.doPreventingRecursion(exception, true, new NullableComputable<PsiType>() {
@Override
public PsiType compute() {
return exception.getNominalType();
}
});
final PsiType type = getNominalTypeNoRecursion(exception);
if (type != null) {
ExceptionInfo info = findCatch(type);
if (info != null) {
@@ -402,6 +397,15 @@ public class ControlFlowBuilder extends GroovyRecursiveElementVisitor {
}
}
private static PsiType getNominalTypeNoRecursion(final GrExpression exception) {
return RecursionManager.doPreventingRecursion(exception, true, new NullableComputable<PsiType>() {
@Override
public PsiType compute() {
return exception.getNominalType();
}
});
}
private void interruptFlow() {
myHead = null;
}
@@ -924,7 +928,7 @@ public class ControlFlowBuilder extends GroovyRecursiveElementVisitor {
final GrExpression condition = statement.getCondition();
if (!(condition instanceof GrReferenceExpression)) return false;
PsiType type = TypesUtil.unboxPrimitiveTypeWrapper(condition.getNominalType());
PsiType type = TypesUtil.unboxPrimitiveTypeWrapper(getNominalTypeNoRecursion(condition));
if (type == null) return false;
if (type instanceof PsiPrimitiveType) {
@@ -386,8 +386,14 @@ public class GrClassImplUtil {
return Arrays.asList(grType.getInnerClasses());
}
List<PsiClass> result = new ArrayList<PsiClass>();
for (CandidateInfo info : CollectClassMembersUtil.getAllInnerClasses(grType, false).values()) {
ContainerUtil.addIfNotNull(result, (PsiClass)info.getElement());
try {
for (CandidateInfo info : CollectClassMembersUtil.getAllInnerClasses(grType, false).values()) {
ContainerUtil.addIfNotNull(result, (PsiClass)info.getElement());
}
}
catch (StackOverflowError e) {
throw new RuntimeException("lastParent=" + lastParent, e);
}
return result;
}
@@ -1419,4 +1419,19 @@ class X {
testHighlighting('''\
def (a, b) = [a, a]''')
}
public void testSwitchInLoopNoSoe() {
testHighlighting('''
def foo(File f) {
while (true) {
switch (f.name) {
case 'foo': f = new File('bar')
}
if (f) {
return
}
}
}''')
}
}