Skip to content
Open
Show file tree
Hide file tree
Changes from 95 commits
Commits
Show all changes
108 commits
Select commit Hold shift + click to select a range
427c55a
temp commit
t-rasmud Dec 3, 2020
0ad09bb
side effects only checker
t-rasmud Dec 3, 2020
15ca2db
side effects only for this and field values
t-rasmud Dec 4, 2020
2857929
more tests
t-rasmud Dec 4, 2020
21dc0a4
add null checks
t-rasmud Dec 4, 2020
ef59d5e
side effects only javadoc
t-rasmud Dec 4, 2020
40fdfd8
purity suggestions test
t-rasmud Dec 4, 2020
ac6d8ca
nullness check
t-rasmud Dec 4, 2020
df56c0d
javadoc
t-rasmud Dec 4, 2020
48d2d42
remove sideeffectsonly from purity
t-rasmud Dec 5, 2020
595de2c
remove side_effects_only from purity kinds
t-rasmud Dec 5, 2020
9347508
Merge branch 'master' of github.com:t-rasmud/checker-framework into s…
t-rasmud Dec 6, 2020
1459a9c
remove unnecessary
t-rasmud Dec 6, 2020
39edb6d
add documentation
t-rasmud Dec 6, 2020
b3ecb7e
documentation for side effects only
t-rasmud Dec 6, 2020
7300132
fix formatting
t-rasmud Dec 6, 2020
8c3a428
fix side effects only for receiver
t-rasmud Dec 8, 2020
c34dd98
checher-qual after merging with master
t-rasmud Feb 16, 2021
1c9d4ad
remove unrelated
t-rasmud Feb 16, 2021
dcc0390
Merge branch 'master' of github.com:t-rasmud/checker-framework into s…
t-rasmud Feb 17, 2021
a2dd514
refactor qual
t-rasmud Feb 17, 2021
34c456b
Merge github.com:typetools/checker-framework
t-rasmud Feb 23, 2021
5eb932a
Merge github.com:typetools/checker-framework
t-rasmud Feb 23, 2021
5fd464f
Merge branch 'master' of github.com:t-rasmud/checker-framework into s…
t-rasmud Mar 2, 2021
a0442b4
remove unrelated test file
t-rasmud Mar 2, 2021
ce77c26
documenting toy checker
t-rasmud Mar 2, 2021
171090d
fix documentation and refactoring
t-rasmud Mar 2, 2021
6877a37
fix SideEffectsOnly documentation
t-rasmud Mar 2, 2021
8a04d7f
improves documentation for SideEffectsOnly
t-rasmud Mar 2, 2021
245984b
more documentation for SideEffectsOnly
t-rasmud Mar 2, 2021
d7a6c6a
Merge github.com:typetools/checker-framework
t-rasmud Mar 4, 2021
837128d
Merge branch 'master' of github.com:t-rasmud/checker-framework into s…
t-rasmud Mar 4, 2021
ec10c52
addressing review
t-rasmud Mar 4, 2021
201d09b
addressing review: entryset() to keyset()
t-rasmud Mar 4, 2021
39f0044
give meaningful qualifier names
t-rasmud Mar 4, 2021
835712a
address review
t-rasmud Mar 4, 2021
9bbe372
JavaExpression instead of String and clean-up
t-rasmud Mar 5, 2021
3e0fbe7
test case: change parameter names
t-rasmud Mar 5, 2021
5f03c88
fix documentation
t-rasmud Mar 5, 2021
d1dc0cb
Merge github.com:typetools/checker-framework
t-rasmud Mar 5, 2021
9344756
Merge branch 'master' of github.com:t-rasmud/checker-framework into s…
t-rasmud Mar 5, 2021
5afaf07
Merge branch 'master' of github.com:t-rasmud/checker-framework into s…
t-rasmud Mar 5, 2021
237e037
fix checker-qual
t-rasmud Mar 5, 2021
f93a6dc
checker-qual signedness fix
t-rasmud Mar 5, 2021
4590c3d
Merge ../checker-framework-branch-master into side-effects-only
mernst Mar 6, 2021
810a45a
fix documentation for SideEffectsOnly
t-rasmud Mar 9, 2021
6c3560e
SideEffectsOnly empty test
t-rasmud Mar 9, 2021
d4d967d
SideEffectsOnly documentation fixes
t-rasmud Mar 9, 2021
9b85e87
Merge branch 'side-effects-only' of github.com:t-rasmud/checker-frame…
mernst Mar 11, 2021
d9cd13d
Merge ../checker-framework-branch-master into side-effects-only
mernst Mar 18, 2021
4712584
Documentation improvements
mernst Mar 18, 2021
9275dee
Tweaks
mernst Mar 18, 2021
3d2caa1
Fix error and test case for SideEffectsOnly field
t-rasmud Mar 22, 2021
9750682
Merge branch 'master' of github.com:t-rasmud/checker-framework into s…
t-rasmud Mar 22, 2021
875f638
SideEffects relationship documentatio
t-rasmud Mar 22, 2021
0541f0f
Merge ../checker-framework-branch-master into side-effects-only
mernst Mar 23, 2021
8ea0e1e
Merge ../checker-framework-branch-master into side-effects-only
mernst Mar 24, 2021
3092354
Undo whitespace change
mernst Mar 24, 2021
4a11c51
Tweak documentation
mernst Mar 24, 2021
bf86930
clean imports
t-rasmud Mar 30, 2021
dee4cd3
report error correctly
t-rasmud Mar 30, 2021
6e5c391
address review comment
t-rasmud Mar 30, 2021
87bd9a7
reintroduce incorrectly deleted code
t-rasmud Mar 30, 2021
cbc6afb
merge with master; check; skip pre-commit
t-rasmud Mar 31, 2021
7e0337c
fix updateForMethodCall after merge
t-rasmud Mar 31, 2021
94176a4
fix imports
t-rasmud Apr 2, 2021
d5c2fea
Merge branch 'master' of github.com:t-rasmud/checker-framework into s…
t-rasmud Apr 3, 2021
a2c749e
fix deprecated method
t-rasmud Apr 6, 2021
0d5d7b4
javadoc fixes
t-rasmud Apr 7, 2021
2abdc8c
test case for empty @SideEffectsOnly
t-rasmud Apr 8, 2021
a8cad8c
temp commit: experimenting
t-rasmud Apr 9, 2021
1cc560e
SideEffectsOnly checker: reports error on some assignments
t-rasmud Apr 12, 2021
b446e3c
merge with master
t-rasmud May 19, 2021
8e62d1e
imports refactoring
t-rasmud May 20, 2021
533f1eb
Merge branch 'master' of github.com:t-rasmud/checker-framework into s…
t-rasmud May 31, 2021
7e6f352
Merge branch 'master' of github.com:t-rasmud/checker-framework into s…
t-rasmud Jun 25, 2021
9f19380
merge
t-rasmud Jul 8, 2021
0288bdf
handling method invocations
t-rasmud Jul 11, 2021
e09d7ea
SEOnly checking at method invocations
t-rasmud Jul 14, 2021
42c6748
Merge ../checker-framework-branch-master into side-effects-only
mernst Aug 3, 2021
0e478f5
Merge branch 'side-effects-only' of github.com:t-rasmud/checker-frame…
t-rasmud Aug 9, 2021
72647aa
Merge branch 'master' of github.com:t-rasmud/checker-framework into s…
t-rasmud Aug 9, 2021
f91ac19
fix package name
t-rasmud Aug 9, 2021
fc91585
test case: Check SideEffectsOnly
t-rasmud Aug 12, 2021
4bcbb3b
comments
t-rasmud Aug 15, 2021
ebe7036
Merge branch 'master' of github.com:t-rasmud/checker-framework into s…
t-rasmud Aug 15, 2021
e6a61f5
builds
t-rasmud Aug 23, 2021
990e6e2
Merge branch 'master' of github.com:t-rasmud/checker-framework into s…
t-rasmud Oct 14, 2021
9220596
SideEffectsOnlyAnnoChecker
t-rasmud Oct 14, 2021
fccd5e6
test case fixes
t-rasmud Oct 14, 2021
6d2d9fa
javadoc
t-rasmud Oct 18, 2021
e5c48be
Merge branch 'master' of github.com:t-rasmud/checker-framework into s…
t-rasmud Oct 18, 2021
3c8878c
documentation for -AcheckSideEffectsOnlyAnnotation
t-rasmud Oct 20, 2021
a4439a1
Merge branch 'master' of github.com:t-rasmud/checker-framework into s…
t-rasmud Oct 21, 2021
15b3a08
Documentation tweaks
mernst Oct 21, 2021
8dd7d94
Tweak comment
mernst Oct 27, 2021
1264b07
change method name
t-rasmud Nov 2, 2021
5b0dbc5
fix error message key
t-rasmud Nov 2, 2021
1ecd0fe
checkPurityAnnotations flag checks SideEffectsOnly
t-rasmud Nov 2, 2021
a984534
report error if invoked method not @SideEffectsOnly
t-rasmud Nov 6, 2021
177c221
report error if invoked method not @SideEffectsOnly
t-rasmud Nov 6, 2021
eb71099
adding test case
t-rasmud Nov 8, 2021
a1115c7
fixing javadoc
t-rasmud Nov 8, 2021
30f4258
fixing javadoc
t-rasmud Nov 8, 2021
b630298
testing CheckSideEffectsOnly functionality in Purity Checker
t-rasmud Nov 14, 2021
d1b69c4
minor
t-rasmud Nov 14, 2021
d9e3336
fix
t-rasmud Nov 15, 2021
9632766
Merge branch 'master' of github.com:t-rasmud/checker-framework into s…
t-rasmud Nov 22, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package org.checkerframework.dataflow.qual;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.checkerframework.framework.qual.JavaExpression;

/**
* A method annotated with the declaration annotation {@code @SideEffectsOnly(A, B)} performs
* side-effects on at most the expressions A and B. All other expressions have the same value before
* and after a call.
*
* @checker_framework.manual #type-refinement-purity Specifying side effects
*/
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD, ElementType.CONSTRUCTOR})
public @interface SideEffectsOnly {
/**
* An upper bound on the expressions that this method side effects.
*
* @return Java expressions that the annotated method might side-effect
* @checker_framework.manual #java-expressions-as-arguments Syntax of Java expressions
*/
@JavaExpression
public String[] value();
}
13 changes: 12 additions & 1 deletion docs/manual/advanced-features.tex
Original file line number Diff line number Diff line change
Expand Up @@ -1015,7 +1015,8 @@
the refined type, because the method might assign a field.
The \refqualclass{dataflow/qual}{SideEffectFree} annotation indicates that
the method has no side effects, so calling it does not invalidate any
dataflow facts.
dataflow facts. Alternately, the \refqualclass{dataflow/qual}{SideEffectsOnly}
annotation specifies all the expressions that the method might side-effect.

Calling a method twice might have different results, so facts known about
one call cannot be relied upon at another call.
Expand Down Expand Up @@ -1105,6 +1106,16 @@
\end{enumerate}


\subsubsectionAndLabel{Relationship between \<@SideEffectFree> and \<@SideEffectsOnly>}{side-effects-relationship}

A method cannot be annotated with both \refqualclass{dataflow/qual}{SideEffectFree}
and \refqualclass{dataflow/qual}{SideEffectsOnly}.
The annotation \<@SideEffectsOnly(\{\})> is equivalent to \<@SideEffectFree>.
If a method has no \refqualclass{dataflow/qual}{SideEffectsOnly}
or \refqualclass{dataflow/qual}{SideEffectFree} annotation, then the Checker Framework
assumes that the method may side-effect any expressions (including fields and arguments).


\subsubsectionAndLabel{Deterministic methods}{type-refinement-determinism}

Consider the following declaration and uses:
Expand Down
5 changes: 5 additions & 0 deletions docs/manual/introduction.tex
Original file line number Diff line number Diff line change
Expand Up @@ -609,6 +609,11 @@
to ensure the method satisfies the annotation. By default,
the Checker Framework unsoundly trusts the method annotation. See
Section~\ref{type-refinement-purity}.
\item \<-AcheckSideEffectsOnlyAnnotation>
Check the bodies of methods marked
\refqualclass{dataflow/qual}{SideEffectsOnly} to ensure the method
side-effects at most the annotation's arguments/elements. See
Section~\ref{type-refinement-purity}.
\item \<-AinvariantArrays>
Make array subtyping invariant; that is, two arrays are subtypes of one
another only if they have exactly the same element type. By default,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@
import org.checkerframework.dataflow.qual.Deterministic;
import org.checkerframework.dataflow.qual.Pure;
import org.checkerframework.dataflow.qual.SideEffectFree;
import org.checkerframework.dataflow.qual.SideEffectsOnly;
import org.checkerframework.dataflow.util.PurityChecker;
import org.checkerframework.dataflow.util.PurityChecker.PurityResult;
import org.checkerframework.dataflow.util.PurityUtils;
Expand Down Expand Up @@ -129,6 +130,7 @@
import org.checkerframework.framework.util.Contract.Precondition;
import org.checkerframework.framework.util.ContractsFromMethod;
import org.checkerframework.framework.util.FieldInvariants;
import org.checkerframework.framework.util.JavaExpressionParseUtil;
import org.checkerframework.framework.util.JavaExpressionParseUtil.JavaExpressionParseException;
import org.checkerframework.framework.util.JavaParserUtil;
import org.checkerframework.framework.util.StringToJavaExpression;
Expand Down Expand Up @@ -218,6 +220,9 @@ public class BaseTypeVisitor<Factory extends GenericAnnotatedTypeFactory<?, ?, ?
/** The {@code when} element/field of the @Unused annotation. */
protected final ExecutableElement unusedWhenElement;

/** The {@code value} element/field of @{@link SideEffectsOnly} annotation. */
ExecutableElement sideEffectsOnlyValueElement;

/** True if "-Ashowchecks" was passed on the command line. */
private final boolean showchecks;
/** True if "-Ainfer" was passed on the command line. */
Expand Down Expand Up @@ -265,6 +270,8 @@ protected BaseTypeVisitor(BaseTypeChecker checker, Factory typeFactory) {
atypeFactory.fromElement(elements.getTypeElement(Vector.class.getCanonicalName()));
targetValueElement = TreeUtils.getMethod(Target.class, "value", 0, env);
unusedWhenElement = TreeUtils.getMethod(Unused.class, "when", 0, env);
sideEffectsOnlyValueElement =
TreeUtils.getMethod(SideEffectsOnly.class, "value", 0, checker.getProcessingEnvironment());
showchecks = checker.hasOption("showchecks");
infer = checker.hasOption("infer");
suggestPureMethods = checker.hasOption("suggestPureMethods") || infer;
Expand Down Expand Up @@ -887,6 +894,7 @@ public Void visitMethod(MethodTree node, Void p) {
}

checkPurity(node);
checkSideEffectsOnly(node);

// Passing the whole method/constructor validates the return type
validateTypeOf(node);
Expand Down Expand Up @@ -1036,6 +1044,65 @@ protected void checkPurity(MethodTree node) {
}
}

/**
* If the method {@code node} is annotated with {@link SideEffectsOnly}, checks that the method
* side-effects a subset of the expressions specified as annotation arguments/elements to {@link
* SideEffectsOnly}.
*
* @param node the method tree to check
*/
protected void checkSideEffectsOnly(MethodTree node) {
if (!checker.hasOption("checkSideEffectsOnlyAnnotation")) {
return;
}

TreePath body = atypeFactory.getPath(node.getBody());
if (body == null) {
return;
} else {
@Nullable Element methodDeclElem = TreeUtils.elementFromTree(node);
AnnotationMirror sefOnlyAnnotation =
atypeFactory.getDeclAnnotation(methodDeclElem, SideEffectsOnly.class);
if (sefOnlyAnnotation == null) {
return;
}
List<String> sideEffectsOnlyExpressionStrings =
AnnotationUtils.getElementValueArray(
sefOnlyAnnotation, sideEffectsOnlyValueElement, String.class);
List<JavaExpression> sideEffectsOnlyExpressions = new ArrayList<>();
for (String st : sideEffectsOnlyExpressionStrings) {
try {
JavaExpression exprJe = StringToJavaExpression.atMethodBody(st, node, checker);
sideEffectsOnlyExpressions.add(exprJe);
} catch (JavaExpressionParseUtil.JavaExpressionParseException ex) {
checker.report(st, ex.getDiagMessage());
return;
}
}

if (sideEffectsOnlyExpressions.isEmpty()) {
return;
}

SideEffectsOnlyAnnoChecker.SideEffectsOnlyResult sefOnlyResult =
SideEffectsOnlyAnnoChecker.checkSideEffectsOnly(
body,
atypeFactory,
sideEffectsOnlyExpressions,
atypeFactory.getProcessingEnv(),
checker);

List<Pair<Tree, JavaExpression>> seOnlyIncorrectExprs = sefOnlyResult.getSeOnlyResult();
if (!seOnlyIncorrectExprs.isEmpty()) {
for (Pair<Tree, JavaExpression> s : seOnlyIncorrectExprs) {
if (!sideEffectsOnlyExpressions.contains(s.second)) {
checker.reportError(s.first, "incorrect.sideeffectsonly", s.second.toString());
}
}
}
}
}

/**
* Issue a warning if the result type of the constructor is not top. If it is a supertype of the
* class, then a conflicting.annos error will also be issued by {@link
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,198 @@
package org.checkerframework.common.basetype;

import com.sun.source.tree.AssignmentTree;
import com.sun.source.tree.CatchTree;
import com.sun.source.tree.CompoundAssignmentTree;
import com.sun.source.tree.MethodInvocationTree;
import com.sun.source.tree.NewClassTree;
import com.sun.source.tree.Tree;
import com.sun.source.tree.UnaryTree;
import com.sun.source.util.TreePath;
import com.sun.source.util.TreePathScanner;
import java.util.ArrayList;
import java.util.List;
import javax.annotation.processing.ProcessingEnvironment;
import javax.lang.model.element.AnnotationMirror;
import javax.lang.model.element.Element;
import javax.lang.model.element.ExecutableElement;
import org.checkerframework.dataflow.expression.JavaExpression;
import org.checkerframework.dataflow.qual.Pure;
import org.checkerframework.dataflow.qual.SideEffectFree;
import org.checkerframework.dataflow.qual.SideEffectsOnly;
import org.checkerframework.framework.util.JavaExpressionParseUtil;
import org.checkerframework.framework.util.StringToJavaExpression;
import org.checkerframework.javacutil.AnnotationProvider;
import org.checkerframework.javacutil.AnnotationUtils;
import org.checkerframework.javacutil.Pair;
import org.checkerframework.javacutil.TreeUtils;

/**
* For methods annotated with {@link SideEffectsOnly}, computes expressions that are side-effected
* but not permitted by the annotation.
*/
public class SideEffectsOnlyAnnoChecker {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm curious why this is a brand-new class rather than a modification to the existing mutation checker.

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not aware of a mutation checker and couldn’t find it in the manual either. Could you please point me to that class?
Although I think the PurityChecker can be modified to add all the functionality in the SideEffectsOnlyAnnoChecker. Do you think that's more appropriate?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

By "mutation checker" I meant PurityChecker. I'm sorry for being sloppy in my terminology. Thank you for setting me straight. Yes, I was thinking that merging the functionality in one place (maybe controlled by a switch) would be shorter, easier to understand, and less prone to code drift, compared to the two separate implementations. At least, I think that is worth trying to see whether it works out.

Thank you!

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for the suggestions. I tried merging the two functionalities into PurityChecker but wasn’t successful because of the following reason:
SideEffectsOnlyAnnoChecker (a part of the Checker Framework repository) needs to import org.checkerframework.common.basetype.BaseTypeChecker, which is not visible in the dataflow project (dataflow project contains the PurityChecker). Is there any other way around this?

/**
* Returns the computed {@code SideEffectsOnlyResult}.
*
* @param statement TreePath
* @param annoProvider AnnotationProvider
* @param sideEffectsOnlyExpressions List of JavaExpression
* @param processingEnv ProcessingEnvironment
* @param checker BaseTypeChecker
* @return SideEffectsOnlyResult
*/
public static SideEffectsOnlyResult checkSideEffectsOnly(
TreePath statement,
AnnotationProvider annoProvider,
List<JavaExpression> sideEffectsOnlyExpressions,
ProcessingEnvironment processingEnv,
BaseTypeChecker checker) {
SideEffectsOnlyCheckerHelper helper =
new SideEffectsOnlyCheckerHelper(
annoProvider, sideEffectsOnlyExpressions, processingEnv, checker);
helper.scan(statement, null);
return helper.sideEffectsOnlyResult;
}

/** SideEffectsOnlyResult. */
public static class SideEffectsOnlyResult {
/**
* List of expressions a method side-effects that are not specified in the list of arguments to
* {@link SideEffectsOnly}.
*/
protected final List<Pair<Tree, JavaExpression>> seOnlyIncorrectExprs = new ArrayList<>(1);

/**
* Adds {@code t} and {@code javaExpr} as a Pair to seOnlyIncorrectExprs.
*
* @param t Tree
* @param javaExpr JavaExpression
*/
public void addNotSEOnlyExpr(Tree t, JavaExpression javaExpr) {
seOnlyIncorrectExprs.add(Pair.of(t, javaExpr));
}

/**
* Returns {@code seOnlyIncorrectExprs}.
*
* @return seOnlyIncorrectExprs
*/
public List<Pair<Tree, JavaExpression>> getSeOnlyResult() {
return seOnlyIncorrectExprs;
}
}

/** SideEffectsOnlyCheckerHelper. */
protected static class SideEffectsOnlyCheckerHelper extends TreePathScanner<Void, Void> {
/** Result computed by SideEffectsOnlyCheckerHelper. */
SideEffectsOnlyResult sideEffectsOnlyResult = new SideEffectsOnlyResult();
/**
* List of expressions specified as annotation arguments in {@link SideEffectsOnly} annotation.
*/
List<JavaExpression> sideEffectsOnlyExpressions;

/** AnnotationProvider. */
protected final AnnotationProvider annoProvider;
/** Processing Environment. */
ProcessingEnvironment processingEnv;
/** BaseTypeChecker. */
BaseTypeChecker checker;

/**
* Constructor for SideEffectsOnlyCheckerHelper.
*
* @param annoProvider AnnotationProvider
* @param sideEffectsOnlyExpressions List of JavaExpressions
* @param processingEnv ProcessingEnvironment
* @param checker BaseTypeChecker
*/
public SideEffectsOnlyCheckerHelper(
AnnotationProvider annoProvider,
List<JavaExpression> sideEffectsOnlyExpressions,
ProcessingEnvironment processingEnv,
BaseTypeChecker checker) {
this.annoProvider = annoProvider;
this.sideEffectsOnlyExpressions = sideEffectsOnlyExpressions;
this.processingEnv = processingEnv;
this.checker = checker;
}

@Override
public Void visitCatch(CatchTree node, Void aVoid) {
return super.visitCatch(node, aVoid);
}

@Override
public Void visitMethodInvocation(MethodInvocationTree node, Void aVoid) {
Element treeElem = TreeUtils.elementFromTree(node);
AnnotationMirror pureAnno = annoProvider.getDeclAnnotation(treeElem, Pure.class);
AnnotationMirror sideEffectFreeAnno =
annoProvider.getDeclAnnotation(treeElem, SideEffectFree.class);
// If the invoked method is annotated as @Pure or @SideEffectFree, nothing to do.
if (pureAnno != null || sideEffectFreeAnno != null) {
return super.visitMethodInvocation(node, aVoid);
}

AnnotationMirror sideEffectsOnlyAnno =
annoProvider.getDeclAnnotation(treeElem, SideEffectsOnly.class);
// If the invoked method is not annotated with @SideEffectsOnly,
// add those arguments to seOnlyIncorrectExprs
// that are not present in sideEffectsOnlyExpressions.
if (sideEffectsOnlyAnno == null) {
JavaExpression receiverExpr = JavaExpression.getReceiver(node);
if (!sideEffectsOnlyExpressions.contains(receiverExpr)) {
sideEffectsOnlyResult.addNotSEOnlyExpr(node, receiverExpr);
}
} else {
// If the invoked method is annotated with @SideEffectsOnly,
// add annotation values to seOnlyIncorrectExprs
// that are not present in sideEffectsOnlyExpressions.
ExecutableElement sideEffectsOnlyValueElement =
TreeUtils.getMethod(SideEffectsOnly.class, "value", 0, processingEnv);
List<String> sideEffectsOnlyExpressionStrings =
AnnotationUtils.getElementValueArray(
sideEffectsOnlyAnno, sideEffectsOnlyValueElement, String.class);
List<JavaExpression> sideEffectsOnlyExprInv = new ArrayList<>();
for (String st : sideEffectsOnlyExpressionStrings) {
try {
JavaExpression exprJe = StringToJavaExpression.atMethodInvocation(st, node, checker);
sideEffectsOnlyExprInv.add(exprJe);
} catch (JavaExpressionParseUtil.JavaExpressionParseException ex) {
checker.report(st, ex.getDiagMessage());
}
}

for (JavaExpression expr : sideEffectsOnlyExprInv) {
if (!sideEffectsOnlyExpressions.contains(expr)) {
sideEffectsOnlyResult.addNotSEOnlyExpr(node, expr);
}
}
}
return super.visitMethodInvocation(node, aVoid);
}

@Override
public Void visitNewClass(NewClassTree node, Void aVoid) {
return super.visitNewClass(node, aVoid);
}

@Override
public Void visitAssignment(AssignmentTree node, Void aVoid) {
JavaExpression javaExpr = JavaExpression.fromTree(node.getVariable());
if (!sideEffectsOnlyExpressions.contains(javaExpr)) {
sideEffectsOnlyResult.addNotSEOnlyExpr(node, javaExpr);
}
return super.visitAssignment(node, aVoid);
}

@Override
public Void visitUnary(UnaryTree node, Void aVoid) {
return super.visitUnary(node, aVoid);
}

@Override
public Void visitCompoundAssignment(CompoundAssignmentTree node, Void aVoid) {
return super.visitCompoundAssignment(node, aVoid);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,8 @@ purity.more.deterministic=the method %s could be declared as @Deterministic
purity.more.pure=the method %s could be declared as @Pure
purity.more.sideeffectfree=the method %s could be declared as @SideEffectFree

incorrect.sideeffectsonly=the method side-effects %s

flowexpr.parse.index.too.big=the method does not have a parameter %s
flowexpr.parse.error=cannot parse the expression %s
flowexpr.parse.error.postcondition=error parsing the postcondition expression for %s%ncannot parse the expression %s
Expand Down
Loading