diff --git a/java/java-analysis-api/resources/messages/JavaAnalysisBundle.properties b/java/java-analysis-api/resources/messages/JavaAnalysisBundle.properties index a73cc6b97596..ba30ba12af2e 100644 --- a/java/java-analysis-api/resources/messages/JavaAnalysisBundle.properties +++ b/java/java-analysis-api/resources/messages/JavaAnalysisBundle.properties @@ -148,6 +148,7 @@ scope.package=Package {0} 0.field.is.always.initialized.not.null=@{0} field is always initialized not-null access.can.be.0=Access can be {0} access.to.field.code.ref.code.outside.of.declared.guards.loc=Access to field #ref outside of declared guards #loc +call.to.method.code.ref.code.outside.of.declared.guards.loc=Call to method #ref() outside of declared guards #loc annotate.as.safevarargs=Annotate as @SafeVarargs annotate.overridden.methods.parameters.family.name=Annotate overridden method parameters annotate.overridden.methods.parameters=Annotate overridden method parameters as ''@{0}'' diff --git a/java/java-analysis-impl/src/META-INF/JavaAnalysisPlugin.xml b/java/java-analysis-impl/src/META-INF/JavaAnalysisPlugin.xml index 891ddc6b6fa7..e0f0d9d59992 100644 --- a/java/java-analysis-impl/src/META-INF/JavaAnalysisPlugin.xml +++ b/java/java-analysis-impl/src/META-INF/JavaAnalysisPlugin.xml @@ -145,7 +145,7 @@ - annotations = ConcurrencyAnnotationsManager.getInstance(member.getProject()).getGuardedByAnnotations(); + final PsiAnnotation annotation = AnnotationUtil.findAnnotation(member, annotations); if (annotation != null) { return getGuardValue(annotation); } - if (member instanceof PsiCompiledElement) { - member = (PsiMember)member.getNavigationElement(); - if (member == null || member instanceof PsiCompiledElement) { - return null; // can't analyze compiled code + if (member instanceof PsiDocCommentOwner) { + PsiDocCommentOwner commentOwner = (PsiDocCommentOwner)member; + PsiDocComment comment = commentOwner.getDocComment(); + if (comment != null) { + PsiDocTag[] tags = comment.getTags(); + for (int i = tags.length - 1; i >= 0; i--) { + String value = getGuardValue(tags[i]); + if (value != null) { + return value; + } + } } } - final GuardedTagVisitor visitor = new GuardedTagVisitor(); - member.accept(visitor); - return visitor.getGuardString(); + return null; } static boolean isGuardedBy(@NotNull PsiMember member, @NotNull String guard) { @@ -81,18 +74,12 @@ public class JCiPUtil { return annotation != null && guard.equals(getGuardValue(annotation)); } - public static boolean isGuardedBy(PsiMember member, PsiField field) { - return isGuardedBy(member, field.getName()); - } - static boolean isGuardedByAnnotation(@NotNull PsiAnnotation annotation) { return ConcurrencyAnnotationsManager.getInstance(annotation.getProject()).getGuardedByAnnotations().contains(annotation.getQualifiedName()); } static boolean isGuardedByTag(PsiDocTag tag) { - final String text = tag.getText(); - - return text.startsWith("@GuardedBy") && text.contains("(") && text.contains(")"); + return tag.getText().startsWith("@GuardedBy"); } @Nullable @@ -100,38 +87,38 @@ public class JCiPUtil { final PsiAnnotationMemberValue psiAnnotationMemberValue = annotation.findAttributeValue("value"); if (psiAnnotationMemberValue instanceof PsiLiteralExpression) { final Object value = ((PsiLiteralExpression)psiAnnotationMemberValue).getValue(); - if ("itself".equals(value)) { - final PsiMember member = PsiTreeUtil.getParentOfType(annotation, PsiMember.class); - if (member != null) return member.getName(); - } if (value instanceof String) { - return (String)value; + return resolveItself((String)value, annotation); } } return null; } - @NotNull + @Nullable static String getGuardValue(PsiDocTag tag) { - final String text = tag.getText(); - return text.substring(text.indexOf((int)'(') + 1, text.indexOf((int)')')).trim(); + if ("GuardedBy".equals(tag.getName())) { + final PsiDocTagValue value = tag.getValueElement(); + if (value == null) return ""; + return resolveItself(value.getText(), tag); + } + else { + final String text = tag.getText(); + if (!text.startsWith("@GuardedBy")) return null; + int start = text.indexOf('('); + int end = text.indexOf(')'); + if (start >= end || start < 0) return ""; + return resolveItself(text.substring(start + 1, end), tag); + } } - private static class GuardedTagVisitor extends JavaRecursiveElementWalkingVisitor { - private String guardString; - - @Override - 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)')')); + private static String resolveItself(String value, PsiElement context) { + if ("itself".equals(value)) { + final PsiMember member = PsiTreeUtil.getParentOfType(context, PsiMember.class); + if (!(member instanceof PsiField)) { + return "itself"; } + return member.getName(); } - - @Nullable - private String getGuardString() { - return guardString; - } + return value; } } diff --git a/java/java-tests/testData/inspection/guarded/fieldAccessNotGuarded.java b/java/java-tests/testData/inspection/guarded/fieldAccessNotGuarded.java index 412352f2940c..43a32bb07059 100644 --- a/java/java-tests/testData/inspection/guarded/fieldAccessNotGuarded.java +++ b/java/java-tests/testData/inspection/guarded/fieldAccessNotGuarded.java @@ -114,4 +114,18 @@ class Example4 { Object o = field; } } +} +class No { + + @GuardedBy("this") + void x() { + notify(); + } + + void y() { + x(); // warn here + } + synchronized void z() { + x(); // don't warn here + } } \ No newline at end of file diff --git a/java/java-tests/testData/inspection/unknownGuard/UnknownGuard.java b/java/java-tests/testData/inspection/unknownGuard/UnknownGuard.java index d30dfca2a763..cc67c67aa63a 100644 --- a/java/java-tests/testData/inspection/unknownGuard/UnknownGuard.java +++ b/java/java-tests/testData/inspection/unknownGuard/UnknownGuard.java @@ -80,4 +80,12 @@ class UnknownGuard { @GuardedBy("Nothing.LOCK") private Object twentytwo = new Object(); + + /** + * @GuardedBy itself + */ + private Object twentythree = new Object(); + + @GuardedBy("itself") + private void method() {} } \ No newline at end of file