summaryrefslogtreecommitdiff
path: root/java/java-analysis-impl/src/com/intellij/codeInspection/bytecodeAnalysis/ClassDataIndexer.java
diff options
context:
space:
mode:
Diffstat (limited to 'java/java-analysis-impl/src/com/intellij/codeInspection/bytecodeAnalysis/ClassDataIndexer.java')
-rw-r--r--java/java-analysis-impl/src/com/intellij/codeInspection/bytecodeAnalysis/ClassDataIndexer.java425
1 files changed, 273 insertions, 152 deletions
diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/bytecodeAnalysis/ClassDataIndexer.java b/java/java-analysis-impl/src/com/intellij/codeInspection/bytecodeAnalysis/ClassDataIndexer.java
index 9e656b98a7fb..316307896467 100644
--- a/java/java-analysis-impl/src/com/intellij/codeInspection/bytecodeAnalysis/ClassDataIndexer.java
+++ b/java/java-analysis-impl/src/com/intellij/codeInspection/bytecodeAnalysis/ClassDataIndexer.java
@@ -15,17 +15,20 @@
*/
package com.intellij.codeInspection.bytecodeAnalysis;
+import com.intellij.codeInspection.bytecodeAnalysis.asm.*;
import com.intellij.openapi.progress.ProcessCanceledException;
import com.intellij.openapi.progress.ProgressManager;
import com.intellij.openapi.util.NotNullLazyValue;
+import com.intellij.openapi.util.NullableLazyValue;
+import com.intellij.openapi.util.Pair;
import com.intellij.util.indexing.DataIndexer;
import com.intellij.util.indexing.FileContent;
-import gnu.trove.TIntHashSet;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.org.objectweb.asm.*;
import org.jetbrains.org.objectweb.asm.tree.MethodNode;
import org.jetbrains.org.objectweb.asm.tree.analysis.AnalyzerException;
+import java.security.MessageDigest;
import java.util.*;
import static com.intellij.codeInspection.bytecodeAnalysis.ProjectBytecodeAnalysis.LOG;
@@ -33,29 +36,32 @@ import static com.intellij.codeInspection.bytecodeAnalysis.ProjectBytecodeAnalys
/**
* @author lambdamix
*/
-public class ClassDataIndexer implements DataIndexer<Long, IdEquation, FileContent> {
- final BytecodeAnalysisConverter myConverter;
+public class ClassDataIndexer implements DataIndexer<Bytes, HEquations, FileContent> {
- public ClassDataIndexer(BytecodeAnalysisConverter converter) {
- myConverter = converter;
- }
+ private static final int STABLE_FLAGS = Opcodes.ACC_FINAL | Opcodes.ACC_PRIVATE | Opcodes.ACC_STATIC;
+ public static final Final<Key, Value> FINAL_TOP = new Final<Key, Value>(Value.Top);
+ public static final Final<Key, Value> FINAL_BOT = new Final<Key, Value>(Value.Bot);
+ public static final Final<Key, Value> FINAL_NOT_NULL = new Final<Key, Value>(Value.NotNull);
+ public static final Final<Key, Value> FINAL_NULL = new Final<Key, Value>(Value.Null);
+ private static final List<Equation<Key, Value>> EMPTY_EQUATIONS = Collections.EMPTY_LIST;
@NotNull
@Override
- public Map<Long, IdEquation> map(@NotNull FileContent inputData) {
- HashMap<Long, IdEquation> map = new HashMap<Long, IdEquation>();
+ public Map<Bytes, HEquations> map(@NotNull FileContent inputData) {
+ HashMap<Bytes, HEquations> map = new HashMap<Bytes, HEquations>();
try {
- ClassEquations rawEquations = processClass(new ClassReader(inputData.getContent()));
- List<Equation<Key, Value>> rawParameterEquations = rawEquations.parameterEquations;
- List<Equation<Key, Value>> rawContractEquations = rawEquations.contractEquations;
+ MessageDigest md = BytecodeAnalysisConverter.getMessageDigest();
+ Map<Key, List<Equation<Key, Value>>> rawEquations = processClass(new ClassReader(inputData.getContent()), inputData.getFile().getPresentableUrl());
+ for (Map.Entry<Key, List<Equation<Key, Value>>> entry: rawEquations.entrySet()) {
+ Key primaryKey = entry.getKey();
+ Key serKey = new Key(primaryKey.method, primaryKey.direction, true);
- for (Equation<Key, Value> rawParameterEquation: rawParameterEquations) {
- IdEquation equation = myConverter.convert(rawParameterEquation);
- map.put(equation.id, equation);
- }
- for (Equation<Key, Value> rawContractEquation: rawContractEquations) {
- IdEquation equation = myConverter.convert(rawContractEquation);
- map.put(equation.id, equation);
+ List<Equation<Key, Value>> equations = entry.getValue();
+ List<DirectionResultPair> result = new ArrayList<DirectionResultPair>(equations.size());
+ for (Equation<Key, Value> equation : equations) {
+ result.add(BytecodeAnalysisConverter.convert(equation, md));
+ }
+ map.put(new Bytes(BytecodeAnalysisConverter.asmKey(serKey, md).key), new HEquations(result, primaryKey.stable));
}
}
catch (ProcessCanceledException e) {
@@ -66,28 +72,21 @@ public class ClassDataIndexer implements DataIndexer<Long, IdEquation, FileConte
// so here we suppose that exception is due to incorrect bytecode
LOG.debug("Unexpected Error during indexing of bytecode", e);
}
+ //return map;
return map;
}
- private static class ClassEquations {
- final List<Equation<Key, Value>> parameterEquations;
- final List<Equation<Key, Value>> contractEquations;
-
- private ClassEquations(List<Equation<Key, Value>> parameterEquations, List<Equation<Key, Value>> contractEquations) {
- this.parameterEquations = parameterEquations;
- this.contractEquations = contractEquations;
- }
- }
+ public static Map<Key, List<Equation<Key, Value>>> processClass(final ClassReader classReader, final String presentableUrl) {
- public static ClassEquations processClass(final ClassReader classReader) {
- final List<Equation<Key, Value>> parameterEquations = new ArrayList<Equation<Key, Value>>();
- final List<Equation<Key, Value>> contractEquations = new ArrayList<Equation<Key, Value>>();
+ final Map<Key, List<Equation<Key, Value>>> equations = new HashMap<Key, List<Equation<Key, Value>>>();
classReader.accept(new ClassVisitor(Opcodes.ASM5) {
+ private String className;
private boolean stableClass;
@Override
public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) {
+ className = name;
stableClass = (access & Opcodes.ACC_FINAL) != 0;
super.visit(version, access, name, signature, superName, interfaces);
}
@@ -96,164 +95,286 @@ public class ClassDataIndexer implements DataIndexer<Long, IdEquation, FileConte
public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
final MethodNode node = new MethodNode(Opcodes.ASM5, access, name, desc, signature, exceptions);
return new MethodVisitor(Opcodes.ASM5, node) {
+ private boolean jsr;
+
+ @Override
+ public void visitJumpInsn(int opcode, Label label) {
+ if (opcode == Opcodes.JSR) {
+ jsr = true;
+ }
+ super.visitJumpInsn(opcode, label);
+ }
+
@Override
public void visitEnd() {
super.visitEnd();
- processMethod(classReader.getClassName(), node, stableClass);
+ Pair<Key, List<Equation<Key, Value>>> methodEquations = processMethod(node, jsr);
+ equations.put(methodEquations.first, methodEquations.second);
}
};
}
- void processMethod(final String className, final MethodNode methodNode, boolean stableClass) {
+ private Pair<Key, List<Equation<Key, Value>>> processMethod(final MethodNode methodNode, boolean jsr) {
ProgressManager.checkCanceled();
- Type[] argumentTypes = Type.getArgumentTypes(methodNode.desc);
- Type resultType = Type.getReturnType(methodNode.desc);
- int resultSort = resultType.getSort();
- boolean isReferenceResult = resultSort == Type.OBJECT || resultSort == Type.ARRAY;
- boolean isBooleanResult = Type.BOOLEAN_TYPE == resultType;
- boolean isInterestingResult = isReferenceResult || isBooleanResult;
+ final Type[] argumentTypes = Type.getArgumentTypes(methodNode.desc);
+ final Type resultType = Type.getReturnType(methodNode.desc);
+ final boolean isReferenceResult = ASMUtils.isReferenceType(resultType);
+ final boolean isBooleanResult = ASMUtils.isBooleanType(resultType);
+ final boolean isInterestingResult = isReferenceResult || isBooleanResult;
+ final Method method = new Method(className, methodNode.name, methodNode.desc);
+ final boolean stable = stableClass || (methodNode.access & STABLE_FLAGS) != 0 || "<init>".equals(methodNode.name);
+
+ Key primaryKey = new Key(method, new Out(), stable);
if (argumentTypes.length == 0 && !isInterestingResult) {
- return;
+ return Pair.create(primaryKey, EMPTY_EQUATIONS);
}
- Method method = new Method(className, methodNode.name, methodNode.desc);
- int access = methodNode.access;
- boolean stable =
- stableClass ||
- (access & Opcodes.ACC_FINAL) != 0 ||
- (access & Opcodes.ACC_PRIVATE) != 0 ||
- (access & Opcodes.ACC_STATIC) != 0 ||
- "<init>".equals(methodNode.name);
try {
- boolean added = false;
- ControlFlowGraph graph = cfg.buildControlFlowGraph(className, methodNode);
-
- boolean maybeLeakingParameter = false;
- for (Type argType : argumentTypes) {
- int argSort = argType.getSort();
- if (argSort == Type.OBJECT || argSort == Type.ARRAY || (isInterestingResult && Type.BOOLEAN_TYPE.equals(argType))) {
- maybeLeakingParameter = true;
- break;
+ final ControlFlowGraph graph = ControlFlowGraph.build(className, methodNode, jsr);
+ if (graph.transitions.length > 0) {
+ final DFSTree dfs = DFSTree.build(graph.transitions, graph.edgeCount);
+ boolean branching = !dfs.back.isEmpty();
+ if (!branching) {
+ for (int[] transition : graph.transitions) {
+ if (transition != null && transition.length > 1) {
+ branching = true;
+ break;
+ }
+ }
+ }
+
+ if (branching) {
+ RichControlFlow richControlFlow = new RichControlFlow(graph, dfs);
+ if (richControlFlow.reducible()) {
+ return Pair.create(primaryKey,
+ processBranchingMethod(method, methodNode, richControlFlow, argumentTypes, isReferenceResult, isInterestingResult, stable, jsr));
+ }
+ LOG.debug(method + ": CFG is not reducible");
+ }
+ // simple
+ else {
+ return Pair.create(primaryKey,
+ processNonBranchingMethod(method, argumentTypes, graph, isReferenceResult, isBooleanResult, stable));
}
}
+ return Pair.create(primaryKey, topEquations(method, argumentTypes, isReferenceResult, isInterestingResult, stable));
+ }
+ catch (ProcessCanceledException e) {
+ throw e;
+ }
+ catch (Throwable e) {
+ // incorrect bytecode may result in Runtime exceptions during analysis
+ // so here we suppose that exception is due to incorrect bytecode
+ LOG.debug("Unexpected Error during processing of " + method + " in " + presentableUrl, e);
+ return Pair.create(primaryKey, topEquations(method, argumentTypes, isReferenceResult, isInterestingResult, stable));
+ }
+ }
- if (graph.transitions.length > 0) {
- DFSTree dfs = cfg.buildDFSTree(graph.transitions);
- boolean reducible = dfs.back.isEmpty() || cfg.reducible(graph, dfs);
- if (reducible) {
- NotNullLazyValue<TIntHashSet> resultOrigins = new NotNullLazyValue<TIntHashSet>() {
- @NotNull
- @Override
- protected TIntHashSet compute() {
- try {
- return cfg.resultOrigins(className, methodNode);
- }
- catch (AnalyzerException e) {
- throw new RuntimeException(e);
- }
- }
- };
- boolean[] leakingParameters = maybeLeakingParameter ? cfg.leakingParameters(className, methodNode) : null;
- boolean shouldComputeResult = isReferenceResult;
-
- if (!shouldComputeResult && isInterestingResult && maybeLeakingParameter) {
- loop: for (int i = 0; i < argumentTypes.length; i++) {
- Type argType = argumentTypes[i];
- int argSort = argType.getSort();
- boolean isReferenceArg = argSort == Type.OBJECT || argSort == Type.ARRAY;
- boolean isBooleanArg = Type.BOOLEAN_TYPE.equals(argType);
- if ((isReferenceArg || isBooleanArg) && !leakingParameters[i]) {
- shouldComputeResult = true;
- break loop;
- }
- }
+ private List<Equation<Key, Value>> processBranchingMethod(final Method method,
+ final MethodNode methodNode,
+ final RichControlFlow richControlFlow,
+ Type[] argumentTypes,
+ boolean isReferenceResult,
+ boolean isInterestingResult,
+ final boolean stable,
+ boolean jsr) throws AnalyzerException {
+
+ List<Equation<Key, Value>> result = new ArrayList<Equation<Key, Value>>(argumentTypes.length * 4 + 1);
+ boolean maybeLeakingParameter = isInterestingResult;
+ for (Type argType : argumentTypes) {
+ if (ASMUtils.isReferenceType(argType) || (isReferenceResult && ASMUtils.isBooleanType(argType))) {
+ maybeLeakingParameter = true;
+ break;
+ }
+ }
+
+ final LeakingParameters leakingParametersAndFrames =
+ maybeLeakingParameter ? leakingParametersAndFrames(method, methodNode, argumentTypes, jsr) : null;
+ boolean[] leakingParameters =
+ leakingParametersAndFrames != null ? leakingParametersAndFrames.parameters : null;
+ boolean[] leakingNullableParameters =
+ leakingParametersAndFrames != null ? leakingParametersAndFrames.nullableParameters : null;
+
+ final NullableLazyValue<boolean[]> origins = new NullableLazyValue<boolean[]>() {
+ @Override
+ protected boolean[] compute() {
+ try {
+ return OriginsAnalysis.resultOrigins(leakingParametersAndFrames.frames, methodNode.instructions, richControlFlow.controlFlow);
+ }
+ catch (AnalyzerException e) {
+ LOG.debug("when processing " + method + " in " + presentableUrl, e);
+ return null;
+ }
+ }
+ };
+
+ NotNullLazyValue<Equation<Key, Value>> outEquation = new NotNullLazyValue<Equation<Key, Value>>() {
+ @NotNull
+ @Override
+ protected Equation<Key, Value> compute() {
+ if (origins.getValue() != null) {
+ try {
+ return new InOutAnalysis(richControlFlow, new Out(), origins.getValue(), stable).analyze();
+ }
+ catch (AnalyzerException ignored) {
}
+ }
+ return new Equation<Key, Value>(new Key(method, new Out(), stable), FINAL_TOP);
+ }
+ };
- Equation<Key, Value> resultEquation =
- shouldComputeResult ? new InOutAnalysis(new RichControlFlow(graph, dfs), new Out(), resultOrigins.getValue(), stable).analyze() : null;
-
- for (int i = 0; i < argumentTypes.length; i++) {
- Type argType = argumentTypes[i];
- int argSort = argType.getSort();
- boolean isReferenceArg = argSort == Type.OBJECT || argSort == Type.ARRAY;
- boolean isBooleanArg = Type.BOOLEAN_TYPE.equals(argType);
- if (isReferenceArg) {
- if (leakingParameters[i]) {
- parameterEquations.add(new NonNullInAnalysis(new RichControlFlow(graph, dfs), new In(i), stable).analyze());
- } else {
- parameterEquations.add(new Equation<Key, Value>(new Key(method, new In(i), stable), new Final<Key, Value>(Value.Top)));
- }
- }
- if (isReferenceArg && isInterestingResult) {
- if (leakingParameters[i]) {
- contractEquations.add(new InOutAnalysis(new RichControlFlow(graph, dfs), new InOut(i, Value.Null), resultOrigins.getValue(), stable).analyze());
- contractEquations.add(new InOutAnalysis(new RichControlFlow(graph, dfs), new InOut(i, Value.NotNull), resultOrigins.getValue(), stable).analyze());
- } else {
- contractEquations.add(new Equation<Key, Value>(new Key(method, new InOut(i, Value.Null), stable), resultEquation.rhs));
- contractEquations.add(new Equation<Key, Value>(new Key(method, new InOut(i, Value.NotNull), stable), resultEquation.rhs));
- }
+ if (isReferenceResult) {
+ result.add(outEquation.getValue());
+ }
+
+ for (int i = 0; i < argumentTypes.length; i++) {
+ boolean isReferenceArg = ASMUtils.isReferenceType(argumentTypes[i]);
+ boolean notNullParam = false;
+
+ if (isReferenceArg) {
+ boolean possibleNPE = false;
+ if (leakingParameters[i]) {
+ NonNullInAnalysis notNullInAnalysis = new NonNullInAnalysis(richControlFlow, new In(i, In.NOT_NULL), stable);
+ Equation<Key, Value> notNullParamEquation = notNullInAnalysis.analyze();
+ possibleNPE = notNullInAnalysis.possibleNPE;
+ notNullParam = notNullParamEquation.rhs.equals(FINAL_NOT_NULL);
+ result.add(notNullParamEquation);
+ }
+ else {
+ // parameter is not leaking, so it is definitely NOT @NotNull
+ result.add(new Equation<Key, Value>(new Key(method, new In(i, In.NOT_NULL), stable), FINAL_TOP));
+ }
+ if (leakingNullableParameters[i]) {
+ if (notNullParam || possibleNPE) {
+ result.add(new Equation<Key, Value>(new Key(method, new In(i, In.NULLABLE), stable), FINAL_TOP));
+ }
+ else {
+ result.add(new NullableInAnalysis(richControlFlow, new In(i, In.NULLABLE), stable).analyze());
+ }
+ }
+ else {
+ result.add(new Equation<Key, Value>(new Key(method, new In(i, In.NULLABLE), stable), FINAL_NULL));
+ }
+ }
+ if (isReferenceArg && isInterestingResult) {
+ if (leakingParameters[i]) {
+ if (origins.getValue() != null) {
+ // result origins analysis was ok
+ if (!notNullParam) {
+ // may be null on some branch, running "null->..." analysis
+ result.add(new InOutAnalysis(richControlFlow, new InOut(i, Value.Null), origins.getValue(), stable).analyze());
}
- if (isBooleanArg && isInterestingResult) {
- if (leakingParameters[i]) {
- contractEquations.add(new InOutAnalysis(new RichControlFlow(graph, dfs), new InOut(i, Value.False), resultOrigins.getValue(), stable).analyze());
- contractEquations.add(new InOutAnalysis(new RichControlFlow(graph, dfs), new InOut(i, Value.True), resultOrigins.getValue(), stable).analyze());
- } else {
- contractEquations.add(new Equation<Key, Value>(new Key(method, new InOut(i, Value.False), stable), resultEquation.rhs));
- contractEquations.add(new Equation<Key, Value>(new Key(method, new InOut(i, Value.True), stable), resultEquation.rhs));
- }
+ else {
+ // @NotNull, so "null->fail"
+ result.add(new Equation<Key, Value>(new Key(method, new InOut(i, Value.Null), stable), FINAL_BOT));
}
+ result.add(new InOutAnalysis(richControlFlow, new InOut(i, Value.NotNull), origins.getValue(), stable).analyze());
}
- if (isReferenceResult) {
- if (resultEquation != null) {
- contractEquations.add(resultEquation);
- } else {
- contractEquations.add(new InOutAnalysis(new RichControlFlow(graph, dfs), new Out(), resultOrigins.getValue(), stable).analyze());
- }
+ else {
+ // result origins analysis failed, approximating to Top
+ result.add(new Equation<Key, Value>(new Key(method, new InOut(i, Value.Null), stable), FINAL_TOP));
+ result.add(new Equation<Key, Value>(new Key(method, new InOut(i, Value.NotNull), stable), FINAL_TOP));
}
- added = true;
}
else {
- LOG.debug("CFG for " + method + " is not reducible");
+ // parameter is not leaking, so a contract is the same as for the whole method
+ result.add(new Equation<Key, Value>(new Key(method, new InOut(i, Value.Null), stable), outEquation.getValue().rhs));
+ result.add(new Equation<Key, Value>(new Key(method, new InOut(i, Value.NotNull), stable), outEquation.getValue().rhs));
}
}
-
- if (!added) {
- method = new Method(className, methodNode.name, methodNode.desc);
- for (int i = 0; i < argumentTypes.length; i++) {
- Type argType = argumentTypes[i];
- int argSort = argType.getSort();
- boolean isReferenceArg = argSort == Type.OBJECT || argSort == Type.ARRAY;
- boolean isBooleanArg = Type.BOOLEAN_TYPE.equals(argType);
-
- if (isReferenceArg) {
- parameterEquations.add(new Equation<Key, Value>(new Key(method, new In(i), stable), new Final<Key, Value>(Value.Top)));
- }
- if (isReferenceArg && isInterestingResult) {
- contractEquations.add(new Equation<Key, Value>(new Key(method, new InOut(i, Value.Null), stable), new Final<Key, Value>(Value.Top)));
- contractEquations.add(new Equation<Key, Value>(new Key(method, new InOut(i, Value.NotNull), stable), new Final<Key, Value>(Value.Top)));
+ if (ASMUtils.isBooleanType(argumentTypes[i]) && isInterestingResult) {
+ if (leakingParameters[i]) {
+ if (origins.getValue() != null) {
+ // result origins analysis was ok
+ result.add(new InOutAnalysis(richControlFlow, new InOut(i, Value.False), origins.getValue(), stable).analyze());
+ result.add(new InOutAnalysis(richControlFlow, new InOut(i, Value.True), origins.getValue(), stable).analyze());
}
- if (isBooleanArg && isInterestingResult) {
- contractEquations.add(new Equation<Key, Value>(new Key(method, new InOut(i, Value.False), stable), new Final<Key, Value>(Value.Top)));
- contractEquations.add(new Equation<Key, Value>(new Key(method, new InOut(i, Value.True), stable), new Final<Key, Value>(Value.Top)));
+ else {
+ // result origins analysis failed, approximating to Top
+ result.add(new Equation<Key, Value>(new Key(method, new InOut(i, Value.False), stable), FINAL_TOP));
+ result.add(new Equation<Key, Value>(new Key(method, new InOut(i, Value.True), stable), FINAL_TOP));
}
}
- if (isReferenceResult) {
- contractEquations.add(new Equation<Key, Value>(new Key(method, new Out(), stable), new Final<Key, Value>(Value.Top)));
+ else {
+ // parameter is not leaking, so a contract is the same as for the whole method
+ result.add(new Equation<Key, Value>(new Key(method, new InOut(i, Value.False), stable), outEquation.getValue().rhs));
+ result.add(new Equation<Key, Value>(new Key(method, new InOut(i, Value.True), stable), outEquation.getValue().rhs));
}
}
}
- catch (ProcessCanceledException e) {
- throw e;
+ return result;
+ }
+
+ private List<Equation<Key, Value>> processNonBranchingMethod(Method method,
+ Type[] argumentTypes,
+ ControlFlowGraph graph,
+ boolean isReferenceResult,
+ boolean isBooleanResult,
+ boolean stable) throws AnalyzerException {
+ List<Equation<Key, Value>> result = new ArrayList<Equation<Key, Value>>(argumentTypes.length * 4 + 1);
+ CombinedSingleAnalysis analyzer = new CombinedSingleAnalysis(method, graph);
+ analyzer.analyze();
+ if (isReferenceResult) {
+ result.add(analyzer.outContractEquation(stable));
}
- catch (Throwable e) {
- // incorrect bytecode may result in Runtime exceptions during analysis
- // so here we suppose that exception is due to incorrect bytecode
- LOG.debug("Unexpected Error during processing of " + method, e);
+ for (int i = 0; i < argumentTypes.length; i++) {
+ Type argType = argumentTypes[i];
+ boolean isRefArg = ASMUtils.isReferenceType(argType);
+ if (isRefArg) {
+ result.add(analyzer.notNullParamEquation(i, stable));
+ result.add(analyzer.nullableParamEquation(i, stable));
+ }
+ if (isRefArg && (isReferenceResult || isBooleanResult)) {
+ result.add(analyzer.contractEquation(i, Value.Null, stable));
+ result.add(analyzer.contractEquation(i, Value.NotNull, stable));
+ }
+ if (ASMUtils.isBooleanType(argType) && (isReferenceResult || isBooleanResult)) {
+ result.add(analyzer.contractEquation(i, Value.True, stable));
+ result.add(analyzer.contractEquation(i, Value.False, stable));
+ }
}
+ return result;
+ }
+
+ private List<Equation<Key, Value>> topEquations(Method method,
+ Type[] argumentTypes,
+ boolean isReferenceResult,
+ boolean isInterestingResult,
+ boolean stable) {
+ List<Equation<Key, Value>> result = new ArrayList<Equation<Key, Value>>(argumentTypes.length * 3 + 1);
+ if (isReferenceResult) {
+ result.add(new Equation<Key, Value>(new Key(method, new Out(), stable), FINAL_TOP));
+ }
+ for (int i = 0; i < argumentTypes.length; i++) {
+ Type argType = argumentTypes[i];
+ boolean isReferenceArg = ASMUtils.isReferenceType(argType);
+ boolean isBooleanArg = ASMUtils.isBooleanType(argType);
+
+ if (isReferenceArg) {
+ result.add(new Equation<Key, Value>(new Key(method, new In(i, In.NOT_NULL), stable), FINAL_TOP));
+ result.add(new Equation<Key, Value>(new Key(method, new In(i, In.NULLABLE), stable), FINAL_TOP));
+ }
+ if (isReferenceArg && isInterestingResult) {
+ result.add(new Equation<Key, Value>(new Key(method, new InOut(i, Value.Null), stable), FINAL_TOP));
+ result.add(new Equation<Key, Value>(new Key(method, new InOut(i, Value.NotNull), stable), FINAL_TOP));
+ }
+ if (isBooleanArg && isInterestingResult) {
+ result.add(new Equation<Key, Value>(new Key(method, new InOut(i, Value.False), stable), FINAL_TOP));
+ result.add(new Equation<Key, Value>(new Key(method, new InOut(i, Value.True), stable), FINAL_TOP));
+ }
+ }
+ return result;
+ }
+
+ private LeakingParameters leakingParametersAndFrames(Method method, MethodNode methodNode, Type[] argumentTypes, boolean jsr)
+ throws AnalyzerException {
+ return argumentTypes.length < 32 ?
+ LeakingParameters.buildFast(method.internalClassName, methodNode, jsr) :
+ LeakingParameters.build(method.internalClassName, methodNode, jsr);
}
}, ClassReader.SKIP_DEBUG | ClassReader.SKIP_FRAMES);
- return new ClassEquations(parameterEquations, contractEquations);
+ return equations;
}
}