mirror of
https://gitflic.ru/project/openide/openide.git
synced 2025-12-13 15:52:01 +07:00
add "pure" attribute to @Contract (IDEA-107864)
This commit is contained in:
@@ -42,7 +42,7 @@ import static com.intellij.codeInsight.ConditionChecker.Type.*;
|
||||
import static com.intellij.codeInspection.dataFlow.MethodContract.ValueConstraint;
|
||||
import static com.intellij.psi.CommonClassNames.*;
|
||||
|
||||
class ControlFlowAnalyzer extends JavaElementVisitor {
|
||||
public class ControlFlowAnalyzer extends JavaElementVisitor {
|
||||
private static final Logger LOG = Logger.getInstance("#com.intellij.codeInspection.dataFlow.ControlFlowAnalyzer");
|
||||
public static final String ORG_JETBRAINS_ANNOTATIONS_CONTRACT = Contract.class.getName();
|
||||
private boolean myIgnoreAssertions;
|
||||
|
||||
@@ -111,13 +111,21 @@ public class DataFlowInspectionBase extends BaseJavaBatchLocalInspectionTool {
|
||||
if (method == null) return;
|
||||
|
||||
String text = AnnotationUtil.getStringAttributeValue(annotation, null);
|
||||
if (text == null) return;
|
||||
if (StringUtil.isNotEmpty(text)) {
|
||||
String error = checkContract(method, text);
|
||||
if (error != null) {
|
||||
PsiAnnotationMemberValue value = annotation.findAttributeValue(null);
|
||||
assert value != null;
|
||||
holder.registerProblem(value, error);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
String error = checkContract(method, text);
|
||||
if (error != null) {
|
||||
PsiAnnotationMemberValue value = annotation.findAttributeValue(null);
|
||||
if (Boolean.TRUE.equals(AnnotationUtil.getBooleanAttributeValue(annotation, "pure")) &&
|
||||
PsiType.VOID.equals(method.getReturnType())) {
|
||||
PsiAnnotationMemberValue value = annotation.findDeclaredAttributeValue("pure");
|
||||
assert value != null;
|
||||
holder.registerProblem(value, error);
|
||||
holder.registerProblem(value, "Pure methods must return something, void is not allowed as a return type");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -46,4 +46,7 @@ public class AssertIsNotNull {
|
||||
|
||||
@Contract(<warning descr="Method takes 2 parameters, while contract clause number 1 expects 1">"null -> _"</warning>)
|
||||
void wrongParameterCount(Object a, boolean b) {}
|
||||
|
||||
@Contract(pure=<warning descr="Pure methods must return something, void is not allowed as a return type">true</warning>)
|
||||
void voidPureMethod() {}
|
||||
}
|
||||
|
||||
@@ -39,12 +39,6 @@ public class DataFlowInspectionTest extends LightCodeInsightFixtureTestCase {
|
||||
return JAVA_1_7;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setUp() throws Exception {
|
||||
super.setUp();
|
||||
myFixture.addClass("package org.jetbrains.annotations; public @interface Contract { String value(); }");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getTestDataPath() {
|
||||
return JavaTestUtil.getJavaTestDataPath() + "/inspection/dataFlow/fixture/";
|
||||
|
||||
Binary file not shown.
@@ -43,11 +43,19 @@ import java.lang.annotation.*;
|
||||
* <code>@Contract("_, null -> null; _, !null -> !null")</code> - method returns null if its second argument is null and not-null otherwise<br/>
|
||||
* <code>@Contract("true -> fail")</code> - a typical assertFalse method which throws an exception if <code>true</code> is passed to it<br/>
|
||||
*
|
||||
* @author peter
|
||||
*/
|
||||
@Documented
|
||||
@Retention(RetentionPolicy.CLASS)
|
||||
@Target(ElementType.METHOD)
|
||||
public @interface Contract {
|
||||
String value();
|
||||
/**
|
||||
* Contains the contract clauses describing causal relations between call arguments and the returned value
|
||||
*/
|
||||
String value() default "";
|
||||
|
||||
/**
|
||||
* Specifies if this method is pure, i.e. has no visible side effects. This may be used for more precise data flow analysis, and
|
||||
* to check that the method's return value is actually used in the call place.
|
||||
*/
|
||||
boolean pure() default false;
|
||||
}
|
||||
|
||||
@@ -15,6 +15,8 @@
|
||||
*/
|
||||
package com.siyeh.ig.bugs;
|
||||
|
||||
import com.intellij.codeInsight.AnnotationUtil;
|
||||
import com.intellij.codeInspection.dataFlow.ControlFlowAnalyzer;
|
||||
import com.intellij.openapi.util.InvalidDataException;
|
||||
import com.intellij.openapi.util.WriteExternalException;
|
||||
import com.intellij.psi.*;
|
||||
@@ -146,6 +148,13 @@ public class IgnoreResultOfCallInspectionBase extends BaseInspection {
|
||||
registerMethodCallError(call, aClass);
|
||||
return;
|
||||
}
|
||||
|
||||
PsiAnnotation contractAnnotation = ControlFlowAnalyzer.findContractAnnotation(method);
|
||||
if (contractAnnotation != null && Boolean.TRUE.equals(AnnotationUtil.getBooleanAttributeValue(contractAnnotation, "pure"))) {
|
||||
registerMethodCallError(call, aClass);
|
||||
return;
|
||||
}
|
||||
|
||||
final PsiReferenceExpression methodExpression = call.getMethodExpression();
|
||||
final String methodName = methodExpression.getReferenceName();
|
||||
if (methodName == null) {
|
||||
|
||||
@@ -12,15 +12,15 @@ public class IgnoreResultOfCallInspectionTest extends LightInspectionTestCase {
|
||||
|
||||
@Override
|
||||
protected String[] getEnvironmentClasses() {
|
||||
return new String[]{
|
||||
return [
|
||||
"package java.util.regex; public class Pattern {" +
|
||||
" public static Pattern compile(String regex) {return null;}" +
|
||||
" public Matcher matcher(CharSequence input) {return null;}" +
|
||||
"}",
|
||||
"package java.util.regex; public class Matcher {" +
|
||||
" public boolean find() {return true;}" +
|
||||
"}",
|
||||
};
|
||||
"}"
|
||||
] as String[]
|
||||
}
|
||||
|
||||
public void testObjectMethods() {
|
||||
@@ -41,4 +41,21 @@ public class IgnoreResultOfCallInspectionTest extends LightInspectionTestCase {
|
||||
" }\n" +
|
||||
"}\n");
|
||||
}
|
||||
|
||||
public void testPureMethod() {
|
||||
doTest """
|
||||
import org.jetbrains.annotations.Contract;
|
||||
|
||||
class Util {
|
||||
@Contract(pure=true)
|
||||
static Object util() { return null; }
|
||||
}
|
||||
|
||||
class C {
|
||||
{
|
||||
Util./*Result of 'Util.util()' is ignored*/util/**/();
|
||||
}
|
||||
}
|
||||
"""
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user