1 19 20 package edu.umd.cs.findbugs.ba.type; 21 22 import java.util.HashMap ; 23 import java.util.Iterator ; 24 import java.util.Map ; 25 26 import org.apache.bcel.Constants; 27 import org.apache.bcel.classfile.Attribute; 28 import org.apache.bcel.classfile.Method; 29 import org.apache.bcel.classfile.Signature; 30 import org.apache.bcel.generic.ATHROW; 31 import org.apache.bcel.generic.ArrayType; 32 import org.apache.bcel.generic.CodeExceptionGen; 33 import org.apache.bcel.generic.ConstantPoolGen; 34 import org.apache.bcel.generic.ExceptionThrower; 35 import org.apache.bcel.generic.Instruction; 36 import org.apache.bcel.generic.InstructionHandle; 37 import org.apache.bcel.generic.InvokeInstruction; 38 import org.apache.bcel.generic.MethodGen; 39 import org.apache.bcel.generic.ObjectType; 40 import org.apache.bcel.generic.ReferenceType; 41 import org.apache.bcel.generic.Type; 42 43 import edu.umd.cs.findbugs.DeepSubtypeAnalysis; 44 import edu.umd.cs.findbugs.SystemProperties; 45 import edu.umd.cs.findbugs.annotations.CheckForNull; 46 import edu.umd.cs.findbugs.ba.AnalysisContext; 47 import edu.umd.cs.findbugs.ba.AnalysisFeatures; 48 import edu.umd.cs.findbugs.ba.BasicBlock; 49 import edu.umd.cs.findbugs.ba.CFG; 50 import edu.umd.cs.findbugs.ba.CFGBuilderException; 51 import edu.umd.cs.findbugs.ba.ClassContext; 52 import edu.umd.cs.findbugs.ba.Dataflow; 53 import edu.umd.cs.findbugs.ba.DataflowAnalysis; 54 import edu.umd.cs.findbugs.ba.DataflowAnalysisException; 55 import edu.umd.cs.findbugs.ba.DataflowTestDriver; 56 import edu.umd.cs.findbugs.ba.DepthFirstSearch; 57 import edu.umd.cs.findbugs.ba.Edge; 58 import edu.umd.cs.findbugs.ba.EdgeTypes; 59 import edu.umd.cs.findbugs.ba.FrameDataflowAnalysis; 60 import edu.umd.cs.findbugs.ba.Hierarchy; 61 import edu.umd.cs.findbugs.ba.Location; 62 import edu.umd.cs.findbugs.ba.MissingClassException; 63 import edu.umd.cs.findbugs.ba.ObjectTypeFactory; 64 import edu.umd.cs.findbugs.ba.RepositoryLookupFailureCallback; 65 import edu.umd.cs.findbugs.ba.SignatureConverter; 66 import edu.umd.cs.findbugs.ba.generic.GenericSignatureParser; 67 import edu.umd.cs.findbugs.ba.generic.GenericUtilities; 68 import edu.umd.cs.findbugs.ba.vna.ValueNumber; 69 import edu.umd.cs.findbugs.ba.vna.ValueNumberDataflow; 70 import edu.umd.cs.findbugs.ba.vna.ValueNumberFrame; 71 72 88 public class TypeAnalysis extends FrameDataflowAnalysis<Type, TypeFrame> 89 implements EdgeTypes { 90 91 public static final boolean DEBUG = SystemProperties.getBoolean("ta.debug"); 92 93 96 public static final boolean FORCE_ACCURATE_EXCEPTIONS =SystemProperties.getBoolean("ta.accurateExceptions"); 97 98 105 private class CachedExceptionSet { 106 private TypeFrame result; 107 private ExceptionSet exceptionSet; 108 private Map <Edge, ExceptionSet> edgeExceptionMap; 109 110 public CachedExceptionSet(TypeFrame result, ExceptionSet exceptionSet) { 111 this.result = result; 112 this.exceptionSet = exceptionSet; 113 this.edgeExceptionMap = new HashMap <Edge, ExceptionSet>(); 114 } 115 116 public boolean isUpToDate(TypeFrame result) { 117 return this.result.equals(result); 118 } 119 120 public ExceptionSet getExceptionSet() { 121 return exceptionSet; 122 } 123 124 public void setEdgeExceptionSet(Edge edge, ExceptionSet exceptionSet) { 125 edgeExceptionMap.put(edge, exceptionSet); 126 } 127 128 public ExceptionSet getEdgeExceptionSet(Edge edge) { 129 ExceptionSet edgeExceptionSet = edgeExceptionMap.get(edge); 130 if (edgeExceptionSet == null) { 131 edgeExceptionSet = exceptionSetFactory.createExceptionSet(); 132 edgeExceptionMap.put(edge, edgeExceptionSet); 133 } 134 return edgeExceptionSet; 135 } 136 } 137 138 141 static class InstanceOfCheck { 142 final ValueNumber valueNumber; 143 final Type type; 144 145 InstanceOfCheck(ValueNumber valueNumber, Type type) { 146 this.valueNumber = valueNumber; 147 this.type = type; 148 } 149 150 153 public ValueNumber getValueNumber() { 154 return valueNumber; 155 } 156 157 160 public Type getType() { 161 return type; 162 } 163 } 164 165 protected MethodGen methodGen; 166 protected CFG cfg; 167 private TypeMerger typeMerger; 168 private TypeFrameModelingVisitor visitor; 169 private Map <BasicBlock, CachedExceptionSet> thrownExceptionSetMap; 170 private RepositoryLookupFailureCallback lookupFailureCallback; 171 private ExceptionSetFactory exceptionSetFactory; 172 private ValueNumberDataflow valueNumberDataflow; 173 private Map <BasicBlock, InstanceOfCheck> instanceOfCheckMap; 174 175 187 public TypeAnalysis(MethodGen methodGen, CFG cfg, DepthFirstSearch dfs, 188 TypeMerger typeMerger, TypeFrameModelingVisitor visitor, 189 RepositoryLookupFailureCallback lookupFailureCallback, 190 ExceptionSetFactory exceptionSetFactory) { 191 super(dfs); 192 this.methodGen = methodGen; 193 this.cfg = cfg; 194 this.typeMerger = typeMerger; 195 this.visitor = visitor; 196 this.thrownExceptionSetMap = new HashMap <BasicBlock, CachedExceptionSet>(); 197 this.lookupFailureCallback = lookupFailureCallback; 198 this.exceptionSetFactory = exceptionSetFactory; 199 this.instanceOfCheckMap = new HashMap <BasicBlock, InstanceOfCheck>(); 200 if (DEBUG) { 201 System.out.println("\n\nAnalyzing " + methodGen); 202 } 203 } 204 205 215 public TypeAnalysis(MethodGen methodGen, CFG cfg, DepthFirstSearch dfs, 216 TypeMerger typeMerger, RepositoryLookupFailureCallback lookupFailureCallback, 217 ExceptionSetFactory exceptionSetFactory) { 218 this(methodGen, cfg, dfs, typeMerger, 219 new TypeFrameModelingVisitor(methodGen.getConstantPool()), lookupFailureCallback, 220 exceptionSetFactory); 221 } 222 223 232 public TypeAnalysis(MethodGen methodGen, CFG cfg, DepthFirstSearch dfs, 233 RepositoryLookupFailureCallback lookupFailureCallback, 234 ExceptionSetFactory exceptionSetFactory) { 235 this(methodGen, cfg, dfs, 236 new StandardTypeMerger(lookupFailureCallback, exceptionSetFactory), 237 lookupFailureCallback, exceptionSetFactory); 238 } 239 240 247 public void setValueNumberDataflow(ValueNumberDataflow valueNumberDataflow) { 248 this.valueNumberDataflow = valueNumberDataflow; 249 this.visitor.setValueNumberDataflow(valueNumberDataflow); 250 } 251 252 259 public void setFieldStoreTypeDatabase(FieldStoreTypeDatabase database) { 260 visitor.setFieldStoreTypeDatabase(database); 261 } 262 263 270 public ExceptionSet getEdgeExceptionSet(Edge edge) { 271 CachedExceptionSet cachedExceptionSet = thrownExceptionSetMap.get(edge.getSource()); 272 return cachedExceptionSet.getEdgeExceptionSet(edge); 273 } 274 275 public TypeFrame createFact() { 276 return new TypeFrame(methodGen.getMaxLocals()); 277 } 278 279 public void initEntryFact(TypeFrame result) { 280 result.setValid(); 282 283 int slot = 0; 284 285 result.clearStack(); 287 288 if (!methodGen.isStatic()) 290 result.setValue(slot++, ObjectTypeFactory.getInstance(methodGen.getClassName())); 291 292 Iterator <String > iter = 297 GenericSignatureParser.getGenericSignatureIterator(methodGen.getMethod()); 298 299 Type[] argumentTypes = methodGen.getArgumentTypes(); 303 for (Type argType : argumentTypes) { 304 if (argType.getType() == Constants.T_LONG) { 307 result.setValue(slot++, TypeFrame.getLongExtraType()); 308 } else if (argType.getType() == Constants.T_DOUBLE) { 309 result.setValue(slot++, TypeFrame.getDoubleExtraType()); 310 } 311 312 String s = ( iter == null || !iter.hasNext() )? null : iter.next(); 314 if ( s != null && 315 (argType instanceof ObjectType || argType instanceof ArrayType) && 316 !(argType instanceof ExceptionObjectType) 317 ) { 318 try { 320 argType = GenericUtilities.getType(s); 321 } catch (RuntimeException e) {} } 323 324 result.setValue(slot++, argType); 326 } 327 328 while (slot < methodGen.getMaxLocals()) 331 result.setValue(slot++, TypeFrame.getBottomType()); 332 } 333 334 @Override 335 public void copy(TypeFrame source, TypeFrame dest) { 336 dest.copyFrom(source); 337 } 338 339 @Override 340 public void initResultFact(TypeFrame result) { 341 result.setTop(); 346 } 347 348 @Override 349 public void makeFactTop(TypeFrame fact) { 350 fact.setTop(); 351 } 352 353 @Override 354 public boolean isFactValid(TypeFrame fact) { 355 return fact.isValid(); 356 } 357 358 @Override 359 public boolean same(TypeFrame fact1, TypeFrame fact2) { 360 return fact1.sameAs(fact2); 361 } 362 363 @Override 364 public void transferInstruction(InstructionHandle handle, BasicBlock basicBlock, TypeFrame fact) 365 throws DataflowAnalysisException { 366 visitor.setFrameAndLocation(fact, new Location(handle, basicBlock)); 367 visitor.analyzeInstruction(handle.getInstruction()); 368 } 369 370 373 @Override 374 public void transfer(BasicBlock basicBlock, @CheckForNull InstructionHandle end, TypeFrame start, TypeFrame result) throws DataflowAnalysisException { 375 visitor.startBasicBlock(); 376 377 super.transfer(basicBlock, end, start, result); 378 379 computeThrownExceptionTypes(basicBlock, end, result); 381 if (DEBUG) { 382 System.out.println("After " + basicBlock.getFirstInstruction() + " -> " + basicBlock.getLastInstruction()); 383 System.out.println(" frame: " + result); 384 } 385 386 instanceOfCheckMap.remove(basicBlock); 389 if (visitor.isInstanceOfFollowedByBranch()) { 390 InstanceOfCheck check = new InstanceOfCheck(visitor.getInstanceOfValueNumber(), visitor.getInstanceOfType()); 391 instanceOfCheckMap.put(basicBlock, check); 392 } 393 } 394 395 private void computeThrownExceptionTypes(BasicBlock basicBlock, @CheckForNull InstructionHandle end, TypeFrame result) 396 throws DataflowAnalysisException { 397 398 if (!(FORCE_ACCURATE_EXCEPTIONS || 400 AnalysisContext.currentAnalysisContext().getBoolProperty(AnalysisFeatures.ACCURATE_EXCEPTIONS))) 401 return; 402 403 if (!basicBlock.isExceptionThrower()) 405 return; 406 407 CachedExceptionSet cachedExceptionSet = getCachedExceptionSet(basicBlock); 409 if (cachedExceptionSet.isUpToDate((TypeFrame) result)) 410 return; 411 412 417 int exceptionEdgeCount = 0; 418 Edge lastExceptionEdge = null; 419 420 for (Iterator <Edge> i = cfg.outgoingEdgeIterator(basicBlock); i.hasNext();) { 421 Edge e = i.next(); 422 if (e.isExceptionEdge()) { 423 exceptionEdgeCount++; 424 lastExceptionEdge = e; 425 } 426 } 427 428 if (exceptionEdgeCount == 0) { 429 return; 431 } 432 cachedExceptionSet = computeBlockExceptionSet(basicBlock, (TypeFrame) result); 435 436 if (exceptionEdgeCount == 1) { 437 cachedExceptionSet.setEdgeExceptionSet(lastExceptionEdge, cachedExceptionSet.getExceptionSet()); 438 return; 439 } 440 441 442 ExceptionSet thrownExceptionSet = cachedExceptionSet.getExceptionSet(); 448 if (!thrownExceptionSet.isEmpty()) thrownExceptionSet = thrownExceptionSet.duplicate(); 449 for (Iterator <Edge> i = cfg.outgoingEdgeIterator(basicBlock); i.hasNext();) { 450 Edge edge = i.next(); 451 if (edge.isExceptionEdge()) 452 cachedExceptionSet.setEdgeExceptionSet(edge, computeEdgeExceptionSet(edge, thrownExceptionSet)); 453 } 454 } 455 456 public void meetInto(TypeFrame fact, Edge edge, TypeFrame result) throws DataflowAnalysisException { 457 BasicBlock basicBlock = edge.getTarget(); 458 459 if (fact.isValid()) { 460 TypeFrame tmpFact = null; 461 462 if (basicBlock.isExceptionHandler()) { 464 tmpFact = modifyFrame(fact, tmpFact); 465 466 CodeExceptionGen exceptionGen = basicBlock.getExceptionGen(); 471 tmpFact.clearStack(); 472 473 Type catchType = null; 475 476 if (FORCE_ACCURATE_EXCEPTIONS || 477 AnalysisContext.currentAnalysisContext().getBoolProperty(AnalysisFeatures.ACCURATE_EXCEPTIONS)) { 478 try { 479 CachedExceptionSet cachedExceptionSet = getCachedExceptionSet(edge.getSource()); 482 ExceptionSet edgeExceptionSet = cachedExceptionSet.getEdgeExceptionSet(edge); 483 if (!edgeExceptionSet.isEmpty()) { 484 catchType = ExceptionObjectType.fromExceptionSet(edgeExceptionSet); 486 } 487 } catch (ClassNotFoundException e) { 488 lookupFailureCallback.reportMissingClass(e); 489 } 490 } 491 492 if (catchType == null) { 493 catchType = exceptionGen.getCatchType(); 496 if (catchType == null) 497 catchType = Type.THROWABLE; } 499 500 tmpFact.pushValue(catchType); 501 } 502 503 if (valueNumberDataflow != null) { 506 tmpFact = handleInstanceOfBranch(fact, tmpFact, edge); 507 } 508 509 if (tmpFact != null) { 510 fact = tmpFact; 511 } 512 } 513 514 mergeInto(fact, result); 515 } 516 517 private TypeFrame handleInstanceOfBranch(TypeFrame fact, TypeFrame tmpFact, Edge edge) throws DataflowAnalysisException { 518 519 InstanceOfCheck check = instanceOfCheckMap.get(edge.getSource()); 520 if (check == null) { 521 return tmpFact; 523 } 524 525 if (check.getValueNumber() == null) { 526 return tmpFact; 528 } 529 530 ValueNumber instanceOfValueNumber = check.getValueNumber(); 531 532 short branchOpcode = edge.getSource().getLastInstruction().getInstruction().getOpcode(); 533 534 int edgeType = edge.getType(); 535 if ( (edgeType == EdgeTypes.IFCMP_EDGE && 536 (branchOpcode == Constants.IFNE || branchOpcode == Constants.IFGT || branchOpcode == Constants.IFNULL)) 537 538 || (edgeType == EdgeTypes.FALL_THROUGH_EDGE && 539 (branchOpcode == Constants.IFEQ || branchOpcode == Constants.IFLE || branchOpcode == Constants.IFNONNULL)) 540 ) { 541 543 ValueNumberFrame vnaFrame = valueNumberDataflow.getStartFact(edge.getTarget()); 545 if (!vnaFrame.isValid()) 546 return tmpFact; 547 548 Type instanceOfType = check.getType(); 549 if (!(instanceOfType instanceof ReferenceType || instanceOfType instanceof NullType)) 550 return tmpFact; 551 552 int numSlots = Math.min(fact.getNumSlots(), vnaFrame.getNumSlots()); 553 for (int i = 0; i < numSlots; ++i) { 554 if (!vnaFrame.getValue(i).equals(instanceOfValueNumber)) 555 continue; 556 557 Type checkedType = fact.getValue(i); 558 if (!(checkedType instanceof ReferenceType)) 559 continue; 560 561 562 try { 565 boolean feasibleCheck = instanceOfType.equals(NullType.instance()) 566 || Hierarchy.isSubtype( 567 (ReferenceType) instanceOfType, 568 (ReferenceType) checkedType); 569 if (!feasibleCheck && instanceOfType instanceof ObjectType 570 && checkedType instanceof ObjectType) { 571 double v = DeepSubtypeAnalysis.deepInstanceOf(((ObjectType)instanceOfType).getClassName(), 572 ((ObjectType)checkedType).getClassName()); 573 if (v > 0.0) feasibleCheck = true; 574 } 575 tmpFact = modifyFrame(fact, tmpFact); 576 tmpFact.setValue(i, feasibleCheck ? instanceOfType : TopType.instance()); 577 } catch (ClassNotFoundException e) { 578 lookupFailureCallback.reportMissingClass(e); 579 throw new MissingClassException(e); 580 } 581 } 582 } 583 584 return tmpFact; 585 } 586 587 @Override 588 protected void mergeValues(TypeFrame otherFrame, TypeFrame resultFrame, int slot) throws DataflowAnalysisException { 589 Type value = typeMerger.mergeTypes(resultFrame.getValue(slot), otherFrame.getValue(slot)); 590 resultFrame.setValue(slot, value); 591 592 594 boolean typesAreIdentical = 595 otherFrame.getValue(slot).equals(resultFrame.getValue(slot)); 596 597 boolean bothExact = 598 resultFrame.isExact(slot) && otherFrame.isExact(slot); 599 600 resultFrame.setExact(slot, typesAreIdentical && bothExact); 601 } 602 603 612 private CachedExceptionSet getCachedExceptionSet(BasicBlock basicBlock) { 613 CachedExceptionSet cachedExceptionSet = thrownExceptionSetMap.get(basicBlock); 614 if (cachedExceptionSet == null) { 615 622 TypeFrame top = createFact(); 623 makeFactTop(top); 624 cachedExceptionSet = new CachedExceptionSet(top, exceptionSetFactory.createExceptionSet()); 625 626 thrownExceptionSetMap.put(basicBlock, cachedExceptionSet); 627 } 628 629 return cachedExceptionSet; 630 } 631 632 644 private CachedExceptionSet computeBlockExceptionSet(BasicBlock basicBlock, TypeFrame result) 645 throws DataflowAnalysisException { 646 647 ExceptionSet exceptionSet; 648 try { 649 exceptionSet = computeThrownExceptionTypes(basicBlock); 650 } catch (ClassNotFoundException e) { 651 lookupFailureCallback.reportMissingClass(e); 654 exceptionSet = exceptionSetFactory.createExceptionSet(); 655 exceptionSet.addExplicit(Type.THROWABLE); 656 } 657 658 TypeFrame copyOfResult = createFact(); 659 copy(result, copyOfResult); 660 661 CachedExceptionSet cachedExceptionSet = new CachedExceptionSet(copyOfResult, exceptionSet); 662 thrownExceptionSetMap.put(basicBlock, cachedExceptionSet); 663 664 return cachedExceptionSet; 665 } 666 667 683 private ExceptionSet computeEdgeExceptionSet(Edge edge, ExceptionSet thrownExceptionSet) { 684 685 686 if (thrownExceptionSet.isEmpty()) return thrownExceptionSet; 687 ExceptionSet result = exceptionSetFactory.createExceptionSet(); 688 689 if (edge.getType() == UNHANDLED_EXCEPTION_EDGE) { 690 result.addAll(thrownExceptionSet); 693 thrownExceptionSet.clear(); 694 return result; 695 } 696 697 BasicBlock handlerBlock = edge.getTarget(); 698 CodeExceptionGen handler = handlerBlock.getExceptionGen(); 699 ObjectType catchType = handler.getCatchType(); 700 701 if (Hierarchy.isUniversalExceptionHandler(catchType)) { 702 result.addAll(thrownExceptionSet); 703 thrownExceptionSet.clear(); 704 } else { 705 710 for (ExceptionSet.ThrownExceptionIterator i = thrownExceptionSet.iterator(); i.hasNext();) { 711 ObjectType thrownType = i.next(); 713 boolean explicit = i.isExplicit(); 714 715 if (DEBUG) 716 System.out.println("\texception type " + thrownType + 717 ", catch type " + catchType); 718 719 try { 720 if (Hierarchy.isSubtype(thrownType, catchType)) { 721 result.add(thrownType, explicit); 723 724 i.remove(); 726 727 if (DEBUG) 728 System.out.println("\tException is subtype of catch type: " + 729 "will definitely catch"); 730 } else if (Hierarchy.isSubtype(catchType, thrownType)) { 731 result.add(thrownType, explicit); 733 734 if (DEBUG) 735 System.out.println("\tException is supertype of catch type: " + 736 "might catch"); 737 } 738 } catch (ClassNotFoundException e) { 739 AnalysisContext.reportMissingClass(e); 744 result.add(thrownType, explicit); 745 } 746 } 747 } 748 749 return result; 750 } 751 752 759 private ExceptionSet computeThrownExceptionTypes(BasicBlock basicBlock) 760 throws ClassNotFoundException , DataflowAnalysisException { 761 762 ExceptionSet exceptionTypeSet = exceptionSetFactory.createExceptionSet(); 763 InstructionHandle pei = basicBlock.getExceptionThrower(); 764 Instruction ins = pei.getInstruction(); 765 766 ExceptionThrower exceptionThrower = (ExceptionThrower) ins; 769 Class [] exceptionList = exceptionThrower.getExceptions(); 770 for (Class aExceptionList : exceptionList) { 771 exceptionTypeSet.addImplicit(ObjectTypeFactory.getInstance(aExceptionList.getName())); 772 } 773 774 exceptionTypeSet.addImplicit(Hierarchy.ERROR_TYPE); 776 777 if (ins instanceof ATHROW) { 778 789 if (basicBlock.containsInstruction(pei)) { 790 exceptionTypeSet.clear(); 793 794 TypeFrame frame = getStartFact(basicBlock); 798 799 if (!frame.isValid()) { 807 exceptionTypeSet.addExplicit(Type.THROWABLE); 808 } else if (frame.getStackDepth() == 0) { 809 throw new IllegalStateException ("empty stack " + 810 " thrown by " + pei + " in " + 811 SignatureConverter.convertMethodSignature(methodGen)); 812 } else { 813 814 Type throwType = frame.getTopValue(); 815 if (throwType instanceof ObjectType) { 816 exceptionTypeSet.addExplicit((ObjectType) throwType); 817 } else if (throwType instanceof ExceptionObjectType) { 818 exceptionTypeSet.addAll(((ExceptionObjectType) throwType).getExceptionSet()); 819 } else { 820 if (DEBUG) { 823 System.out.println("Non object type " + throwType + 824 " thrown by " + pei + " in " + 825 SignatureConverter.convertMethodSignature(methodGen)); 826 } 827 exceptionTypeSet.addExplicit(Type.THROWABLE); 828 } 829 } 830 } 831 } 832 833 if (ins instanceof InvokeInstruction) { 835 ConstantPoolGen cpg = methodGen.getConstantPool(); 836 837 InvokeInstruction inv = (InvokeInstruction) ins; 838 ObjectType[] declaredExceptionList = Hierarchy.findDeclaredExceptions(inv, cpg); 839 if (declaredExceptionList == null) { 840 if (DEBUG) 843 System.out.println("Couldn't find declared exceptions for " + 844 SignatureConverter.convertMethodSignature(inv, cpg)); 845 exceptionTypeSet.addExplicit(Hierarchy.EXCEPTION_TYPE); 846 } else { 847 for (ObjectType aDeclaredExceptionList : declaredExceptionList) { 848 exceptionTypeSet.addExplicit(aDeclaredExceptionList); 849 } 850 } 851 852 exceptionTypeSet.addImplicit(Hierarchy.RUNTIME_EXCEPTION_TYPE); 853 } 854 855 if (DEBUG) System.out.println(pei + " can throw " + exceptionTypeSet); 856 857 return exceptionTypeSet; 858 } 859 860 public static void main(String [] argv) throws Exception { 861 if (argv.length != 1) { 862 System.err.println("Usage: " + TypeAnalysis.class.getName() + " <class file>"); 863 System.exit(1); 864 } 865 866 DataflowTestDriver<TypeFrame, TypeAnalysis> driver = new DataflowTestDriver<TypeFrame, TypeAnalysis>() { 867 @Override 868 public Dataflow<TypeFrame, TypeAnalysis> createDataflow(ClassContext classContext, Method method) 869 throws CFGBuilderException, DataflowAnalysisException { 870 return classContext.getTypeDataflow(method); 871 } 872 }; 873 874 driver.execute(argv[0]); 875 } 876 } 877 878 | Popular Tags |