#ref is not declared ''static final'' #loc
+atomic.field.updater.issues.display.name=AtomicFieldUpdater issues
+field.not.found.in.class.problem.descriptor=No field named ''{0}'' found in class ''{1}''
+field.incorrect.type.problem.descriptor=Field ''{0}'' does not have type ''{1}''
+field.missing.volatile.modifier.problem.descriptor=Field ''{0}'' does not have ''volatile'' modifier
+field.has.static.modifier.problem.descriptor=Field ''{0}'' has ''static'' modifier
+private.field.not.accessible.problem.descriptor=''private'' field ''{0}'' is not accessible from here
+package.local.field.not.accessible=package local field ''{0}'' is not accessible from here
+protected.field.not.accessible.problem.descriptor=''protected'' field ''{0}'' is not accessible from here
\ No newline at end of file
diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/threading/AtomicFieldUpdaterIssuesInspection.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/threading/AtomicFieldUpdaterIssuesInspection.java
new file mode 100644
index 000000000000..fa07adabb4dd
--- /dev/null
+++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/threading/AtomicFieldUpdaterIssuesInspection.java
@@ -0,0 +1,170 @@
+/*
+ * Copyright 2000-2015 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.siyeh.InspectionGadgetsBundle;
+import com.siyeh.ig.BaseInspection;
+import com.siyeh.ig.BaseInspectionVisitor;
+import com.siyeh.ig.psiutils.ClassUtils;
+import com.siyeh.ig.psiutils.ExpressionUtils;
+import com.siyeh.ig.psiutils.TypeUtils;
+import org.jetbrains.annotations.Nls;
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * @author Bas Leijdekkers
+ */
+public class AtomicFieldUpdaterIssuesInspection extends BaseInspection {
+
+ @Nls
+ @NotNull
+ @Override
+ public String getDisplayName() {
+ return InspectionGadgetsBundle.message("atomic.field.updater.issues.display.name");
+ }
+
+ @NotNull
+ @Override
+ protected String buildErrorString(Object... infos) {
+ final String message = (String)infos[0];
+ return message;
+ }
+
+ @Override
+ public BaseInspectionVisitor buildVisitor() {
+ return new AtomicFieldUpdaterIssuesVisitor();
+ }
+
+ private static class AtomicFieldUpdaterIssuesVisitor extends BaseInspectionVisitor {
+
+ @Override
+ public void visitMethodCallExpression(PsiMethodCallExpression expression) {
+ super.visitMethodCallExpression(expression);
+ final PsiReferenceExpression methodExpression = expression.getMethodExpression();
+ final String name = methodExpression.getReferenceName();
+ if (!"newUpdater".equals(name)) {
+ return;
+ }
+ final PsiExpressionList argumentList = expression.getArgumentList();
+ final PsiExpression[] arguments = argumentList.getExpressions();
+ if (arguments.length < 2) {
+ return;
+ }
+ final PsiExpression lastArgument = arguments[arguments.length - 1];
+ final Object value = ExpressionUtils.computeConstantExpression(lastArgument);
+ if (!(value instanceof String)) {
+ return;
+ }
+ final String fieldName = (String)value;
+ final PsiExpression firstArgument = arguments[0];
+ if (!(firstArgument instanceof PsiClassObjectAccessExpression)) {
+ return;
+ }
+ final PsiClassObjectAccessExpression classObjectAccessExpression = (PsiClassObjectAccessExpression)firstArgument;
+ final PsiType operandType = classObjectAccessExpression.getOperand().getType();
+ if (!(operandType instanceof PsiClassType)) {
+ return;
+ }
+ final PsiClassType classType = (PsiClassType)operandType;
+ final PsiClass target = classType.resolve();
+ if (target == null) {
+ return;
+ }
+ final PsiMethod method = expression.resolveMethod();
+ if (method == null) {
+ return;
+ }
+ final String typeString = TypeUtils.expressionHasTypeOrSubtype(expression,
+ "java.util.concurrent.atomic.AtomicLongFieldUpdater",
+ "java.util.concurrent.atomic.AtomicIntegerFieldUpdater",
+ "java.util.concurrent.atomic.AtomicReferenceFieldUpdater");
+ if (typeString == null) {
+ return;
+ }
+ final PsiField field = target.findFieldByName(fieldName, false);
+ if (field == null) {
+ registerError(lastArgument,
+ InspectionGadgetsBundle.message("field.not.found.in.class.problem.descriptor", fieldName, target.getName()));
+ return;
+ }
+ else if (typeString.equals("java.util.concurrent.atomic.AtomicLongFieldUpdater")) {
+ if (arguments.length != 2) {
+ return;
+ }
+ if (!PsiType.LONG.equals(field.getType())) {
+ registerError(lastArgument, InspectionGadgetsBundle.message("field.incorrect.type.problem.descriptor", fieldName, "long"));
+ return;
+ }
+ }
+ else if (typeString.equals("java.util.concurrent.atomic.AtomicIntegerFieldUpdater")) {
+ if (arguments.length != 2) {
+ return;
+ }
+ if (!PsiType.INT.equals(field.getType())) {
+ registerError(lastArgument, InspectionGadgetsBundle.message("field.incorrect.type.problem.descriptor", fieldName, "int"));
+ return;
+ }
+ }
+ else if (typeString.equals("java.util.concurrent.atomic.AtomicReferenceFieldUpdater")) {
+ if (arguments.length != 3) {
+ return;
+ }
+ final PsiExpression argument2 = arguments[1];
+ if (!(argument2 instanceof PsiClassObjectAccessExpression)) {
+ return;
+ }
+ final PsiClassObjectAccessExpression objectAccessExpression = (PsiClassObjectAccessExpression)argument2;
+ final PsiType type = objectAccessExpression.getOperand().getType();
+ if (!field.getType().equals(type)) {
+ registerError(lastArgument, InspectionGadgetsBundle.message("field.incorrect.type.problem.descriptor",
+ fieldName, type.getPresentableText()));
+ return;
+ }
+ }
+ else {
+ assert false;
+ }
+ if (!field.hasModifierProperty(PsiModifier.VOLATILE)) {
+ registerError(lastArgument, InspectionGadgetsBundle.message("field.missing.volatile.modifier.problem.descriptor", fieldName));
+ }
+ else if (field.hasModifierProperty(PsiModifier.STATIC)) {
+ registerError(lastArgument, InspectionGadgetsBundle.message("field.has.static.modifier.problem.descriptor", fieldName));
+ }
+ else if (!field.hasModifierProperty(PsiModifier.PUBLIC)) {
+ if (ClassUtils.getContainingClass(expression) != field.getContainingClass()) {
+ if (field.hasModifierProperty(PsiModifier.PRIVATE)) {
+ registerError(lastArgument, InspectionGadgetsBundle.message("private.field.not.accessible.problem.descriptor", fieldName));
+ }
+ }
+ else if (!ClassUtils.inSamePackage(expression, field)) {
+ if (field.hasModifierProperty(PsiModifier.PACKAGE_LOCAL)) {
+ registerError(lastArgument, InspectionGadgetsBundle.message("package.local.field.not.accessible", fieldName));
+ }
+ }
+ else {
+ final PsiClass expressionClass = ClassUtils.getContainingClass(expression);
+ final PsiClass fieldClass = field.getContainingClass();
+ if (expressionClass != null && fieldClass != null && !expressionClass.isInheritor(fieldClass, true)) {
+ if (field.hasModifierProperty(PsiModifier.PROTECTED)) {
+ registerError(lastArgument, InspectionGadgetsBundle.message("protected.field.not.accessible.problem.descriptor", fieldName));
+ }
+ }
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/AtomicFieldUpdaterIssues.html b/plugins/InspectionGadgets/src/inspectionDescriptions/AtomicFieldUpdaterIssues.html
new file mode 100644
index 000000000000..23d6c8e30e9d
--- /dev/null
+++ b/plugins/InspectionGadgets/src/inspectionDescriptions/AtomicFieldUpdaterIssues.html
@@ -0,0 +1,16 @@
+
+
+
+
+Reports issues on fields of type java.util.concurrent.atomic.AtomicLongFieldUpdater,
+java.util.concurrent.atomic.AtomicIntegerFieldUpdater or java.util.concurrent.atomic.AtomicReferenceFieldUpdater.
+The issues reported are identical to the runtime problems that can happen with atomic field updaters:
+specified field not found, specified field not accessible, specified field of the wrong type, etc.
+
+
++New in 15.1 + + + + \ No newline at end of file diff --git a/plugins/InspectionGadgets/testsrc/com/siyeh/ig/threading/AtomicFieldUpdaterIssuesInspectionTest.java b/plugins/InspectionGadgets/testsrc/com/siyeh/ig/threading/AtomicFieldUpdaterIssuesInspectionTest.java new file mode 100644 index 000000000000..88b74be2444f --- /dev/null +++ b/plugins/InspectionGadgets/testsrc/com/siyeh/ig/threading/AtomicFieldUpdaterIssuesInspectionTest.java @@ -0,0 +1,108 @@ +/* + * Copyright 2000-2015 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.codeInspection.InspectionProfileEntry; +import com.siyeh.ig.LightInspectionTestCase; +import org.jetbrains.annotations.Nullable; + +/** + * @author Bas Leijdekkers + */ +public class AtomicFieldUpdaterIssuesInspectionTest extends LightInspectionTestCase { + + public void testAllGood() { + doTest("import java.util.concurrent.atomic.AtomicIntegerFieldUpdater;" + + "class A {" + + " private volatile int value = 0;" + + " private static final AtomicIntegerFieldUpdater updater = " + + " AtomicIntegerFieldUpdater.newUpdater(A.class, \"value\");" + + "}"); + } + + public void testStatic() { + doTest("import java.util.concurrent.atomic.AtomicIntegerFieldUpdater;" + + "class A {" + + " private static volatile int value = 0;" + + " private static final AtomicIntegerFieldUpdater updater = " + + " AtomicIntegerFieldUpdater.newUpdater(A.class, /*Field 'value' has 'static' modifier*/\"value\"/**/);" + + "}"); + } + + public void testNotVolatile() { + doTest("import java.util.concurrent.atomic.AtomicIntegerFieldUpdater;" + + "class A {" + + " private int value = 0;" + + " private static final AtomicIntegerFieldUpdater updater = " + + " AtomicIntegerFieldUpdater.newUpdater(A.class, /*Field 'value' does not have 'volatile' modifier*/\"value\"/**/);" + + "}"); + } + + public void testFieldNotFound() { + doTest("import java.util.concurrent.atomic.AtomicIntegerFieldUpdater;" + + "class Z {" + + " volatile int value = 0;" + + "}" + + "class A extends Z {" + + " private static final AtomicIntegerFieldUpdater updater = " + + " AtomicIntegerFieldUpdater.newUpdater(A.class, /*No field named 'value' found in class 'A'*/\"value\"/**/);" + + "}"); + } + + public void testWrongType1() { + doTest("import java.util.concurrent.atomic.AtomicIntegerFieldUpdater;" + + "class A {" + + " private volatile long value = 0;" + + " private static final AtomicIntegerFieldUpdater updater = " + + " AtomicIntegerFieldUpdater.newUpdater(A.class, /*Field 'value' does not have type 'int'*/\"value\"/**/);" + + "}"); + } + + public void testWrongType2() { + doTest("import java.util.concurrent.atomic.AtomicLongFieldUpdater;" + + "class A {" + + " private volatile int value = 0;" + + " private static final AtomicLongFieldUpdater updater = " + + " AtomicLongFieldUpdater.newUpdater(A.class, /*Field 'value' does not have type 'long'*/\"value\"/**/);" + + "}"); + } + + public void testWrongType3() { + doTest("import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;" + + "class A {" + + " private volatile int[] value = new int[]{0};" + + " private static final AtomicReferenceFieldUpdater updater = " + + " AtomicReferenceFieldUpdater.newUpdater(A.class, long[].class, /*Field 'value' does not have type 'long[]'*/\"value\"/**/);" + + "}"); + } + + public void testNotAccessible1() { + doTest("import java.util.concurrent.atomic.AtomicIntegerFieldUpdater;" + + "class Z {" + + " private volatile int value = 0;" + + "}" + + "class A {" + + " private static final AtomicIntegerFieldUpdater updater = " + + " AtomicIntegerFieldUpdater.newUpdater(Z.class, /*'private' field 'value' is not accessible from here*/\"value\"/**/);" + + "}"); + } + + @Nullable + @Override + protected InspectionProfileEntry getInspection() { + return new AtomicFieldUpdaterIssuesInspection(); + } +} \ No newline at end of file