mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
inspections about concurrency:annotated with @GuardedBy; @Immutable
This commit is contained in:
@@ -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>
|
||||
|
||||
+93
@@ -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");
|
||||
}
|
||||
}
|
||||
}
|
||||
+124
@@ -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");
|
||||
}
|
||||
}
|
||||
}
|
||||
+86
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
+63
@@ -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) {
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
+112
@@ -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) {
|
||||
}
|
||||
}
|
||||
}
|
||||
+133
@@ -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) {
|
||||
}
|
||||
}
|
||||
}
|
||||
+104
@@ -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) {
|
||||
}
|
||||
}
|
||||
}
|
||||
+9
-1
@@ -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";
|
||||
}
|
||||
|
||||
Binary file not shown.
@@ -0,0 +1,16 @@
|
||||
<html>
|
||||
<body>
|
||||
<table>
|
||||
<tr>
|
||||
<td valign="top" height="150">
|
||||
<font face="verdana" size="-1">
|
||||
This inspection reports any accesses of fields declared as @net.jcip.annotations.GuardedBy
|
||||
which are are not guarded by an appropriate synchronization structure.
|
||||
</font></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td height="20"><font face="verdana" size="-2">New in 9</font></td>
|
||||
</tr>
|
||||
</table>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,20 @@
|
||||
<html>
|
||||
<body>
|
||||
<table>
|
||||
<tr>
|
||||
<td valign="top" height="150">
|
||||
<font face="verdana" size="-1">
|
||||
This inspection reports any @net.jcip.annotations.GuardedBy annotations on instance fields or methods,
|
||||
where
|
||||
the guard is a static field. Guarding a non-static by a static may result in excessive lock contention,
|
||||
as access to each locked field in any object instance will prevent simultaneous access to that field in
|
||||
every object
|
||||
instance.
|
||||
</font></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td height="20"><font face="verdana" size="-2">New in 9</font></td>
|
||||
</tr>
|
||||
</table>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,17 @@
|
||||
<html>
|
||||
<body>
|
||||
<table>
|
||||
<tr>
|
||||
<td valign="top" height="150">
|
||||
<font face="verdana" size="-1">
|
||||
This inspection reports any non-final field in a class with annotation
|
||||
@net.jcip.annotations.Immutable. This violates the contract of the @Immutable
|
||||
annotation.
|
||||
</font></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td height="20"><font face="verdana" size="-2">New in 9</font></td>
|
||||
</tr>
|
||||
</table>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,17 @@
|
||||
<html>
|
||||
<body>
|
||||
<table>
|
||||
<tr>
|
||||
<td valign="top" height="150">
|
||||
<font face="verdana" size="-1">
|
||||
This inspection reports any @net.jcip.annotations.GuardedBy annotations where the guarding field
|
||||
is not final. Gaurding on a non-final field may result in unexpected race conditions, as locks will
|
||||
be held on the value of the field (which may change), rather than the field itself.
|
||||
</font></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td height="20"><font face="verdana" size="-2">New in 9</font></td>
|
||||
</tr>
|
||||
</table>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,21 @@
|
||||
<html>
|
||||
<body>
|
||||
<table>
|
||||
<tr>
|
||||
<td valign="top" height="150">
|
||||
<font face="verdana" size="-1">
|
||||
This inspection reports any @net.jcip.annotations.GuardedBy annotations on static fields or methods,
|
||||
where
|
||||
the guard is either a non-static field or 'this'. Guarding a static by a non-static may result in
|
||||
excessive
|
||||
concurrency, multiple threads may be able to access the guarded field simultaneously, by locking in
|
||||
different
|
||||
object contexts.
|
||||
</font></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td height="20"><font face="verdana" size="-2">New in 9</font></td>
|
||||
</tr>
|
||||
</table>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,16 @@
|
||||
<html>
|
||||
<body>
|
||||
<table>
|
||||
<tr>
|
||||
<td valign="top" height="150">
|
||||
<font face="verdana" size="-1">
|
||||
This inspection reports any @net.jcip.annotations.GuardedBy annotations where the guarding field
|
||||
is unknown.
|
||||
</font></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td height="20"><font face="verdana" size="-2">New in 9</font></td>
|
||||
</tr>
|
||||
</table>
|
||||
</body>
|
||||
</html>
|
||||
@@ -557,6 +557,10 @@
|
||||
<className>com.intellij.testIntegration.createTest.CreateTestAction</className>
|
||||
</intentionAction>
|
||||
|
||||
<intentionAction>
|
||||
<className>com.intellij.codeInspection.concurrencyAnnotations.JCiPOrderEntryFix</className>
|
||||
</intentionAction>
|
||||
|
||||
|
||||
<daemon.highlightInfoFilter implementation="com.intellij.debugger.engine.evaluation.DebuggerHighlightFilter"/>
|
||||
<daemon.highlightInfoFilter implementation="com.intellij.codeInsight.daemon.impl.HighlightInfoFilterImpl"/>
|
||||
|
||||
Reference in New Issue
Block a user