inspections about concurrency:annotated with @GuardedBy; @Immutable

This commit is contained in:
anna
2009-11-10 12:18:55 +03:00
parent e292ecd338
commit e31b3fcca4
19 changed files with 988 additions and 1 deletions
+1
View File
@@ -26,6 +26,7 @@
<orderEntry type="module" module-name="dom-impl" />
<orderEntry type="module" module-name="vcs-impl" />
<orderEntry type="module" module-name="icons" />
<orderEntry type="library" name="jcip" level="project" />
</component>
<component name="copyright">
<Base>
@@ -0,0 +1,93 @@
/*
* Copyright 2000-2009 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.intellij.codeInspection.concurrencyAnnotations;
import com.intellij.codeInsight.daemon.GroupNames;
import com.intellij.codeInspection.BaseJavaLocalInspectionTool;
import com.intellij.codeInspection.ProblemsHolder;
import com.intellij.psi.*;
import com.intellij.psi.util.PsiTreeUtil;
import org.jetbrains.annotations.Nls;
import org.jetbrains.annotations.NotNull;
public class FieldAccessNotGuardedInspection extends BaseJavaLocalInspectionTool {
@NotNull
public String getGroupDisplayName() {
return GroupNames.CONCURRENCY_ANNOTATION_ISSUES;
}
@Nls
@NotNull
public String getDisplayName() {
return "Unguarded field access";
}
@NotNull
public String getShortName() {
return "FieldAccessNotGuarded";
}
@NotNull
public PsiElementVisitor buildVisitor(@NotNull ProblemsHolder holder, boolean isOnTheFly) {
return new Visitor(holder);
}
private static class Visitor extends JavaElementVisitor {
private final ProblemsHolder myHolder;
public Visitor(ProblemsHolder holder) {
myHolder = holder;
}
public void visitReferenceExpression(PsiReferenceExpression expression) {
final PsiElement referent = expression.resolve();
if (referent == null || !(referent instanceof PsiField)) {
return;
}
final PsiField field = (PsiField)referent;
final String guard = JCiPUtil.findGuardForMember(field);
if (guard == null) {
return;
}
final PsiMethod containingMethod = PsiTreeUtil.getParentOfType(expression, PsiMethod.class);
if (containingMethod != null && JCiPUtil.isGuardedBy(containingMethod, guard)) {
return;
}
if ("this".equals(guard)) {
if (containingMethod != null && containingMethod.hasModifierProperty(PsiModifier.SYNCHRONIZED)) {
return;
}
}
PsiElement check = expression;
while (true) {
final PsiSynchronizedStatement syncStatement = PsiTreeUtil.getParentOfType(check, PsiSynchronizedStatement.class);
if (syncStatement == null) {
break;
}
final PsiExpression lockExpression = syncStatement.getLockExpression();
if (lockExpression != null && lockExpression.getText().equals(guard)) //TODO: this isn't quite right,
{
return;
}
check = syncStatement;
}
//TODO: see if there is a lock via a .lock* call
myHolder.registerProblem(expression, "Access to field <code>#ref</code> outside of declared guards #loc");
}
}
}
@@ -0,0 +1,124 @@
/*
* Copyright 2000-2009 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.intellij.codeInspection.concurrencyAnnotations;
import com.intellij.codeInsight.daemon.GroupNames;
import com.intellij.codeInspection.BaseJavaLocalInspectionTool;
import com.intellij.codeInspection.ProblemsHolder;
import com.intellij.psi.*;
import com.intellij.psi.javadoc.PsiDocTag;
import com.intellij.psi.util.PsiTreeUtil;
import org.jetbrains.annotations.Nls;
import org.jetbrains.annotations.NotNull;
public class InstanceGuardedByStaticInspection extends BaseJavaLocalInspectionTool {
@NotNull
public String getGroupDisplayName() {
return GroupNames.CONCURRENCY_ANNOTATION_ISSUES;
}
@Nls
@NotNull
public String getDisplayName() {
return "Instance member guarded by static field";
}
@NotNull
public String getShortName() {
return "InstanceGuardedByStatic";
}
@NotNull
public PsiElementVisitor buildVisitor(@NotNull ProblemsHolder holder, boolean isOnTheFly) {
return new Visitor(holder);
}
private static class Visitor extends JavaElementVisitor {
private final ProblemsHolder myHolder;
public Visitor(ProblemsHolder holder) {
myHolder = holder;
}
public void visitDocTag(PsiDocTag psiDocTag) {
super.visitDocTag(psiDocTag);
if (!JCiPUtil.isGuardedByTag(psiDocTag)) {
return;
}
final PsiMember member = PsiTreeUtil.getParentOfType(psiDocTag, PsiMember.class);
if (member == null) {
return;
}
if (member.hasModifierProperty(PsiModifier.STATIC)) {
return;
}
final String guardValue = JCiPUtil.getGuardValue(psiDocTag);
final PsiClass containingClass = PsiTreeUtil.getParentOfType(psiDocTag, PsiClass.class);
if (containingClass == null) {
return;
}
final PsiField guardField = containingClass.findFieldByName(guardValue, true);
if (guardField == null) {
return;
}
if (!guardField.hasModifierProperty(PsiModifier.STATIC)) {
return;
}
myHolder.registerProblem(psiDocTag, "Instance member guarded by static \"" + guardValue + "\" #loc");
}
public void visitReferenceExpression(PsiReferenceExpression expression) {
}
public void visitAnnotation(PsiAnnotation annotation) {
super.visitAnnotation(annotation);
if (!JCiPUtil.isGuardedByAnnotation(annotation)) {
return;
}
final PsiMember member = PsiTreeUtil.getParentOfType(annotation, PsiMember.class);
if (member == null) {
return;
}
if (member.hasModifierProperty(PsiModifier.STATIC)) {
return;
}
final String guardValue = JCiPUtil.getGuardValue(annotation);
if (guardValue == null) {
return;
}
final PsiAnnotationMemberValue guardRef = annotation.findAttributeValue("value");
if (guardRef == null) {
return;
}
final PsiClass containingClass = PsiTreeUtil.getParentOfType(annotation, PsiClass.class);
if (containingClass == null) {
return;
}
final PsiField guardField = containingClass.findFieldByName(guardValue, true);
if (guardField == null) {
return;
}
if (!guardField.hasModifierProperty(PsiModifier.STATIC)) {
return;
}
myHolder.registerProblem(guardRef, "Instance member guarded by static #ref #loc");
}
}
}
@@ -0,0 +1,86 @@
/*
* Copyright 2000-2009 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.
*/
/*
* User: anna
* Date: 30-Jul-2007
*/
package com.intellij.codeInspection.concurrencyAnnotations;
import com.intellij.codeInsight.TargetElementUtil;
import com.intellij.codeInsight.daemon.impl.quickfix.OrderEntryFix;
import com.intellij.codeInsight.intention.IntentionAction;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.module.ModuleUtil;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.roots.ProjectFileIndex;
import com.intellij.openapi.roots.ProjectRootManager;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.*;
import com.intellij.psi.util.PsiUtil;
import com.intellij.util.IncorrectOperationException;
import com.intellij.util.PathUtil;
import net.jcip.annotations.GuardedBy;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
public class JCiPOrderEntryFix implements IntentionAction {
private static final Logger LOG = Logger.getInstance("#" + JCiPOrderEntryFix.class.getName());
@NotNull
public String getText() {
return "Add jcip-annotations.jar to classpath";
}
@NotNull
public String getFamilyName() {
return getText();
}
public boolean isAvailable(@NotNull final Project project, final Editor editor, final PsiFile file) {
if (!(file instanceof PsiJavaFile)) return false;
final PsiReference reference = TargetElementUtil.findReference(editor);
if (!(reference instanceof PsiJavaCodeReferenceElement)) return false;
if (reference.resolve() != null) return false;
@NonNls final String referenceName = ((PsiJavaCodeReferenceElement)reference).getReferenceName();
if (referenceName == null) return false;
final ProjectFileIndex fileIndex = ProjectRootManager.getInstance(project).getFileIndex();
final VirtualFile virtualFile = file.getVirtualFile();
if (virtualFile == null) return false;
if (fileIndex.getModuleForFile(virtualFile) == null) return false;
if (!(((PsiJavaCodeReferenceElement)reference).getParent() instanceof PsiAnnotation &&
PsiUtil.isLanguageLevel5OrHigher(((PsiJavaCodeReferenceElement)reference)))) return false;
if (!JCiPUtil.isJCiPAnnotation(referenceName)) return false;
return true;
}
public void invoke(@NotNull final Project project, final Editor editor, final PsiFile file) throws IncorrectOperationException {
final PsiJavaCodeReferenceElement reference = (PsiJavaCodeReferenceElement)TargetElementUtil.findReference(editor);
LOG.assertTrue(reference != null);
String jarPath = PathUtil.getJarPathForClass(GuardedBy.class);
final VirtualFile virtualFile = file.getVirtualFile();
LOG.assertTrue(virtualFile != null);
OrderEntryFix.addBundledJarToRoots(project, editor, ModuleUtil.findModuleForFile(virtualFile, project), reference,
"net.jcip.annotations." + reference.getReferenceName(), jarPath);
}
public boolean startInWriteAction() {
return true;
}
}
@@ -0,0 +1,151 @@
/*
* Copyright 2000-2009 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.intellij.codeInspection.concurrencyAnnotations;
import com.intellij.codeInsight.AnnotationUtil;
import com.intellij.psi.*;
import com.intellij.psi.javadoc.PsiDocTag;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public class JCiPUtil {
@NonNls
private static final String IMMUTABLE = "net.jcip.annotations.Immutable";
@NonNls
private static final String GUARDED_BY = "net.jcip.annotations.GuardedBy";
@NonNls
private static final String THREAD_SAFE = "net.jcip.annotations.ThreadSafe";
public static boolean isJCiPAnnotation(String ref) {
return "Immutable".equals(ref) || "GuardedBy".equals(ref) || "ThreadSafe".equals("ref");
}
private JCiPUtil() {
}
public static boolean isImmutable(PsiClass aClass) {
final PsiAnnotation annotation = AnnotationUtil.findAnnotation(aClass, IMMUTABLE);
if (annotation != null) {
return true;
}
final ImmutableTagVisitor visitor = new ImmutableTagVisitor();
aClass.accept(visitor);
return visitor.isFound();
}
@Nullable
public static String findGuardForMember(PsiMember member) {
final PsiAnnotation annotation = AnnotationUtil.findAnnotation(member, GUARDED_BY);
if (annotation != null) {
return getGuardValue(annotation);
}
final GuardedTagVisitor visitor = new GuardedTagVisitor();
member.accept(visitor);
return visitor.getGuardString();
}
public static boolean isGuardedBy(PsiMember member, String guard) {
final PsiAnnotation annotation = AnnotationUtil.findAnnotation(member, GUARDED_BY);
if (annotation != null) {
final PsiAnnotationParameterList parameters = annotation.getParameterList();
final PsiNameValuePair[] pairs = parameters.getAttributes();
final String fieldName = '"' + guard + '"';
for (PsiNameValuePair pair : pairs) {
final String name = pair.getName();
if (("value".equals(name) || name == null)) {
final PsiAnnotationMemberValue value = pair.getValue();
if (value != null && value.getText().equals(fieldName)) {
return true;
}
}
}
}
return false;
}
public static boolean isGuardedBy(PsiMember member, PsiField field) {
return isGuardedBy(member, field.getName());
}
public static boolean isGuardedByAnnotation(PsiAnnotation annotation) {
return GUARDED_BY.equals(annotation.getQualifiedName());
}
public static boolean isGuardedByTag(PsiDocTag tag) {
final String text = tag.getText();
return text.startsWith("@GuardedBy") && text.contains("(") && text.contains(")");
}
@Nullable
public static String getGuardValue(PsiAnnotation annotation) {
final PsiAnnotationParameterList parameters = annotation.getParameterList();
final PsiNameValuePair[] pairs = parameters.getAttributes();
for (PsiNameValuePair pair : pairs) {
final String name = pair.getName();
if ("value".equals(name) || name == null) {
final PsiAnnotationMemberValue psiAnnotationMemberValue = pair.getValue();
if (psiAnnotationMemberValue != null) {
final String value = psiAnnotationMemberValue.getText();
return value.substring(1, value.length() - 1).trim();
}
}
}
return null;
}
@NotNull
public static String getGuardValue(PsiDocTag tag) {
final String text = tag.getText();
return text.substring(text.indexOf((int)'(') + 1, text.indexOf((int)')')).trim();
}
private static class GuardedTagVisitor extends JavaRecursiveElementVisitor {
private String guardString = null;
public void visitDocTag(PsiDocTag tag) {
super.visitDocTag(tag);
final String text = tag.getText();
if (text.startsWith("@GuardedBy") && text.contains("(") && text.contains(")")) {
guardString = text.substring(text.indexOf((int)'(') + 1, text.indexOf((int)')'));
}
}
@Nullable
public String getGuardString() {
return guardString;
}
}
private static class ImmutableTagVisitor extends JavaRecursiveElementVisitor {
private boolean found = false;
public void visitDocTag(PsiDocTag tag) {
super.visitDocTag(tag);
final String text = tag.getText();
if (text.startsWith("@Immutable")) {
found = true;
}
}
public boolean isFound() {
return found;
}
}
}
@@ -0,0 +1,63 @@
/*
* Copyright 2000-2009 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.intellij.codeInspection.concurrencyAnnotations;
import com.intellij.codeInsight.daemon.GroupNames;
import com.intellij.codeInspection.BaseJavaLocalInspectionTool;
import com.intellij.codeInspection.ProblemsHolder;
import com.intellij.psi.*;
import org.jetbrains.annotations.Nls;
import org.jetbrains.annotations.NotNull;
public class NonFinalFieldInImmutableInspection extends BaseJavaLocalInspectionTool {
@NotNull
public String getGroupDisplayName() {
return GroupNames.CONCURRENCY_ANNOTATION_ISSUES;
}
@Nls
@NotNull
public String getDisplayName() {
return "Non-final field in @Immutable class";
}
@NotNull
public String getShortName() {
return "NonFinalFieldInImmutable";
}
@NotNull
public PsiElementVisitor buildVisitor(@NotNull final ProblemsHolder holder, boolean isOnTheFly) {
return new JavaElementVisitor() {
public void visitField(PsiField field) {
super.visitField(field);
if (field.hasModifierProperty(PsiModifier.FINAL)) {
return;
}
final PsiClass containingClass = field.getContainingClass();
if (!JCiPUtil.isImmutable(containingClass)) {
return;
}
holder.registerProblem(field, "Non-final field #ref in @Immutable class #loc");
}
public void visitReferenceExpression(PsiReferenceExpression expression) {
}
};
}
}
@@ -0,0 +1,112 @@
/*
* Copyright 2000-2009 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.intellij.codeInspection.concurrencyAnnotations;
import com.intellij.codeInsight.daemon.GroupNames;
import com.intellij.codeInspection.BaseJavaLocalInspectionTool;
import com.intellij.codeInspection.ProblemsHolder;
import com.intellij.psi.*;
import com.intellij.psi.javadoc.PsiDocTag;
import com.intellij.psi.util.PsiTreeUtil;
import org.jetbrains.annotations.Nls;
import org.jetbrains.annotations.NotNull;
public class NonFinalGuardInspection extends BaseJavaLocalInspectionTool {
@NotNull
public String getGroupDisplayName() {
return GroupNames.CONCURRENCY_ANNOTATION_ISSUES;
}
@Nls
@NotNull
public String getDisplayName() {
return "Non-final @GuardedBy field";
}
@NotNull
public String getShortName() {
return "NonFinalGuard";
}
@NotNull
public PsiElementVisitor buildVisitor(@NotNull ProblemsHolder holder, boolean isOnTheFly) {
return new Visitor(holder);
}
private static class Visitor extends JavaElementVisitor {
private final ProblemsHolder myHolder;
public Visitor(ProblemsHolder holder) {
myHolder = holder;
}
public void visitAnnotation(PsiAnnotation annotation) {
super.visitAnnotation(annotation);
if (!JCiPUtil.isGuardedByAnnotation(annotation)) {
return;
}
final String guardValue = JCiPUtil.getGuardValue(annotation);
if (guardValue == null || "this".equals(guardValue)) {
return;
}
final PsiClass containingClass = PsiTreeUtil.getParentOfType(annotation, PsiClass.class);
if (containingClass == null) {
return;
}
final PsiField guardField = containingClass.findFieldByName(guardValue, true);
if (guardField == null) {
return;
}
if (guardField.hasModifierProperty(PsiModifier.FINAL)) {
return;
}
final PsiAnnotationMemberValue member = annotation.findAttributeValue("value");
if (member == null) {
return;
}
myHolder.registerProblem(member, "Non-final @GuardedBy field #ref #loc");
}
public void visitDocTag(PsiDocTag psiDocTag) {
super.visitDocTag(psiDocTag);
if (!JCiPUtil.isGuardedByTag(psiDocTag)) {
return;
}
final String guardValue = JCiPUtil.getGuardValue(psiDocTag);
if ("this".equals(guardValue)) {
return;
}
final PsiClass containingClass = PsiTreeUtil.getParentOfType(psiDocTag, PsiClass.class);
if (containingClass == null) {
return;
}
final PsiField guardField = containingClass.findFieldByName(guardValue, true);
if (guardField == null) {
return;
}
if (guardField.hasModifierProperty(PsiModifier.FINAL)) {
return;
}
myHolder.registerProblem(psiDocTag, "Non-final @GuardedBy field \"" + guardValue + "\" #loc");
}
public void visitReferenceExpression(PsiReferenceExpression expression) {
}
}
}
@@ -0,0 +1,133 @@
/*
* Copyright 2000-2009 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.intellij.codeInspection.concurrencyAnnotations;
import com.intellij.codeInsight.daemon.GroupNames;
import com.intellij.codeInspection.BaseJavaLocalInspectionTool;
import com.intellij.codeInspection.ProblemsHolder;
import com.intellij.psi.*;
import com.intellij.psi.javadoc.PsiDocTag;
import com.intellij.psi.util.PsiTreeUtil;
import org.jetbrains.annotations.Nls;
import org.jetbrains.annotations.NotNull;
public class StaticGuardedByInstanceInspection extends BaseJavaLocalInspectionTool {
@NotNull
public String getGroupDisplayName() {
return GroupNames.CONCURRENCY_ANNOTATION_ISSUES;
}
@Nls
@NotNull
public String getDisplayName() {
return "Static member guarded by instance field or this";
}
@NotNull
public String getShortName() {
return "StaticGuardedByInstance";
}
@NotNull
public PsiElementVisitor buildVisitor(@NotNull ProblemsHolder holder, boolean isOnTheFly) {
return new Visitor(holder);
}
private static class Visitor extends JavaElementVisitor {
private final ProblemsHolder myHolder;
public Visitor(ProblemsHolder holder) {
myHolder = holder;
}
public void visitAnnotation(PsiAnnotation annotation) {
super.visitAnnotation(annotation);
if (!JCiPUtil.isGuardedByAnnotation(annotation)) {
return;
}
final PsiMember member = PsiTreeUtil.getParentOfType(annotation, PsiMember.class);
if (member == null) {
return;
}
if (!member.hasModifierProperty(PsiModifier.STATIC)) {
return;
}
final String guardValue = JCiPUtil.getGuardValue(annotation);
if (guardValue == null) {
return;
}
final PsiAnnotationMemberValue guardRef = annotation.findAttributeValue("value");
if (guardRef == null) {
return;
}
if ("this".equals(guardValue)) {
registerError(guardRef);
}
final PsiClass containingClass = PsiTreeUtil.getParentOfType(annotation, PsiClass.class);
if (containingClass == null) {
return;
}
final PsiField guardField = containingClass.findFieldByName(guardValue, true);
if (guardField == null) {
return;
}
if (guardField.hasModifierProperty(PsiModifier.STATIC)) {
return;
}
registerError(guardRef);
}
public void visitDocTag(PsiDocTag psiDocTag) {
super.visitDocTag(psiDocTag);
if (!JCiPUtil.isGuardedByTag(psiDocTag)) {
return;
}
final PsiMember member = PsiTreeUtil.getParentOfType(psiDocTag, PsiMember.class);
if (member == null) {
return;
}
if (!member.hasModifierProperty(PsiModifier.STATIC)) {
return;
}
final String guardValue = JCiPUtil.getGuardValue(psiDocTag);
if ("this".equals(guardValue)) {
registerError(psiDocTag);
}
final PsiClass containingClass = PsiTreeUtil.getParentOfType(psiDocTag, PsiClass.class);
if (containingClass == null) {
return;
}
final PsiField guardField = containingClass.findFieldByName(guardValue, true);
if (guardField == null) {
return;
}
if (guardField.hasModifierProperty(PsiModifier.STATIC)) {
return;
}
myHolder.registerProblem(psiDocTag, "Static member guarded by instance \"" + guardValue + "\" #loc");
}
private void registerError(PsiElement element) {
myHolder.registerProblem(element, "Static member guarded by instance #ref #loc");
}
public void visitReferenceExpression(PsiReferenceExpression expression) {
}
}
}
@@ -0,0 +1,104 @@
/*
* Copyright 2000-2009 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.intellij.codeInspection.concurrencyAnnotations;
import com.intellij.codeInsight.daemon.GroupNames;
import com.intellij.codeInspection.BaseJavaLocalInspectionTool;
import com.intellij.codeInspection.ProblemsHolder;
import com.intellij.psi.*;
import com.intellij.psi.javadoc.PsiDocTag;
import com.intellij.psi.util.PsiTreeUtil;
import org.jetbrains.annotations.Nls;
import org.jetbrains.annotations.NotNull;
public class UnknownGuardInspection extends BaseJavaLocalInspectionTool {
@NotNull
public String getGroupDisplayName() {
return GroupNames.CONCURRENCY_ANNOTATION_ISSUES;
}
@Nls
@NotNull
public String getDisplayName() {
return "Unknown @GuardedBy field";
}
@NotNull
public String getShortName() {
return "UnknownGuard";
}
@NotNull
public PsiElementVisitor buildVisitor(@NotNull ProblemsHolder holder, boolean isOnTheFly) {
return new Visitor(holder);
}
private static class Visitor extends JavaElementVisitor {
private final ProblemsHolder myHolder;
public Visitor(ProblemsHolder holder) {
myHolder = holder;
}
public void visitAnnotation(PsiAnnotation annotation) {
super.visitAnnotation(annotation);
if (!JCiPUtil.isGuardedByAnnotation(annotation)) {
return;
}
final String guardValue = JCiPUtil.getGuardValue(annotation);
if (guardValue == null || "this".equals(guardValue)) {
return;
}
final PsiClass containingClass = PsiTreeUtil.getParentOfType(annotation, PsiClass.class);
if (containingClass == null) {
return;
}
final PsiField guardField = containingClass.findFieldByName(guardValue, true);
if (guardField != null) {
return;
}
final PsiAnnotationMemberValue member = annotation.findAttributeValue("value");
if (member == null) {
return;
}
myHolder.registerProblem(member, "Unknown @GuardedBy field #ref #loc");
}
public void visitDocTag(PsiDocTag psiDocTag) {
super.visitDocTag(psiDocTag);
if (!JCiPUtil.isGuardedByTag(psiDocTag)) {
return;
}
final String guardValue = JCiPUtil.getGuardValue(psiDocTag);
if ("this".equals(guardValue)) {
return;
}
final PsiClass containingClass = PsiTreeUtil.getParentOfType(psiDocTag, PsiClass.class);
if (containingClass == null) {
return;
}
final PsiField guardField = containingClass.findFieldByName(guardValue, true);
if (guardField != null) {
return;
}
myHolder.registerProblem(psiDocTag, "Unknown @GuardedBy field \"" + guardValue + "\" #loc");
}
public void visitReferenceExpression(PsiReferenceExpression expression) {
}
}
}
@@ -20,6 +20,7 @@ import com.intellij.codeInspection.LossyEncodingInspection;
import com.intellij.codeInspection.RedundantSuppressInspection;
import com.intellij.codeInspection.accessStaticViaInstance.AccessStaticViaInstance;
import com.intellij.codeInspection.canBeFinal.CanBeFinalInspection;
import com.intellij.codeInspection.concurrencyAnnotations.*;
import com.intellij.codeInspection.dataFlow.DataFlowInspection;
import com.intellij.codeInspection.deadCode.DeadCodeInspection;
import com.intellij.codeInspection.defUse.DefUseInspection;
@@ -108,7 +109,14 @@ public class StandardInspectionToolsProvider implements InspectionToolProvider {
UncheckedWarningLocalInspection.class,
SuspiciousNameCombinationInspection.class,
DuplicateThrowsInspection.class,
LossyEncodingInspection.class
LossyEncodingInspection.class,
FieldAccessNotGuardedInspection.class,
InstanceGuardedByStaticInspection.class,
NonFinalFieldInImmutableInspection.class,
NonFinalGuardInspection.class,
StaticGuardedByInstanceInspection.class,
UnknownGuardInspection.class
};
}
}
@@ -66,4 +66,5 @@ public interface GroupNames {
String MODULARIZATION_GROUP_NAME = InspectionsBundle.message("group.names.modularization.issues");
String JAVAEE_GROUP_NAME = InspectionsBundle.message("group.names.javaee.issues");
String CONCURRENCY_ANNOTATION_ISSUES = "Concurrency annotation issues";
}