mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
Source purity inference: do not infer purity for methods which read volatile field (own field within the same class only)
This commit is contained in:
+1
-1
@@ -30,7 +30,7 @@ import java.util.*
|
||||
* @author peter
|
||||
*/
|
||||
|
||||
private val gist = GistManager.getInstance().newPsiFileGist("contractInference", 5, MethodDataExternalizer) { file ->
|
||||
private val gist = GistManager.getInstance().newPsiFileGist("contractInference", 6, MethodDataExternalizer) { file ->
|
||||
indexFile(file.node.lighterAST)
|
||||
}
|
||||
|
||||
|
||||
+22
-1
@@ -19,7 +19,10 @@ import com.intellij.lang.LighterAST;
|
||||
import com.intellij.lang.LighterASTNode;
|
||||
import com.intellij.openapi.util.RecursionManager;
|
||||
import com.intellij.psi.JavaTokenType;
|
||||
import com.intellij.psi.PsiModifier;
|
||||
import com.intellij.psi.PsiType;
|
||||
import com.intellij.psi.impl.cache.RecordUtil;
|
||||
import com.intellij.psi.impl.source.FileLocalResolver;
|
||||
import com.intellij.psi.impl.source.JavaLightTreeUtil;
|
||||
import com.intellij.psi.impl.source.PsiMethodImpl;
|
||||
import com.intellij.psi.impl.source.tree.LightTreeUtil;
|
||||
@@ -60,6 +63,7 @@ public class PurityInference {
|
||||
private final LighterASTNode body;
|
||||
private List<LighterASTNode> mutatedRefs = new ArrayList<>();
|
||||
private boolean hasReturns;
|
||||
private boolean hasVolatileReads;
|
||||
private List<LighterASTNode> calls = new ArrayList<>();
|
||||
|
||||
PurityInferenceVisitor(LighterAST tree, LighterASTNode body) {
|
||||
@@ -81,6 +85,23 @@ public class PurityInference {
|
||||
else if (isCall(element, type)) {
|
||||
calls.add(element);
|
||||
}
|
||||
else if (type == REFERENCE_EXPRESSION) {
|
||||
LighterASTNode qualifier = JavaLightTreeUtil.findExpressionChild(tree, element);
|
||||
if (qualifier == null || qualifier.getTokenType() == THIS_EXPRESSION) {
|
||||
LighterASTNode target = new FileLocalResolver(tree).resolveLocally(element).getTarget();
|
||||
if (target != null && target.getTokenType() == FIELD) {
|
||||
LighterASTNode modifierList = LightTreeUtil.firstChildOfType(tree, target, MODIFIER_LIST);
|
||||
if (modifierList != null) {
|
||||
for (LighterASTNode modifier : tree.getChildren(modifierList)) {
|
||||
if (RecordUtil.intern(tree.getCharTable(), modifier).equals(PsiModifier.VOLATILE)) {
|
||||
hasVolatileReads = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isCall(@NotNull LighterASTNode element, IElementType type) {
|
||||
@@ -95,7 +116,7 @@ public class PurityInference {
|
||||
|
||||
@Nullable
|
||||
PurityInferenceResult getResult() {
|
||||
if (calls.size() > 1 || !hasReturns) return null;
|
||||
if (calls.size() > 1 || !hasReturns || hasVolatileReads) return null;
|
||||
|
||||
int bodyStart = body.getStartOffset();
|
||||
return new PurityInferenceResult(ContainerUtil.map(mutatedRefs, node -> ExpressionRange.create(node, bodyStart)),
|
||||
|
||||
+20
@@ -231,6 +231,26 @@ class Another {
|
||||
"""
|
||||
}
|
||||
|
||||
void "test plain field read"() {
|
||||
assertPure true, """
|
||||
int x;
|
||||
|
||||
int get() {
|
||||
return x;
|
||||
}
|
||||
"""
|
||||
}
|
||||
|
||||
void "test volatile field read"() {
|
||||
assertPure false, """
|
||||
volatile int x;
|
||||
|
||||
int get() {
|
||||
return x;
|
||||
}
|
||||
"""
|
||||
}
|
||||
|
||||
private void assertPure(boolean expected, String classBody) {
|
||||
def clazz = myFixture.addClass("final class Foo { $classBody }")
|
||||
assert !((PsiFileImpl) clazz.containingFile).contentsLoaded
|
||||
|
||||
Reference in New Issue
Block a user