diff options
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.java | 425 |
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; } } |