Merge remote-tracking branch 'origin/master'

This commit is contained in:
Dmitry Batkovich
2017-05-29 11:02:48 +03:00
5 changed files with 60 additions and 35 deletions
@@ -421,7 +421,7 @@ public class BytecodeAnalysisConverter {
ValueConstraint left = c1.arguments[i];
ValueConstraint right = c2.arguments[i];
if (left == ValueConstraint.ANY_VALUE && right == ValueConstraint.ANY_VALUE) continue;
if (idx >= 0 || left == right || left != right.negate()) return null;
if (idx >= 0 || !right.canBeNegated() || left != right.negate()) return null;
idx = i;
}
return c1;
@@ -53,7 +53,7 @@ public class BytecodeAnalysisIndex extends ScalarIndexExtension<Bytes> {
private static final ID<Bytes, Void> NAME = ID.create("bytecodeAnalysis");
private static final HKeyDescriptor KEY_DESCRIPTOR = new HKeyDescriptor();
private static final VirtualFileGist<Map<Bytes, HEquations>> ourGist = GistManager.getInstance().newVirtualFileGist(
"BytecodeAnalysisIndex", 5, new HEquationsExternalizer(), new ClassDataIndexer());
"BytecodeAnalysisIndex", 4, new HEquationsExternalizer(), new ClassDataIndexer());
@NotNull
@Override
@@ -556,6 +556,9 @@ final class HardCodedPurity {
// Maybe overloaded and be not pure, but this would be definitely bad code style
// Used in Throwable(Throwable) ctor, so this helps to infer purity of many exception constructors
new Method("java/lang/Throwable", "toString", "()Ljava/lang/String;"),
// Declared in final class StringBuilder
new Method("java/lang/StringBuilder", "toString", "()Ljava/lang/String;"),
new Method("java/lang/StringBuffer", "toString", "()Ljava/lang/String;"),
// Native
new Method("java/lang/Object", "getClass", "()Ljava/lang/Class;"),
new Method("java/lang/Class", "getComponentType", "()Ljava/lang/Class;"),
@@ -593,8 +596,7 @@ final class HardCodedPurity {
}
static boolean isPureMethod(Key key) {
return key.method.methodName.equals("toString") && key.method.methodDesc.equals("()Ljava/lang/String;") ||
pureMethods.contains(key.method);
return pureMethods.contains(key.method);
}
static boolean isOwnedField(FieldInsnNode fieldInsn) {
@@ -160,7 +160,17 @@ public abstract class MethodContract {
}
/**
* @return negated constraint or this if the constraint cannot be negated
* @return true if constraint can be negated
* @see #negate()
*/
public boolean canBeNegated() {
return this != ANY_VALUE && this != THROW_EXCEPTION;
}
/**
* @return negated constraint
* @throws IllegalStateException if constraint cannot be negated
* @see #canBeNegated()
*/
public ValueConstraint negate() {
switch (this) {
@@ -168,7 +178,8 @@ public abstract class MethodContract {
case NOT_NULL_VALUE: return NULL_VALUE;
case TRUE_VALUE: return FALSE_VALUE;
case FALSE_VALUE: return TRUE_VALUE;
default: return this;
default:
throw new IllegalStateException("ValueConstraint = " + this);
}
}
@@ -15,6 +15,8 @@
*/
package com.siyeh.ig.psiutils;
import com.intellij.openapi.diagnostic.Attachment;
import com.intellij.openapi.diagnostic.RuntimeExceptionWithAttachments;
import com.intellij.psi.*;
import com.intellij.psi.tree.IElementType;
import com.intellij.psi.util.PsiTreeUtil;
@@ -60,49 +62,59 @@ public class StatementExtractor {
return result.toString();
}
@NotNull
private static Node createNode(@NotNull PsiExpression expression, @NotNull PsiExpression root) {
Node result = new Expr(expression);
PsiExpression parent;
for (; expression != root; expression = parent) {
while (expression != root) {
PsiElement parentElement = expression.getParent();
if(parentElement instanceof PsiExpressionList) {
parentElement = parentElement.getParent();
}
parent = ObjectUtils.tryCast(parentElement, PsiExpression.class);
if (parent == null) {
throw new IllegalStateException(expression.getText() + ": expected to have expression parent; root = " + root.getText());
}
if (parent instanceof PsiPolyadicExpression) {
PsiPolyadicExpression polyadic = (PsiPolyadicExpression)parent;
IElementType type = polyadic.getOperationTokenType();
boolean and;
if (type == JavaTokenType.ANDAND) {
and = true;
}
else if (type == JavaTokenType.OROR) {
and = false;
}
else {
continue;
}
PsiExpression[] operands = polyadic.getOperands();
int index = ArrayUtil.indexOf(operands, expression);
if (index == 0) continue;
result = new Cond(parent, parent, index, and ? result : EMPTY, and ? EMPTY : result);
}
if (parent instanceof PsiConditionalExpression) {
PsiConditionalExpression ternary = (PsiConditionalExpression)parent;
if (expression == ternary.getThenExpression()) {
result = new Cond(ternary, ternary.getCondition(), -1, result, EMPTY);
}
else if (expression == ternary.getElseExpression()) {
result = new Cond(ternary, ternary.getCondition(), -1, EMPTY, result);
}
throw new RuntimeExceptionWithAttachments("Expected to have expression parent",
new Attachment("expression.txt", expression.getText()),
new Attachment("root.txt", root.getText()));
}
result = foldNode(result, expression, parent);
expression = parent;
}
return result;
}
@NotNull
private static Node foldNode(@NotNull Node node, @NotNull PsiExpression expression, @NotNull PsiExpression parent) {
if (parent instanceof PsiPolyadicExpression) {
PsiPolyadicExpression polyadic = (PsiPolyadicExpression)parent;
IElementType type = polyadic.getOperationTokenType();
boolean and;
if (type == JavaTokenType.ANDAND) {
and = true;
}
else if (type == JavaTokenType.OROR) {
and = false;
}
else {
return node;
}
PsiExpression[] operands = polyadic.getOperands();
int index = ArrayUtil.indexOf(operands, expression);
if (index == 0) return node;
return new Cond(parent, parent, index, and ? node : EMPTY, and ? EMPTY : node);
}
if (parent instanceof PsiConditionalExpression) {
PsiConditionalExpression ternary = (PsiConditionalExpression)parent;
if (expression == ternary.getThenExpression()) {
return new Cond(ternary, ternary.getCondition(), -1, node, EMPTY);
}
if (expression == ternary.getElseExpression()) {
return new Cond(ternary, ternary.getCondition(), -1, EMPTY, node);
}
}
return node;
}
private static abstract class Node {
final PsiExpression myAnchor;