├── .github ├── ISSUE_TEMPLATE │ ├── bug_report.md │ ├── feature_request.md │ └── question.md └── workflows │ └── maven.yml ├── .gitignore ├── .gitmodules ├── LICENSE ├── README.md ├── cfr.iml ├── contributing.md ├── decompilation-test ├── src │ └── org │ │ └── benf │ │ └── cfr │ │ └── test │ │ ├── DecompilationTest.java │ │ └── DecompilationTestImplementation.java ├── test-data-expected-output │ └── classes │ │ ├── CondJumpTest2c.10.expected.java │ │ ├── CondJumpTest2c.6.expected.java │ │ ├── EnumTestEmpty.13.expected.java │ │ ├── EnumTestEmpty.6.expected.java │ │ └── TryTest1.10.expected.java └── test-specs │ └── classes.xml ├── pom.xml ├── src-templates └── org │ └── benf │ └── cfr │ └── reader │ └── util │ └── CfrVersionInfo.java └── src └── org └── benf └── cfr └── reader ├── CfrDriverImpl.java ├── Driver.java ├── Main.java ├── PluginRunner.java ├── api ├── CfrDriver.java ├── ClassFileSource.java ├── OutputSinkFactory.java └── SinkReturns.java ├── apiunreleased ├── ClassFileSource2.java └── JarContent.java ├── bytecode ├── AnalysisResult.java ├── AnalysisResultFromException.java ├── AnalysisResultSuccessful.java ├── AnonymousClassUsage.java ├── BytecodeMeta.java ├── CodeAnalyser.java ├── CodeAnalyserWholeClass.java ├── RecoveryOption.java ├── RecoveryOptions.java ├── analysis │ ├── loc │ │ ├── BytecodeLoc.java │ │ ├── BytecodeLocCollector.java │ │ ├── BytecodeLocFactory.java │ │ ├── BytecodeLocFactoryImpl.java │ │ ├── BytecodeLocFactoryStub.java │ │ ├── BytecodeLocSet.java │ │ ├── BytecodeLocSimple.java │ │ ├── BytecodeLocSpecific.java │ │ └── HasByteCodeLoc.java │ ├── opgraph │ │ ├── Graph.java │ │ ├── GraphConversionHelper.java │ │ ├── IndexedStatement.java │ │ ├── InstrIndex.java │ │ ├── MutableGraph.java │ │ ├── Op01WithProcessedDataAndByteJumps.java │ │ ├── Op02WithProcessedDataAndRefs.java │ │ ├── Op03Blocks.java │ │ ├── Op03SimpleStatement.java │ │ ├── Op04StructuredStatement.java │ │ ├── op02obf │ │ │ ├── ControlFlowIntDiv0Exception.java │ │ │ ├── ControlFlowNullException.java │ │ │ ├── ControlFlowNumericObf.java │ │ │ ├── Op02Obf.java │ │ │ └── SimpleControlFlowBase.java │ │ ├── op03obf │ │ │ └── Op03Obf.java │ │ ├── op2rewriters │ │ │ ├── GetClassTest.java │ │ │ ├── GetClassTestInnerConstructor.java │ │ │ ├── GetClassTestLambda.java │ │ │ ├── Op02GetClassRewriter.java │ │ │ ├── Op02RedundantStoreRewriter.java │ │ │ ├── TypeHintRecovery.java │ │ │ ├── TypeHintRecoveryImpl.java │ │ │ └── TypeHintRecoveryNone.java │ │ ├── op3rewriters │ │ │ ├── AnonymousArray.java │ │ │ ├── AnonymousBlocks.java │ │ │ ├── AssertionJumps.java │ │ │ ├── BadBoolAssignmentRewriter.java │ │ │ ├── BadCompareRewriter.java │ │ │ ├── BadNarrowingArgRewriter.java │ │ │ ├── BreakRewriter.java │ │ │ ├── ClassifyGotos.java │ │ │ ├── Cleaner.java │ │ │ ├── CompareByIndex.java │ │ │ ├── CondenseConditionals.java │ │ │ ├── CondenseConstruction.java │ │ │ ├── ConditionalCondenser.java │ │ │ ├── ConditionalRewriter.java │ │ │ ├── ConditionalSimplifier.java │ │ │ ├── DeadConditionalRemover.java │ │ │ ├── DupAssigns.java │ │ │ ├── EclipseLoops.java │ │ │ ├── ExactTypeFilter.java │ │ │ ├── ExceptionRewriters.java │ │ │ ├── FinallyRewriter.java │ │ │ ├── GenericInferer.java │ │ │ ├── InlineDeAssigner.java │ │ │ ├── InstanceConstants.java │ │ │ ├── IsolatedStackValue.java │ │ │ ├── IterLoopRewriter.java │ │ │ ├── JoinBlocks.java │ │ │ ├── JumpsIntoDoRewriter.java │ │ │ ├── JumpsIntoLoopCloneRewriter.java │ │ │ ├── KotlinSwitchHandler.java │ │ │ ├── LValueCondense.java │ │ │ ├── LValueProp.java │ │ │ ├── LValuePropSimple.java │ │ │ ├── LinearScannedBlock.java │ │ │ ├── LoopIdentifier.java │ │ │ ├── LoopLivenessClash.java │ │ │ ├── Misc.java │ │ │ ├── MonitorRewriter.java │ │ │ ├── NOPSearchingExpressionRewriter.java │ │ │ ├── NarrowingTypeRewriter.java │ │ │ ├── NegativeJumps.java │ │ │ ├── NullTypedLValueRewriter.java │ │ │ ├── Op03Rewriters.java │ │ │ ├── PointlessExpressions.java │ │ │ ├── PointlessJumps.java │ │ │ ├── PrePostchangeAssignmentRewriter.java │ │ │ ├── PushThroughGoto.java │ │ │ ├── RedundantTries.java │ │ │ ├── RemoveDeterministicJumps.java │ │ │ ├── ReturnRewriter.java │ │ │ ├── StatementEquivalenceConstraint.java │ │ │ ├── StaticInitReturnRewriter.java │ │ │ ├── StaticInstanceCondenser.java │ │ │ ├── SwitchReplacer.java │ │ │ ├── SwitchUtils.java │ │ │ ├── SynchronizedBlocks.java │ │ │ ├── SynchronizedRewriter.java │ │ │ ├── TryRewriter.java │ │ │ ├── TypeFilter.java │ │ │ ├── UselessNops.java │ │ │ └── WhileRewriter.java │ │ └── op4rewriters │ │ │ ├── AnonymousClassConstructorRewriter.java │ │ │ ├── AssertRewriter.java │ │ │ ├── BadCastChainRewriter.java │ │ │ ├── ClashDeclarationReducer.java │ │ │ ├── EnumAllSuperRewriter.java │ │ │ ├── EnumClassRewriter.java │ │ │ ├── EnumSuperRewriter.java │ │ │ ├── ExpressionReplacingRewriter.java │ │ │ ├── ExpressionWildcardReplacingRewriter.java │ │ │ ├── FakeMethodRewriter.java │ │ │ ├── IllegalGenericRewriter.java │ │ │ ├── InnerClassConstructorRewriter.java │ │ │ ├── InstanceofMatchTidyingRewriter.java │ │ │ ├── J14ClassObjectRewriter.java │ │ │ ├── LValueReplacingRewriter.java │ │ │ ├── LambdaRewriter.java │ │ │ ├── LocalInlinedStringConstantRewriter.java │ │ │ ├── NarrowingAssignmentRewriter.java │ │ │ ├── NonStaticLifter.java │ │ │ ├── Op04Rewriter.java │ │ │ ├── PointlessStructuredExpressions.java │ │ │ ├── PrimitiveBoxingRewriter.java │ │ │ ├── RecordRewriter.java │ │ │ ├── RedundantSuperRewriter.java │ │ │ ├── ResourceReleaseDetector.java │ │ │ ├── RetroLambdaRewriter.java │ │ │ ├── ScopeHidingVariableRewriter.java │ │ │ ├── SealedClassChecker.java │ │ │ ├── StaticLifter.java │ │ │ ├── SwitchEnumRewriter.java │ │ │ ├── SwitchExpressionRewriter.java │ │ │ ├── SwitchStringRewriter.java │ │ │ ├── SyntheticAccessorRewriter.java │ │ │ ├── SyntheticOuterRefRewriter.java │ │ │ ├── UnreachableStaticRewriter.java │ │ │ ├── VarArgsRewriter.java │ │ │ ├── checker │ │ │ ├── IllegalReturnChecker.java │ │ │ ├── LooseCatchChecker.java │ │ │ ├── Op04Checker.java │ │ │ └── VoidVariableChecker.java │ │ │ ├── matchutil │ │ │ ├── AbstractMatchResultIterator.java │ │ │ ├── CollectMatch.java │ │ │ ├── DeadMethodRemover.java │ │ │ ├── EmptyMatchResultCollector.java │ │ │ ├── KleeneN.java │ │ │ ├── KleenePlus.java │ │ │ ├── KleeneStar.java │ │ │ ├── MatchIterator.java │ │ │ ├── MatchOneOf.java │ │ │ ├── MatchOpt.java │ │ │ ├── MatchResultCollector.java │ │ │ ├── MatchSequence.java │ │ │ ├── Matcher.java │ │ │ └── ResetAfterTest.java │ │ │ ├── transformers │ │ │ ├── BadLoopPrettifier.java │ │ │ ├── CanRemovePointlessBlock.java │ │ │ ├── ControlFlowCleaningTransformer.java │ │ │ ├── ExpressionRewriterTransformer.java │ │ │ ├── HexLiteralTidier.java │ │ │ ├── InfiniteAssertRewriter.java │ │ │ ├── InstanceOfAssignRewriter.java │ │ │ ├── InstanceOfTreeTransformer.java │ │ │ ├── InvalidBooleanCastCleaner.java │ │ │ ├── InvalidExpressionStatementCleaner.java │ │ │ ├── LValueTypeClashCheck.java │ │ │ ├── LambdaCleaner.java │ │ │ ├── LocalDeclarationRemover.java │ │ │ ├── NakedNullCaster.java │ │ │ ├── ObjectTypeUsageRewriter.java │ │ │ ├── PreconditionAssertRewriter.java │ │ │ ├── RedundantIntersectionCastTransformer.java │ │ │ ├── StructuredStatementTransformer.java │ │ │ ├── TernaryCastCleaner.java │ │ │ ├── TryResourceTransformerFinally.java │ │ │ ├── TryResourcesCollapser.java │ │ │ ├── TryResourcesTransformerBase.java │ │ │ ├── TryResourcesTransformerJ12.java │ │ │ ├── TryResourcesTransformerJ7.java │ │ │ ├── TryResourcesTransformerJ9.java │ │ │ ├── TypeAnnotationTransformer.java │ │ │ ├── TypedBooleanTidier.java │ │ │ ├── UnusedAnonymousBlockFlattener.java │ │ │ └── VariableNameTidier.java │ │ │ └── util │ │ │ ├── BoxingHelper.java │ │ │ ├── ConstructorUtils.java │ │ │ └── MiscStatementTools.java │ ├── parse │ │ ├── Expression.java │ │ ├── LValue.java │ │ ├── Statement.java │ │ ├── StatementContainer.java │ │ ├── expression │ │ │ ├── AbstractAssignmentExpression.java │ │ │ ├── AbstractConstructorInvokation.java │ │ │ ├── AbstractExpression.java │ │ │ ├── AbstractFunctionInvokation.java │ │ │ ├── AbstractFunctionInvokationExplicit.java │ │ │ ├── AbstractMemberFunctionInvokation.java │ │ │ ├── AbstractMutatingAssignmentExpression.java │ │ │ ├── AbstractNewArray.java │ │ │ ├── ArithOp.java │ │ │ ├── ArithmeticMonOperation.java │ │ │ ├── ArithmeticMutationOperation.java │ │ │ ├── ArithmeticOperation.java │ │ │ ├── ArithmeticPostMutationOperation.java │ │ │ ├── ArithmeticPreMutationOperation.java │ │ │ ├── ArrayIndex.java │ │ │ ├── ArrayLength.java │ │ │ ├── AssignmentExpression.java │ │ │ ├── BoolOp.java │ │ │ ├── BooleanExpression.java │ │ │ ├── BooleanOperation.java │ │ │ ├── CastExpression.java │ │ │ ├── CompOp.java │ │ │ ├── ComparisonOperation.java │ │ │ ├── ConditionalExpression.java │ │ │ ├── ConstructorInvokationAnonymousInner.java │ │ │ ├── ConstructorInvokationExplicit.java │ │ │ ├── ConstructorInvokationSimple.java │ │ │ ├── DynamicConstExpression.java │ │ │ ├── DynamicInvokation.java │ │ │ ├── InstanceOfExpression.java │ │ │ ├── InstanceOfExpressionDefining.java │ │ │ ├── LValueExpression.java │ │ │ ├── LambdaExpression.java │ │ │ ├── LambdaExpressionCommon.java │ │ │ ├── LambdaExpressionFallback.java │ │ │ ├── LambdaExpressionNewArray.java │ │ │ ├── Literal.java │ │ │ ├── LiteralHex.java │ │ │ ├── MemberFunctionInvokation.java │ │ │ ├── MemberFunctionInvokationExplicit.java │ │ │ ├── MethodHandlePlaceholder.java │ │ │ ├── NewAnonymousArray.java │ │ │ ├── NewObject.java │ │ │ ├── NewObjectArray.java │ │ │ ├── NewPrimitiveArray.java │ │ │ ├── NotOperation.java │ │ │ ├── StackValue.java │ │ │ ├── StaticFunctionInvokation.java │ │ │ ├── StaticFunctionInvokationExplicit.java │ │ │ ├── SuperFunctionInvokation.java │ │ │ ├── SwitchExpression.java │ │ │ ├── TernaryExpression.java │ │ │ ├── misc │ │ │ │ └── Precedence.java │ │ │ └── rewriteinterface │ │ │ │ ├── BoxingProcessor.java │ │ │ │ └── FunctionProcessor.java │ │ ├── literal │ │ │ ├── LiteralFolding.java │ │ │ └── TypedLiteral.java │ │ ├── lvalue │ │ │ ├── AbstractFieldVariable.java │ │ │ ├── AbstractLValue.java │ │ │ ├── ArrayVariable.java │ │ │ ├── FieldVariable.java │ │ │ ├── LocalVariable.java │ │ │ ├── SentinelLocalClassLValue.java │ │ │ ├── StackSSALabel.java │ │ │ └── StaticVariable.java │ │ ├── rewriters │ │ │ ├── AbstractExpressionRewriter.java │ │ │ ├── AbstractExpressionVisitor.java │ │ │ ├── AccountingRewriter.java │ │ │ ├── CloneHelper.java │ │ │ ├── ConditionalSimplifyingRewriter.java │ │ │ ├── ConstantFoldingRewriter.java │ │ │ ├── DeepCloneable.java │ │ │ ├── ExplicitTypeCallRewriter.java │ │ │ ├── ExpressionRewriter.java │ │ │ ├── ExpressionRewriterFlags.java │ │ │ ├── ExpressionRewriterHelper.java │ │ │ ├── ExpressionVisitor.java │ │ │ ├── LiteralRewriter.java │ │ │ ├── StackVarToLocalRewriter.java │ │ │ ├── StringBuilderRewriter.java │ │ │ └── XorRewriter.java │ │ ├── statement │ │ │ ├── AbstractAssignment.java │ │ │ ├── AbstractStatement.java │ │ │ ├── AnonBreakTarget.java │ │ │ ├── AssignmentPreMutation.java │ │ │ ├── AssignmentSimple.java │ │ │ ├── CaseStatement.java │ │ │ ├── CatchStatement.java │ │ │ ├── CommentStatement.java │ │ │ ├── CompoundStatement.java │ │ │ ├── ConstructorStatement.java │ │ │ ├── DoStatement.java │ │ │ ├── ExpressionStatement.java │ │ │ ├── FinallyStatement.java │ │ │ ├── ForIterStatement.java │ │ │ ├── ForStatement.java │ │ │ ├── GotoStatement.java │ │ │ ├── IfExitingStatement.java │ │ │ ├── IfStatement.java │ │ │ ├── JSRCallStatement.java │ │ │ ├── JSRRetStatement.java │ │ │ ├── JumpingStatement.java │ │ │ ├── MonitorEnterStatement.java │ │ │ ├── MonitorExitStatement.java │ │ │ ├── MonitorStatement.java │ │ │ ├── Nop.java │ │ │ ├── RawSwitchStatement.java │ │ │ ├── ReturnNothingStatement.java │ │ │ ├── ReturnStatement.java │ │ │ ├── ReturnValueStatement.java │ │ │ ├── SwitchStatement.java │ │ │ ├── ThrowStatement.java │ │ │ ├── TryStatement.java │ │ │ └── WhileStatement.java │ │ ├── utils │ │ │ ├── ArrayType.java │ │ │ ├── BlockIdentifier.java │ │ │ ├── BlockIdentifierFactory.java │ │ │ ├── BlockType.java │ │ │ ├── ComparableUnderEC.java │ │ │ ├── ConditionalUtils.java │ │ │ ├── CreationCollector.java │ │ │ ├── DefaultEquivalenceConstraint.java │ │ │ ├── EquivalenceConstraint.java │ │ │ ├── JumpType.java │ │ │ ├── LValueAssignmentAndAliasCondenser.java │ │ │ ├── LValueAssignmentCollector.java │ │ │ ├── LValueAssignmentExpressionRewriter.java │ │ │ ├── LValueRewriter.java │ │ │ ├── LValueUsageCollector.java │ │ │ ├── LValueUsageCollectorSimple.java │ │ │ ├── LValueUsageCollectorSimpleRW.java │ │ │ ├── Pair.java │ │ │ ├── QuotingUtils.java │ │ │ ├── ReadWrite.java │ │ │ ├── SSAIdent.java │ │ │ ├── SSAIdentifierFactory.java │ │ │ ├── SSAIdentifierUtils.java │ │ │ ├── SSAIdentifiers.java │ │ │ ├── Triplet.java │ │ │ ├── finalhelp │ │ │ │ ├── CompositeBlockIdentifierKey.java │ │ │ │ ├── FinalAnalyzer.java │ │ │ │ ├── FinallyCatchBody.java │ │ │ │ ├── FinallyGraphHelper.java │ │ │ │ ├── PeerTries.java │ │ │ │ └── Result.java │ │ │ └── scope │ │ │ │ ├── AbstractLValueScopeDiscoverer.java │ │ │ │ ├── LValueScopeDiscoverImpl.java │ │ │ │ ├── LValueScopeDiscoverer.java │ │ │ │ ├── LocalClassScopeDiscoverImpl.java │ │ │ │ └── ScopeDiscoverInfoCache.java │ │ └── wildcard │ │ │ ├── OptionalMatch.java │ │ │ ├── Wildcard.java │ │ │ └── WildcardMatch.java │ ├── stack │ │ ├── StackDelta.java │ │ ├── StackDeltaImpl.java │ │ ├── StackEntry.java │ │ ├── StackEntryHolder.java │ │ └── StackSim.java │ ├── structured │ │ ├── StructuredScope.java │ │ ├── StructuredStatement.java │ │ ├── expression │ │ │ └── StructuredStatementExpression.java │ │ └── statement │ │ │ ├── AbstractStructuredBlockStatement.java │ │ │ ├── AbstractStructuredConditionalLoopStatement.java │ │ │ ├── AbstractStructuredContinue.java │ │ │ ├── AbstractStructuredStatement.java │ │ │ ├── AbstractUnStructuredStatement.java │ │ │ ├── Block.java │ │ │ ├── StructuredAssert.java │ │ │ ├── StructuredAssignment.java │ │ │ ├── StructuredBreak.java │ │ │ ├── StructuredCase.java │ │ │ ├── StructuredCatch.java │ │ │ ├── StructuredComment.java │ │ │ ├── StructuredContinue.java │ │ │ ├── StructuredDefinition.java │ │ │ ├── StructuredDo.java │ │ │ ├── StructuredExpressionStatement.java │ │ │ ├── StructuredExpressionYield.java │ │ │ ├── StructuredFakeDecompFailure.java │ │ │ ├── StructuredFinally.java │ │ │ ├── StructuredFor.java │ │ │ ├── StructuredIf.java │ │ │ ├── StructuredIter.java │ │ │ ├── StructuredReturn.java │ │ │ ├── StructuredSwitch.java │ │ │ ├── StructuredSynchronized.java │ │ │ ├── StructuredThrow.java │ │ │ ├── StructuredTry.java │ │ │ ├── StructuredWhile.java │ │ │ ├── UnstructuredAnonBreakTarget.java │ │ │ ├── UnstructuredAnonymousBreak.java │ │ │ ├── UnstructuredBreak.java │ │ │ ├── UnstructuredCase.java │ │ │ ├── UnstructuredCatch.java │ │ │ ├── UnstructuredContinue.java │ │ │ ├── UnstructuredDo.java │ │ │ ├── UnstructuredFinally.java │ │ │ ├── UnstructuredFor.java │ │ │ ├── UnstructuredGoto.java │ │ │ ├── UnstructuredIf.java │ │ │ ├── UnstructuredIter.java │ │ │ ├── UnstructuredSwitch.java │ │ │ ├── UnstructuredSynchronized.java │ │ │ ├── UnstructuredTry.java │ │ │ ├── UnstructuredWhile.java │ │ │ └── placeholder │ │ │ ├── AbstractPlaceholder.java │ │ │ ├── BeginBlock.java │ │ │ ├── ElseBlock.java │ │ │ └── EndBlock.java │ ├── types │ │ ├── BindingSuperContainer.java │ │ ├── BoundSuperCollector.java │ │ ├── ClassNameUtils.java │ │ ├── ClassSignature.java │ │ ├── DeclarationAnnotationHelper.java │ │ ├── DynamicInvokeType.java │ │ ├── FormalTypeParameter.java │ │ ├── GenericTypeBinder.java │ │ ├── InnerClassInfo.java │ │ ├── InnerClassInfoUtils.java │ │ ├── JavaAnnotatedTypeIterator.java │ │ ├── JavaArrayTypeInstance.java │ │ ├── JavaGenericBaseInstance.java │ │ ├── JavaGenericPlaceholderTypeInstance.java │ │ ├── JavaGenericRefTypeInstance.java │ │ ├── JavaIntersectionTypeInstance.java │ │ ├── JavaRefTypeInstance.java │ │ ├── JavaTypeInstance.java │ │ ├── JavaWildcardTypeInstance.java │ │ ├── MethodPrototype.java │ │ ├── MethodPrototypeAnnotationsHelper.java │ │ ├── MiscAnnotations.java │ │ ├── RawJavaType.java │ │ ├── StackType.java │ │ ├── StackTypes.java │ │ ├── TypeAnnotationHelper.java │ │ ├── TypeConstants.java │ │ ├── WildcardType.java │ │ ├── annotated │ │ │ └── JavaAnnotatedTypeInstance.java │ │ └── discovery │ │ │ ├── CastAction.java │ │ │ └── InferredJavaType.java │ └── variables │ │ ├── Ident.java │ │ ├── Keywords.java │ │ ├── NamedVariable.java │ │ ├── NamedVariableDefault.java │ │ ├── NamedVariableFromHint.java │ │ ├── Slot.java │ │ ├── VariableFactory.java │ │ ├── VariableNamer.java │ │ ├── VariableNamerDefault.java │ │ ├── VariableNamerFactory.java │ │ └── VariableNamerHinted.java └── opcode │ ├── DecodedLookupSwitch.java │ ├── DecodedSwitch.java │ ├── DecodedSwitchEntry.java │ ├── DecodedTableSwitch.java │ ├── JVMInstr.java │ ├── OperationFactory.java │ ├── OperationFactoryCPEntry.java │ ├── OperationFactoryCPEntryW.java │ ├── OperationFactoryConditionalJump.java │ ├── OperationFactoryDefault.java │ ├── OperationFactoryDup.java │ ├── OperationFactoryDup2.java │ ├── OperationFactoryDup2X1.java │ ├── OperationFactoryDup2X2.java │ ├── OperationFactoryDupBase.java │ ├── OperationFactoryDupX1.java │ ├── OperationFactoryDupX2.java │ ├── OperationFactoryFakeCatch.java │ ├── OperationFactoryGetField.java │ ├── OperationFactoryGetStatic.java │ ├── OperationFactoryGoto.java │ ├── OperationFactoryGotoW.java │ ├── OperationFactoryInvoke.java │ ├── OperationFactoryInvokeDynamic.java │ ├── OperationFactoryInvokeInterface.java │ ├── OperationFactoryLDC.java │ ├── OperationFactoryLDC2W.java │ ├── OperationFactoryLDCW.java │ ├── OperationFactoryLookupSwitch.java │ ├── OperationFactoryMultiANewArray.java │ ├── OperationFactoryNew.java │ ├── OperationFactoryPop.java │ ├── OperationFactoryPop2.java │ ├── OperationFactoryPutField.java │ ├── OperationFactoryPutStatic.java │ ├── OperationFactoryReturn.java │ ├── OperationFactorySwap.java │ ├── OperationFactoryTableSwitch.java │ ├── OperationFactoryThrow.java │ └── OperationFactoryWide.java ├── entities ├── AbstractConstantPoolEntry.java ├── AccessFlag.java ├── AccessFlagMethod.java ├── ClassFile.java ├── ClassFileField.java ├── FakeMethod.java ├── FakeMethods.java ├── Field.java ├── Method.java ├── MethodOrdering.java ├── annotations │ ├── AnnotationTableEntry.java │ ├── AnnotationTableTypeEntry.java │ ├── ElementValue.java │ ├── ElementValueAnnotation.java │ ├── ElementValueArray.java │ ├── ElementValueClass.java │ ├── ElementValueConst.java │ └── ElementValueEnum.java ├── attributes │ ├── AnnotationHelpers.java │ ├── Attribute.java │ ├── AttributeAnnotationDefault.java │ ├── AttributeAnnotations.java │ ├── AttributeBootstrapMethods.java │ ├── AttributeCode.java │ ├── AttributeConstantValue.java │ ├── AttributeDeprecated.java │ ├── AttributeEnclosingMethod.java │ ├── AttributeExceptions.java │ ├── AttributeInnerClasses.java │ ├── AttributeLineNumberTable.java │ ├── AttributeLocalVariableTable.java │ ├── AttributeLocalVariableTypeTable.java │ ├── AttributeMap.java │ ├── AttributeModule.java │ ├── AttributeModuleClassMain.java │ ├── AttributeModulePackages.java │ ├── AttributeParameterAnnotations.java │ ├── AttributePermittedSubclasses.java │ ├── AttributeRecord.java │ ├── AttributeRuntimeInvisibleAnnotations.java │ ├── AttributeRuntimeInvisibleParameterAnnotations.java │ ├── AttributeRuntimeInvisibleTypeAnnotations.java │ ├── AttributeRuntimeVisibleAnnotations.java │ ├── AttributeRuntimeVisibleParameterAnnotations.java │ ├── AttributeRuntimeVisibleTypeAnnotations.java │ ├── AttributeScala.java │ ├── AttributeScalaSig.java │ ├── AttributeSignature.java │ ├── AttributeSourceFile.java │ ├── AttributeStackMapTable.java │ ├── AttributeSynthetic.java │ ├── AttributeTypeAnnotations.java │ ├── AttributeUnknown.java │ ├── BadAttributeException.java │ ├── LocalVariableEntry.java │ ├── TypeAnnotationEntryKind.java │ ├── TypeAnnotationEntryValue.java │ ├── TypeAnnotationLocation.java │ ├── TypeAnnotationTargetInfo.java │ ├── TypePath.java │ ├── TypePathAccessor.java │ ├── TypePathPart.java │ ├── TypePathPartArray.java │ ├── TypePathPartBound.java │ ├── TypePathPartNested.java │ └── TypePathPartParameterized.java ├── bootstrap │ ├── BootstrapMethodInfo.java │ └── MethodHandleBehaviour.java ├── classfilehelpers │ ├── AbstractClassFileDumper.java │ ├── ClassFileDumper.java │ ├── ClassFileDumperAnnotation.java │ ├── ClassFileDumperAnonymousInner.java │ ├── ClassFileDumperEnum.java │ ├── ClassFileDumperInterface.java │ ├── ClassFileDumperModule.java │ ├── ClassFileDumperNormal.java │ ├── ClassFileDumperRecord.java │ ├── ConstantLinks.java │ ├── OverloadMethodSet.java │ └── VisibilityHelper.java ├── constantpool │ ├── ConstantPool.java │ ├── ConstantPoolEntry.java │ ├── ConstantPoolEntryClass.java │ ├── ConstantPoolEntryDouble.java │ ├── ConstantPoolEntryDynamicInfo.java │ ├── ConstantPoolEntryFieldRef.java │ ├── ConstantPoolEntryFloat.java │ ├── ConstantPoolEntryInteger.java │ ├── ConstantPoolEntryInvokeDynamic.java │ ├── ConstantPoolEntryLiteral.java │ ├── ConstantPoolEntryLong.java │ ├── ConstantPoolEntryMethodHandle.java │ ├── ConstantPoolEntryMethodRef.java │ ├── ConstantPoolEntryMethodType.java │ ├── ConstantPoolEntryModuleInfo.java │ ├── ConstantPoolEntryNameAndType.java │ ├── ConstantPoolEntryPackageInfo.java │ ├── ConstantPoolEntryString.java │ ├── ConstantPoolEntryUTF8.java │ └── ConstantPoolUtils.java ├── exceptions │ ├── BasicExceptions.java │ ├── ClosedIdxExceptionEntry.java │ ├── ExceptionAggregator.java │ ├── ExceptionCheck.java │ ├── ExceptionCheckImpl.java │ ├── ExceptionCheckSimple.java │ ├── ExceptionGroup.java │ ├── ExceptionTableEntry.java │ ├── IntervalCollisionRemover.java │ ├── IntervalCount.java │ └── IntervalOverlapper.java └── innerclass │ └── InnerClassAttributeInfo.java ├── entityfactories ├── AttributeFactory.java └── ContiguousEntityFactory.java ├── mapping ├── ClassMapping.java ├── FieldMapping.java ├── Mapping.java ├── MappingFactory.java ├── MethodMapping.java ├── NullMapping.java └── ObfuscationMapping.java ├── package-info.java ├── relationship └── MemberNameResolver.java ├── state ├── AbstractTypeUsageCollector.java ├── ClassCache.java ├── ClassFileRelocator.java ├── ClassFileSourceChained.java ├── ClassFileSourceImpl.java ├── ClassFileSourceWrapper.java ├── ClassNameFunction.java ├── ClassNameFunctionCase.java ├── ClassNameFunctionInvalid.java ├── ClassRenamer.java ├── DCCommonState.java ├── DetectedStaticImport.java ├── InnerClassTypeUsageInformation.java ├── JarContentImpl.java ├── LocalClassAwareTypeUsageInformation.java ├── ObfuscationRewriter.java ├── ObfuscationTypeMap.java ├── OsInfo.java ├── OverloadMethodSetCache.java ├── TypeUsageCollectingDumper.java ├── TypeUsageCollector.java ├── TypeUsageInformation.java ├── TypeUsageInformationEmpty.java ├── TypeUsageInformationImpl.java └── TypeUsageUtils.java └── util ├── AnalysisType.java ├── BoolPair.java ├── CannotLoadClassException.java ├── CannotPerformDecode.java ├── ClassFileVersion.java ├── ConfusedCFRException.java ├── DecompilerComment.java ├── DecompilerCommentSource.java ├── DecompilerComments.java ├── KnowsRawName.java ├── KnowsRawSize.java ├── MalformedPrototypeException.java ├── MiscConstants.java ├── MiscUtils.java ├── Optional.java ├── StringUtils.java ├── Troolean.java ├── TypeUsageCollectable.java ├── UnverifiableJumpException.java ├── annotation └── Nullable.java ├── bytestream ├── AbstractBackedByteData.java ├── BaseByteData.java ├── ByteData.java ├── OffsetBackedByteData.java ├── OffsettingBackedByteData.java └── OffsettingByteData.java ├── collections ├── CollectionUtils.java ├── Functional.java ├── LazyExceptionRetainingMap.java ├── LazyMap.java ├── ListFactory.java ├── MapFactory.java ├── SetFactory.java ├── SetUtil.java ├── StackFactory.java └── UniqueSeenQueue.java ├── functors ├── BinaryFunction.java ├── BinaryPredicate.java ├── BinaryProcedure.java ├── NonaryFunction.java ├── Predicate.java ├── TrinaryFunction.java ├── UnaryFunction.java └── UnaryProcedure.java ├── getopt ├── BadParametersException.java ├── GetOptParser.java ├── GetOptSinkFactory.java ├── MutableOptions.java ├── OptionDecoder.java ├── OptionDecoderParam.java ├── Options.java ├── OptionsImpl.java └── PermittedOptionProvider.java ├── graph ├── AbstractGraphVisitorFI.java ├── GraphVisitor.java ├── GraphVisitorDFS.java └── GraphVisitorFIFO.java ├── lambda └── LambdaUtils.java └── output ├── AbstractDumper.java ├── BlockCommentState.java ├── BytecodeDumpConsumer.java ├── BytecodeTrackingDumper.java ├── DelegatingDumper.java ├── Dumpable.java ├── DumpableWithPrecedence.java ├── Dumper.java ├── DumperFactory.java ├── ExceptionDumper.java ├── FileDumper.java ├── FileSummaryDumper.java ├── IllegalIdentifierDump.java ├── IllegalIdentifierReplacement.java ├── InternalDumperFactoryImpl.java ├── LogFormatter.java ├── LoggerFactory.java ├── MethodErrorCollector.java ├── MovableDumperContext.java ├── NopSummaryDumper.java ├── ProgressDumper.java ├── ProgressDumperNop.java ├── ProgressDumperStdErr.java ├── SinkDumperFactory.java ├── SinkSummaryDumper.java ├── StdErrExceptionDumper.java ├── StdIODumper.java ├── StreamDumper.java ├── StringStreamDumper.java ├── SummaryDumper.java ├── ToStringDumper.java ├── TokenStreamDumper.java ├── TypeContext.java └── TypeOverridingDumper.java /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Report a bug with CFR. 4 | title: '' 5 | labels: bug 6 | assignees: '' 7 | 8 | --- 9 | 10 | # CFR version 11 | 12 | 13 | 14 | 15 | # Compiler 16 | 17 | 18 | 19 | 20 | # Description 21 | 22 | 23 | 24 | # Example 25 | 26 | 27 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest a feature for CFR. 4 | title: '' 5 | labels: enhancement 6 | assignees: '' 7 | 8 | --- 9 | 10 | 11 | # Problem solved by this feature 12 | 13 | 14 | 15 | # Feature description 16 | 17 | 18 | 19 | # Considerations 20 | 21 | 22 | 23 | # Alternatives 24 | 25 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/question.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Question 3 | about: Ask a question about CFR, its usage, development, ... 4 | title: '' 5 | labels: question 6 | assignees: '' 7 | 8 | --- 9 | 10 | 11 | -------------------------------------------------------------------------------- /.github/workflows/maven.yml: -------------------------------------------------------------------------------- 1 | # This workflow will build a Java project with Maven 2 | # For more information see: https://help.github.com/actions/language-and-framework-guides/building-and-testing-java-with-maven 3 | 4 | name: Java CI with Maven 5 | 6 | on: [push, pull_request] 7 | 8 | jobs: 9 | build: 10 | runs-on: ubuntu-latest 11 | 12 | steps: 13 | - name: Check out Git repository 14 | uses: actions/checkout@v2 15 | with: 16 | # Clone decompilation test data submodule 17 | submodules: true 18 | 19 | - name: Set up Java 20 | uses: actions/setup-java@v2 21 | with: 22 | distribution: temurin 23 | java-version: 8 24 | cache: maven 25 | 26 | - id: maven-build 27 | name: Build with Maven 28 | run: mvn --batch-mode --update-snapshots -Dgpg.skip=true clean verify 29 | 30 | - name: Upload decompilation test failures artifact 31 | # Only run when Maven build failed, see https://github.community/t/run-step-only-if-previous-step-failed/127124/3 32 | if: failure() && steps.maven-build.outcome == 'failure' 33 | uses: actions/upload-artifact@v2 34 | with: 35 | name: decompilation-test-failures-diff 36 | path: target/cfr-test-failures-diff 37 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # IntelliJ 2 | .idea 3 | out 4 | *.iml 5 | 6 | # Eclipse 7 | /.classpath 8 | /.project 9 | /.settings 10 | 11 | # Maven 12 | /target 13 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "decompilation-test/test-data"] 2 | path = decompilation-test/test-data 3 | url = https://github.com/leibnitz27/cfr_tests.git 4 | branch = master 5 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2011-2019 Lee Benfield - https://www.benf.org/other/cfr 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /cfr.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /decompilation-test/src/org/benf/cfr/test/DecompilationTest.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.test; 2 | 3 | import java.io.IOException; 4 | import java.nio.file.Path; 5 | import java.util.Map; 6 | 7 | import org.benf.cfr.test.DecompilationTestImplementation.ClassFileTestDataSource; 8 | import org.junit.jupiter.params.ParameterizedTest; 9 | 10 | /** 11 | * CFR decompilation test. For increased readability this class only contains the JUnit test methods; 12 | * the actual implementation is in {@link DecompilationTestImplementation}. 13 | */ 14 | class DecompilationTest { 15 | @ParameterizedTest(name = "[{index}] {0}") 16 | @ClassFileTestDataSource("classes.xml") 17 | void classFile(Path classFilePath, Map cfrOptionsDict, Path output, String outputPrefix) throws IOException { 18 | DecompilationTestImplementation.assertClassFile(classFilePath, cfrOptionsDict, output, outputPrefix); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /decompilation-test/test-data-expected-output/classes/CondJumpTest2c.10.expected.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Decompiled with CFR. 3 | */ 4 | package org.benf.cfr.tests; 5 | 6 | public class CondJumpTest2c { 7 | public boolean test(boolean a, boolean b) { 8 | boolean c; 9 | return b && a == (c = b) || b && (c = a); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /decompilation-test/test-data-expected-output/classes/CondJumpTest2c.6.expected.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Decompiled with CFR. 3 | */ 4 | package org.benf.cfr.tests; 5 | 6 | public class CondJumpTest2c { 7 | public boolean test(boolean bl, boolean bl2) { 8 | boolean bl3; 9 | return bl2 && bl == (bl3 = bl2) || bl2 && (bl3 = bl); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /decompilation-test/test-data-expected-output/classes/EnumTestEmpty.13.expected.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Decompiled with CFR. 3 | */ 4 | package org.benf.cfr.tests; 5 | 6 | public enum EnumTestEmpty { 7 | 8 | } 9 | -------------------------------------------------------------------------------- /decompilation-test/test-data-expected-output/classes/EnumTestEmpty.6.expected.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Decompiled with CFR. 3 | */ 4 | package org.benf.cfr.tests; 5 | 6 | public enum EnumTestEmpty { 7 | 8 | } 9 | -------------------------------------------------------------------------------- /decompilation-test/test-data-expected-output/classes/TryTest1.10.expected.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Decompiled with CFR. 3 | */ 4 | package org.benf.cfr.tests; 5 | 6 | public class TryTest1 { 7 | public void test1() { 8 | try { 9 | try { 10 | System.out.print(3); 11 | throw new NoSuchFieldException(); 12 | } catch (NoSuchFieldException noSuchFieldException) { 13 | System.out.print("Finally!"); 14 | } 15 | } catch (Throwable throwable) { 16 | System.out.print("Finally!"); 17 | throw throwable; 18 | } 19 | System.out.print(5); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /decompilation-test/test-specs/classes.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | precompiled_tests/java_6/org/benf/cfr/tests 8 | CondJumpTest2c 9 | 10 | 11 | 12 | 13 | 15 | 16 | 17 | precompiled_tests/java_10/org/benf/cfr/tests 18 | CondJumpTest2c 19 | 20 | 21 | 22 | precompiled_tests/java_6/org/benf/cfr/tests 23 | EnumTestEmpty 24 | 25 | 26 | 27 | precompiled_tests/java_13/org/benf/cfr/tests 28 | EnumTestEmpty 29 | 30 | 31 | 32 | precompiled_tests/java_10/org/benf/cfr/tests 33 | TryTest1 34 | 35 | 36 | -------------------------------------------------------------------------------- /src-templates/org/benf/cfr/reader/util/CfrVersionInfo.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.util; 2 | 3 | /** 4 | * Provides information about the CFR build. 5 | * 6 | *

The information in this class is automatically generated when the project 7 | * is built. 8 | */ 9 | public class CfrVersionInfo { 10 | private CfrVersionInfo() {} 11 | 12 | /** CFR version */ 13 | public static final String VERSION = "${project.version}"; 14 | 15 | /** Are we a snapshot? */ 16 | public static final boolean SNAPSHOT = CfrVersionInfo.VERSION.contains("SNAPSHOT"); 17 | /** 18 | * Abbreviated Git commit hash of the commit representing this state 19 | * of the project. 20 | */ 21 | public static final String GIT_COMMIT_ABBREVIATED = "${git.commit.id.abbrev}"; 22 | /** 23 | * Whether the working tree contained not yet committed changes when 24 | * the project was built. 25 | * 26 | *

This information can be useful for error reports to find out 27 | * if changes have been made. 28 | */ 29 | public static final boolean GIT_IS_DIRTY = "${git.dirty}".equals("true"); 30 | 31 | /** String consisting of CFR version and Git commit hash */ 32 | public static final String VERSION_INFO = 33 | VERSION + 34 | (SNAPSHOT ? 35 | " (" + GIT_COMMIT_ABBREVIATED + (GIT_IS_DIRTY ? "-dirty" : "") + ")" : 36 | ""); 37 | } 38 | -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/apiunreleased/ClassFileSource2.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.apiunreleased; 2 | 3 | import org.benf.cfr.reader.api.ClassFileSource; 4 | import org.benf.cfr.reader.util.AnalysisType; 5 | 6 | // TODO : Experimental API - before moving, snip ClassFileSource link. 7 | public interface ClassFileSource2 extends ClassFileSource { 8 | /** 9 | * CFR would like to know about all classes contained within the jar at {@code jarPath} 10 | * 11 | * @param jarPath path to a jar. 12 | * @return @{link JarContent} for this jar. 13 | */ 14 | JarContent addJarContent(String jarPath, AnalysisType analysisType); 15 | } 16 | -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/apiunreleased/JarContent.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.apiunreleased; 2 | 3 | import org.benf.cfr.reader.util.AnalysisType; 4 | 5 | import java.util.Collection; 6 | import java.util.Map; 7 | 8 | public interface JarContent { 9 | /** 10 | * @return All files which we may want to process. 11 | */ 12 | Collection getClassFiles(); 13 | 14 | /** 15 | * Nb: Java has a perfectly good {@link java.util.jar.Manifest} class since 1.2 16 | * which could be used here. This simplifies the content. 17 | * @return Map of manifest entries. 18 | */ 19 | Map getManifestEntries(); 20 | 21 | /** 22 | * @return source of data - jar? war? 23 | */ 24 | AnalysisType getAnalysisType(); 25 | } 26 | -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/bytecode/AnalysisResult.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.bytecode; 2 | 3 | import org.benf.cfr.reader.bytecode.analysis.opgraph.Op04StructuredStatement; 4 | import org.benf.cfr.reader.util.DecompilerComments; 5 | 6 | public interface AnalysisResult { 7 | boolean isFailed(); 8 | boolean isThrown(); 9 | Op04StructuredStatement getCode(); 10 | DecompilerComments getComments(); 11 | AnonymousClassUsage getAnonymousClassUsage(); 12 | } 13 | -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/bytecode/analysis/loc/BytecodeLocFactory.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.bytecode.analysis.loc; 2 | 3 | import org.benf.cfr.reader.entities.Method; 4 | 5 | public interface BytecodeLocFactory { 6 | BytecodeLoc DISABLED = new BytecodeLocSpecific(BytecodeLocSpecific.Specific.DISABLED); 7 | BytecodeLoc NONE = new BytecodeLocSpecific(BytecodeLocSpecific.Specific.NONE); 8 | BytecodeLoc TODO = new BytecodeLocSpecific(BytecodeLocSpecific.Specific.TODO); 9 | 10 | BytecodeLoc at(int originalRawOffset, Method method); 11 | } 12 | -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/bytecode/analysis/loc/BytecodeLocFactoryStub.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.bytecode.analysis.loc; 2 | 3 | import org.benf.cfr.reader.entities.Method; 4 | 5 | public class BytecodeLocFactoryStub implements BytecodeLocFactory { 6 | public static BytecodeLocFactory INSTANCE = new BytecodeLocFactoryStub(); 7 | 8 | private BytecodeLocFactoryStub() { 9 | } 10 | 11 | @Override 12 | public BytecodeLoc at(int originalRawOffset, Method method) { 13 | return BytecodeLocFactory.DISABLED; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/bytecode/analysis/loc/BytecodeLocSpecific.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.bytecode.analysis.loc; 2 | 3 | import org.benf.cfr.reader.entities.Method; 4 | 5 | import java.util.Collection; 6 | import java.util.Collections; 7 | 8 | class BytecodeLocSpecific extends BytecodeLoc { 9 | enum Specific { 10 | DISABLED, 11 | TODO, 12 | NONE 13 | } 14 | 15 | private final Specific type; 16 | 17 | BytecodeLocSpecific(Specific type) { 18 | this.type = type; 19 | } 20 | 21 | @Override 22 | void addTo(BytecodeLocCollector collector) { 23 | } 24 | 25 | @Override 26 | public String toString() { 27 | return type.name(); 28 | } 29 | 30 | @Override 31 | public Collection getMethods() { 32 | return Collections.emptyList(); 33 | } 34 | 35 | @Override 36 | public Collection getOffsetsForMethod(Method method) { 37 | return Collections.emptyList(); 38 | } 39 | 40 | @Override 41 | public boolean isEmpty() { 42 | return true; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/bytecode/analysis/loc/HasByteCodeLoc.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.bytecode.analysis.loc; 2 | 3 | public interface HasByteCodeLoc { 4 | BytecodeLoc getCombinedLoc(); 5 | 6 | BytecodeLoc getLoc(); 7 | 8 | void addLoc(HasByteCodeLoc loc); 9 | } 10 | -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/bytecode/analysis/opgraph/Graph.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.bytecode.analysis.opgraph; 2 | 3 | import java.util.List; 4 | 5 | public interface Graph { 6 | List getSources(); 7 | List getTargets(); 8 | } 9 | -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/bytecode/analysis/opgraph/GraphConversionHelper.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.bytecode.analysis.opgraph; 2 | 3 | import org.benf.cfr.reader.util.ConfusedCFRException; 4 | import org.benf.cfr.reader.util.collections.MapFactory; 5 | 6 | import java.util.Map; 7 | 8 | class GraphConversionHelper, Y extends MutableGraph> { 9 | private final Map correspondance; 10 | 11 | GraphConversionHelper() { 12 | this.correspondance = MapFactory.newMap(); 13 | } 14 | 15 | private Y findEntry(X key, X orig, String dbg) { 16 | Y value = correspondance.get(key); 17 | if (value == null) 18 | throw new ConfusedCFRException("Missing key when tying up graph " + key + ", was " + dbg + " of " + orig); 19 | return value; 20 | } 21 | 22 | void patchUpRelations() { 23 | for (Map.Entry entry : correspondance.entrySet()) { 24 | X orig = entry.getKey(); 25 | Y newnode = entry.getValue(); 26 | 27 | for (X source : orig.getSources()) { 28 | newnode.addSource(findEntry(source, orig, "source")); 29 | } 30 | 31 | for (X target : orig.getTargets()) { 32 | newnode.addTarget(findEntry(target, orig, "target")); 33 | } 34 | } 35 | } 36 | 37 | void registerOriginalAndNew(X original, Y newnode) { 38 | correspondance.put(original, newnode); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/bytecode/analysis/opgraph/IndexedStatement.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.bytecode.analysis.opgraph; 2 | 3 | public interface IndexedStatement { 4 | InstrIndex getIndex(); 5 | } 6 | -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/bytecode/analysis/opgraph/MutableGraph.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.bytecode.analysis.opgraph; 2 | 3 | public interface MutableGraph extends Graph { 4 | void addSource(T source); 5 | void addTarget(T target); 6 | } 7 | -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/bytecode/analysis/opgraph/op02obf/Op02Obf.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.bytecode.analysis.opgraph.op02obf; 2 | 3 | import org.benf.cfr.reader.bytecode.analysis.opgraph.Op02WithProcessedDataAndRefs; 4 | import org.benf.cfr.reader.entities.Method; 5 | import org.benf.cfr.reader.entities.exceptions.ExceptionAggregator; 6 | 7 | import java.util.List; 8 | import java.util.SortedMap; 9 | 10 | public class Op02Obf { 11 | public static void removeControlFlowExceptions(Method method, ExceptionAggregator exceptions, List op2list, SortedMap lutByOffset) { 12 | ControlFlowIntDiv0Exception.Instance.process(method, exceptions, op2list, lutByOffset); 13 | ControlFlowNullException.Instance.process(method, exceptions, op2list, lutByOffset); 14 | } 15 | 16 | public static void removeNumericObf(Method method, List op2list) { 17 | ControlFlowNumericObf.Instance.process(method, op2list); 18 | } 19 | 20 | public static boolean detectObfuscations(Method method, ExceptionAggregator exceptions, List op2list, SortedMap lutByOffset) { 21 | if (ControlFlowIntDiv0Exception.Instance.check(exceptions, op2list, lutByOffset)) return true; 22 | if (ControlFlowNullException.Instance.check(exceptions, op2list, lutByOffset)) return true; 23 | return false; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/bytecode/analysis/opgraph/op03obf/Op03Obf.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.bytecode.analysis.opgraph.op03obf; 2 | 3 | import org.benf.cfr.reader.bytecode.analysis.opgraph.Op03SimpleStatement; 4 | 5 | import java.util.List; 6 | 7 | public class Op03Obf { 8 | 9 | } 10 | -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/bytecode/analysis/opgraph/op2rewriters/GetClassTest.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.bytecode.analysis.opgraph.op2rewriters; 2 | 3 | import org.benf.cfr.reader.bytecode.analysis.opgraph.Op02WithProcessedDataAndRefs; 4 | import org.benf.cfr.reader.bytecode.opcode.JVMInstr; 5 | import org.benf.cfr.reader.entities.ClassFile; 6 | 7 | public interface GetClassTest { 8 | JVMInstr getInstr(); 9 | 10 | boolean test(ClassFile classFile, Op02WithProcessedDataAndRefs item); 11 | } 12 | -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/bytecode/analysis/opgraph/op2rewriters/TypeHintRecovery.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.bytecode.analysis.opgraph.op2rewriters; 2 | 3 | import org.benf.cfr.reader.bytecode.analysis.types.discovery.InferredJavaType; 4 | 5 | public interface TypeHintRecovery { 6 | void improve(InferredJavaType type); 7 | } 8 | -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/bytecode/analysis/opgraph/op2rewriters/TypeHintRecoveryNone.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.bytecode.analysis.opgraph.op2rewriters; 2 | 3 | import org.benf.cfr.reader.bytecode.analysis.types.discovery.InferredJavaType; 4 | 5 | public class TypeHintRecoveryNone implements TypeHintRecovery { 6 | public static final TypeHintRecoveryNone INSTANCE = new TypeHintRecoveryNone(); 7 | 8 | private TypeHintRecoveryNone() { 9 | } 10 | 11 | @Override 12 | public void improve(InferredJavaType type) {} 13 | } 14 | -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/bytecode/analysis/opgraph/op3rewriters/CompareByIndex.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.bytecode.analysis.opgraph.op3rewriters; 2 | 3 | import org.benf.cfr.reader.bytecode.analysis.opgraph.Op03SimpleStatement; 4 | import org.benf.cfr.reader.util.ConfusedCFRException; 5 | 6 | import java.util.Comparator; 7 | 8 | public class CompareByIndex implements Comparator { 9 | 10 | private boolean asc; 11 | 12 | public CompareByIndex() { 13 | this(true); 14 | } 15 | 16 | public CompareByIndex(boolean asc) { 17 | this.asc = asc; 18 | } 19 | 20 | @Override 21 | public int compare(Op03SimpleStatement a, Op03SimpleStatement b) { 22 | int res = a.getIndex().compareTo(b.getIndex()); 23 | if (!asc) res = -res; 24 | if (res == 0) { 25 | throw new ConfusedCFRException("Can't sort instructions [" + a + ", " + b + "]"); 26 | } 27 | //noinspection ComparatorMethodParameterNotUsed 28 | return res; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/bytecode/analysis/opgraph/op3rewriters/CondenseConstruction.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.bytecode.analysis.opgraph.op3rewriters; 2 | 3 | import org.benf.cfr.reader.bytecode.AnonymousClassUsage; 4 | import org.benf.cfr.reader.bytecode.analysis.opgraph.Op03SimpleStatement; 5 | import org.benf.cfr.reader.bytecode.analysis.parse.utils.CreationCollector; 6 | import org.benf.cfr.reader.entities.Method; 7 | import org.benf.cfr.reader.state.DCCommonState; 8 | 9 | import java.util.List; 10 | 11 | class CondenseConstruction { 12 | /* 13 | * Find all the constructors and initialisers. If something is initialised and 14 | * constructed in one place each, we can guarantee that the construction happened 15 | * after the initialisation, so replace 16 | * 17 | * a1 = new foo 18 | * a1.(x, y, z) 19 | * 20 | * with 21 | * 22 | * a1 = new foo(x,y,z) 23 | */ 24 | static void condenseConstruction(DCCommonState state, Method method, List statements, AnonymousClassUsage anonymousClassUsage) { 25 | CreationCollector creationCollector = new CreationCollector(anonymousClassUsage); 26 | for (Op03SimpleStatement statement : statements) { 27 | statement.findCreation(creationCollector); 28 | } 29 | creationCollector.condenseConstructions(method, state); 30 | } 31 | 32 | } 33 | -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/bytecode/analysis/opgraph/op3rewriters/ExactTypeFilter.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.bytecode.analysis.opgraph.op3rewriters; 2 | 3 | import org.benf.cfr.reader.bytecode.analysis.opgraph.Op03SimpleStatement; 4 | import org.benf.cfr.reader.util.functors.Predicate; 5 | 6 | public class ExactTypeFilter implements Predicate { 7 | private final Class clazz; 8 | 9 | public ExactTypeFilter(Class clazz) { 10 | this.clazz = clazz; 11 | } 12 | 13 | @Override 14 | public boolean test(Op03SimpleStatement in) { 15 | return clazz == (in.getStatement().getClass()); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/bytecode/analysis/opgraph/op3rewriters/NullTypedLValueRewriter.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.bytecode.analysis.opgraph.op3rewriters; 2 | 3 | import org.benf.cfr.reader.bytecode.analysis.parse.LValue; 4 | import org.benf.cfr.reader.bytecode.analysis.parse.StatementContainer; 5 | import org.benf.cfr.reader.bytecode.analysis.parse.rewriters.AbstractExpressionRewriter; 6 | import org.benf.cfr.reader.bytecode.analysis.parse.rewriters.ExpressionRewriterFlags; 7 | import org.benf.cfr.reader.bytecode.analysis.parse.utils.SSAIdentifiers; 8 | import org.benf.cfr.reader.bytecode.analysis.types.JavaTypeInstance; 9 | import org.benf.cfr.reader.bytecode.analysis.types.RawJavaType; 10 | import org.benf.cfr.reader.bytecode.analysis.types.discovery.InferredJavaType; 11 | 12 | public class NullTypedLValueRewriter extends AbstractExpressionRewriter { 13 | @Override 14 | public LValue rewriteExpression(LValue lValue, SSAIdentifiers ssaIdentifiers, StatementContainer statementContainer, ExpressionRewriterFlags flags) { 15 | InferredJavaType inferredJavaType = lValue.getInferredJavaType(); 16 | JavaTypeInstance javaTypeInstance = inferredJavaType.getJavaTypeInstance(); 17 | if (javaTypeInstance == RawJavaType.NULL || javaTypeInstance == RawJavaType.VOID) { 18 | inferredJavaType.applyKnownBaseType(); 19 | } 20 | return lValue; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/bytecode/analysis/opgraph/op3rewriters/TypeFilter.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.bytecode.analysis.opgraph.op3rewriters; 2 | 3 | import org.benf.cfr.reader.bytecode.analysis.opgraph.Op03SimpleStatement; 4 | import org.benf.cfr.reader.util.functors.Predicate; 5 | 6 | public class TypeFilter implements Predicate { 7 | private final Class clazz; 8 | private final boolean positive; 9 | 10 | public TypeFilter(Class clazz) { 11 | this.clazz = clazz; 12 | this.positive = true; 13 | } 14 | 15 | public TypeFilter(Class clazz, boolean positive) { 16 | this.clazz = clazz; 17 | this.positive = positive; 18 | } 19 | 20 | @Override 21 | public boolean test(Op03SimpleStatement in) { 22 | return (positive == clazz.isInstance(in.getStatement())); 23 | } 24 | } -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/bytecode/analysis/opgraph/op3rewriters/UselessNops.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.bytecode.analysis.opgraph.op3rewriters; 2 | 3 | import org.benf.cfr.reader.bytecode.analysis.opgraph.Op03SimpleStatement; 4 | import org.benf.cfr.reader.util.collections.Functional; 5 | import org.benf.cfr.reader.util.functors.Predicate; 6 | 7 | import java.util.List; 8 | 9 | public class UselessNops { 10 | public static List removeUselessNops(List in) { 11 | return Functional.filter(in, new Predicate() { 12 | @Override 13 | public boolean test(Op03SimpleStatement in) { 14 | return !(in.getSources().isEmpty() && in.getTargets().isEmpty()); 15 | } 16 | }); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/bytecode/analysis/opgraph/op4rewriters/EnumAllSuperRewriter.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.bytecode.analysis.opgraph.op4rewriters; 2 | 3 | import org.benf.cfr.reader.bytecode.analysis.parse.expression.SuperFunctionInvokation; 4 | 5 | public class EnumAllSuperRewriter extends RedundantSuperRewriter { 6 | 7 | @Override 8 | protected boolean canBeNopped(SuperFunctionInvokation superInvokation) { 9 | return true; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/bytecode/analysis/opgraph/op4rewriters/LValueReplacingRewriter.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.bytecode.analysis.opgraph.op4rewriters; 2 | 3 | import org.benf.cfr.reader.bytecode.analysis.parse.LValue; 4 | import org.benf.cfr.reader.bytecode.analysis.parse.StatementContainer; 5 | import org.benf.cfr.reader.bytecode.analysis.parse.rewriters.AbstractExpressionRewriter; 6 | import org.benf.cfr.reader.bytecode.analysis.parse.rewriters.ExpressionRewriterFlags; 7 | import org.benf.cfr.reader.bytecode.analysis.parse.utils.SSAIdentifiers; 8 | 9 | import java.util.Map; 10 | 11 | public class LValueReplacingRewriter extends AbstractExpressionRewriter { 12 | private final Map replacements; 13 | 14 | public LValueReplacingRewriter(Map replacements) { 15 | this.replacements = replacements; 16 | } 17 | 18 | @Override 19 | public LValue rewriteExpression(LValue lValue, SSAIdentifiers ssaIdentifiers, StatementContainer statementContainer, ExpressionRewriterFlags flags) { 20 | LValue replacement = replacements.get(lValue); 21 | if (replacement != null) { 22 | return replacement; 23 | } 24 | return lValue.applyExpressionRewriter(this, ssaIdentifiers, statementContainer, flags); 25 | } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/bytecode/analysis/opgraph/op4rewriters/Op04Rewriter.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.bytecode.analysis.opgraph.op4rewriters; 2 | 3 | import org.benf.cfr.reader.bytecode.analysis.opgraph.Op04StructuredStatement; 4 | 5 | public interface Op04Rewriter { 6 | void rewrite(Op04StructuredStatement root); 7 | } 8 | -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/bytecode/analysis/opgraph/op4rewriters/PointlessStructuredExpressions.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.bytecode.analysis.opgraph.op4rewriters; 2 | 3 | import org.benf.cfr.reader.bytecode.analysis.opgraph.op3rewriters.PointlessExpressions; 4 | import org.benf.cfr.reader.bytecode.analysis.parse.Expression; 5 | import org.benf.cfr.reader.bytecode.analysis.parse.LValue; 6 | import org.benf.cfr.reader.bytecode.analysis.structured.StructuredStatement; 7 | import org.benf.cfr.reader.bytecode.analysis.structured.statement.StructuredAssignment; 8 | 9 | public class PointlessStructuredExpressions { 10 | // Same as the op03 version, but we need to unpick the temporary we introduced. 11 | public static void removePointlessExpression(StructuredStatement stm) { 12 | if (stm instanceof StructuredAssignment) { 13 | StructuredAssignment ass = (StructuredAssignment)stm; 14 | LValue lv = ass.getLvalue(); 15 | if (lv.isFakeIgnored()) { 16 | Expression e = ass.getRvalue(); 17 | // This didn't used to be. But after some rewriting it might now be. 18 | if (PointlessExpressions.isSafeToIgnore(e)) { 19 | stm.getContainer().nopOut(); 20 | } 21 | } 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/bytecode/analysis/opgraph/op4rewriters/checker/Op04Checker.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.bytecode.analysis.opgraph.op4rewriters.checker; 2 | 3 | import org.benf.cfr.reader.bytecode.analysis.opgraph.op4rewriters.transformers.StructuredStatementTransformer; 4 | import org.benf.cfr.reader.util.DecompilerComments; 5 | 6 | public interface Op04Checker extends StructuredStatementTransformer { 7 | void commentInto(DecompilerComments comments); 8 | } 9 | -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/bytecode/analysis/opgraph/op4rewriters/matchutil/AbstractMatchResultIterator.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.bytecode.analysis.opgraph.op4rewriters.matchutil; 2 | 3 | import org.benf.cfr.reader.bytecode.analysis.parse.wildcard.WildcardMatch; 4 | import org.benf.cfr.reader.bytecode.analysis.structured.StructuredStatement; 5 | 6 | public abstract class AbstractMatchResultIterator implements MatchResultCollector { 7 | @Override 8 | public void clear() { 9 | 10 | } 11 | 12 | @Override 13 | public void collectStatement(String name, StructuredStatement statement) { 14 | } 15 | 16 | @Override 17 | public void collectMatches(String name, WildcardMatch wcm) { 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/bytecode/analysis/opgraph/op4rewriters/matchutil/CollectMatch.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.bytecode.analysis.opgraph.op4rewriters.matchutil; 2 | 3 | import org.benf.cfr.reader.bytecode.analysis.structured.StructuredStatement; 4 | 5 | public class CollectMatch implements Matcher { 6 | private final Matcher inner; 7 | private final String name; 8 | 9 | public CollectMatch(String name, Matcher inner) { 10 | this.inner = inner; 11 | this.name = name; 12 | } 13 | 14 | @Override 15 | public boolean match(MatchIterator matchIterator, MatchResultCollector matchResultCollector) { 16 | MatchIterator orig = matchIterator.copy(); 17 | boolean res = inner.match(matchIterator, matchResultCollector); 18 | if (res) { 19 | matchResultCollector.collectStatement(name, orig.getCurrent()); 20 | } 21 | return res; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/bytecode/analysis/opgraph/op4rewriters/matchutil/DeadMethodRemover.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.bytecode.analysis.opgraph.op4rewriters.matchutil; 2 | 3 | import org.benf.cfr.reader.bytecode.analysis.opgraph.Op04StructuredStatement; 4 | import org.benf.cfr.reader.bytecode.analysis.structured.StructuredStatement; 5 | import org.benf.cfr.reader.bytecode.analysis.structured.statement.Block; 6 | import org.benf.cfr.reader.bytecode.analysis.structured.statement.StructuredComment; 7 | import org.benf.cfr.reader.entities.ClassFile; 8 | import org.benf.cfr.reader.entities.Method; 9 | 10 | public class DeadMethodRemover { 11 | 12 | public static void removeDeadMethod(ClassFile classFile, Method method) { 13 | Op04StructuredStatement code = method.getAnalysis(); 14 | StructuredStatement statement = code.getStatement(); 15 | if (!(statement instanceof Block)) return; 16 | 17 | Block block = (Block) statement; 18 | for (Op04StructuredStatement inner : block.getBlockStatements()) { 19 | StructuredStatement innerStatement = inner.getStatement(); 20 | if (!(innerStatement instanceof StructuredComment)) { 21 | return; 22 | } 23 | } 24 | method.hideDead(); 25 | } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/bytecode/analysis/opgraph/op4rewriters/matchutil/EmptyMatchResultCollector.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.bytecode.analysis.opgraph.op4rewriters.matchutil; 2 | 3 | import org.benf.cfr.reader.bytecode.analysis.parse.wildcard.WildcardMatch; 4 | import org.benf.cfr.reader.bytecode.analysis.structured.StructuredStatement; 5 | 6 | public class EmptyMatchResultCollector implements MatchResultCollector { 7 | @Override 8 | public void clear() { 9 | 10 | } 11 | 12 | @Override 13 | public void collectStatement(String name, StructuredStatement statement) { 14 | 15 | } 16 | 17 | @Override 18 | public void collectMatches(String name, WildcardMatch wcm) { 19 | 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/bytecode/analysis/opgraph/op4rewriters/matchutil/KleeneN.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.bytecode.analysis.opgraph.op4rewriters.matchutil; 2 | 3 | import org.benf.cfr.reader.bytecode.analysis.structured.StructuredStatement; 4 | 5 | public class KleeneN implements Matcher { 6 | private final Matcher inner; 7 | private final int nRequired; 8 | 9 | public KleeneN(int nRequired, Matcher inner) { 10 | this.inner = inner; 11 | this.nRequired = nRequired; 12 | } 13 | 14 | public KleeneN(int nRequired, Matcher... matchers) { 15 | this.inner = new MatchSequence(matchers); 16 | this.nRequired = nRequired; 17 | } 18 | 19 | @Override 20 | public boolean match(MatchIterator matchIterator, MatchResultCollector matchResultCollector) { 21 | MatchIterator mi = matchIterator.copy(); 22 | 23 | int nMatches = 0; 24 | while (inner.match(mi, matchResultCollector)) { 25 | nMatches++; 26 | } 27 | 28 | if (nMatches >= nRequired) { 29 | matchIterator.advanceTo(mi); 30 | return true; 31 | } 32 | return false; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/bytecode/analysis/opgraph/op4rewriters/matchutil/KleenePlus.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.bytecode.analysis.opgraph.op4rewriters.matchutil; 2 | 3 | import org.benf.cfr.reader.bytecode.analysis.structured.StructuredStatement; 4 | 5 | public class KleenePlus extends KleeneN { 6 | public KleenePlus(Matcher inner) { 7 | super(1, inner); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/bytecode/analysis/opgraph/op4rewriters/matchutil/KleeneStar.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.bytecode.analysis.opgraph.op4rewriters.matchutil; 2 | 3 | import org.benf.cfr.reader.bytecode.analysis.structured.StructuredStatement; 4 | 5 | public class KleeneStar extends KleeneN { 6 | public KleeneStar(Matcher inner) { 7 | super(0, inner); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/bytecode/analysis/opgraph/op4rewriters/matchutil/MatchOneOf.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.bytecode.analysis.opgraph.op4rewriters.matchutil; 2 | 3 | import org.benf.cfr.reader.bytecode.analysis.structured.StructuredStatement; 4 | 5 | /** 6 | * Note that this will match the FIRST match, not necessarily the best. 7 | * I.e. no backtracking. 8 | */ 9 | public class MatchOneOf implements Matcher { 10 | private final Matcher[] matchers; 11 | 12 | public MatchOneOf(Matcher... matchers) { 13 | this.matchers = matchers; 14 | } 15 | 16 | @Override 17 | public boolean match(MatchIterator matchIterator, MatchResultCollector matchResultCollector) { 18 | 19 | for (Matcher matcher : matchers) { 20 | MatchIterator mi = matchIterator.copy(); 21 | if (matcher.match(mi, matchResultCollector)) { 22 | matchIterator.advanceTo(mi); 23 | return true; 24 | } 25 | } 26 | return false; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/bytecode/analysis/opgraph/op4rewriters/matchutil/MatchOpt.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.bytecode.analysis.opgraph.op4rewriters.matchutil; 2 | 3 | import org.benf.cfr.reader.bytecode.analysis.structured.StructuredStatement; 4 | 5 | /** 6 | * Note that this will match the FIRST match, not necessarily the best. 7 | * I.e. no backtracking. 8 | */ 9 | public class MatchOpt implements Matcher { 10 | private final Matcher matcher; 11 | 12 | public MatchOpt(Matcher matcher) { 13 | this.matcher = matcher; 14 | } 15 | 16 | @Override 17 | public boolean match(MatchIterator matchIterator, MatchResultCollector matchResultCollector) { 18 | MatchIterator mi = matchIterator.copy(); 19 | if (matcher.match(mi, matchResultCollector)) { 20 | matchIterator.advanceTo(mi); 21 | return true; 22 | } 23 | return true; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/bytecode/analysis/opgraph/op4rewriters/matchutil/MatchResultCollector.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.bytecode.analysis.opgraph.op4rewriters.matchutil; 2 | 3 | import org.benf.cfr.reader.bytecode.analysis.parse.wildcard.WildcardMatch; 4 | import org.benf.cfr.reader.bytecode.analysis.structured.StructuredStatement; 5 | 6 | public interface MatchResultCollector { 7 | void clear(); 8 | 9 | void collectStatement(String name, StructuredStatement statement); 10 | 11 | void collectMatches(String name, WildcardMatch wcm); 12 | } 13 | -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/bytecode/analysis/opgraph/op4rewriters/matchutil/MatchSequence.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.bytecode.analysis.opgraph.op4rewriters.matchutil; 2 | 3 | import org.benf.cfr.reader.bytecode.analysis.structured.StructuredStatement; 4 | 5 | public class MatchSequence implements Matcher { 6 | 7 | private final Matcher[] inner; 8 | @SuppressWarnings("unused") 9 | private final String name; // useful for breakpointing. 10 | 11 | public MatchSequence(Matcher... inner) { 12 | this.inner = inner; 13 | this.name = ""; 14 | } 15 | 16 | public MatchSequence(String name, Matcher... inner) { 17 | this.inner = inner; 18 | this.name = name; 19 | } 20 | 21 | @Override 22 | public boolean match(MatchIterator matchIterator, MatchResultCollector matchResultCollector) { 23 | MatchIterator mi = matchIterator.copy(); 24 | 25 | for (Matcher matcher : inner) { 26 | if (!matcher.match(mi, matchResultCollector)) { 27 | return false; 28 | } 29 | } 30 | 31 | matchIterator.advanceTo(mi); 32 | return true; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/bytecode/analysis/opgraph/op4rewriters/matchutil/Matcher.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.bytecode.analysis.opgraph.op4rewriters.matchutil; 2 | 3 | public interface Matcher { 4 | boolean match(MatchIterator matchIterator, MatchResultCollector matchResultCollector); 5 | } 6 | -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/bytecode/analysis/opgraph/op4rewriters/matchutil/ResetAfterTest.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.bytecode.analysis.opgraph.op4rewriters.matchutil; 2 | 3 | import org.benf.cfr.reader.bytecode.analysis.parse.wildcard.WildcardMatch; 4 | import org.benf.cfr.reader.bytecode.analysis.structured.StructuredStatement; 5 | 6 | public class ResetAfterTest implements Matcher { 7 | private final WildcardMatch wildcardMatch; 8 | private final Matcher inner; 9 | private final String name; 10 | 11 | public ResetAfterTest(WildcardMatch wildcardMatch, Matcher inner) { 12 | this(wildcardMatch, "", inner); 13 | } 14 | 15 | public ResetAfterTest(WildcardMatch wildcardMatch, String name, Matcher inner) { 16 | this.inner = inner; 17 | this.wildcardMatch = wildcardMatch; 18 | this.name = name; 19 | } 20 | 21 | @Override 22 | public boolean match(MatchIterator matchIterator, MatchResultCollector matchResultCollector) { 23 | boolean result = inner.match(matchIterator, matchResultCollector); 24 | if (result) matchResultCollector.collectMatches(name, wildcardMatch); 25 | wildcardMatch.reset(); 26 | return result; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/bytecode/analysis/opgraph/op4rewriters/transformers/CanRemovePointlessBlock.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.bytecode.analysis.opgraph.op4rewriters.transformers; 2 | 3 | import org.benf.cfr.reader.bytecode.analysis.structured.StructuredScope; 4 | 5 | public interface CanRemovePointlessBlock { 6 | void removePointlessBlocks(StructuredScope scope); 7 | } 8 | -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/bytecode/analysis/opgraph/op4rewriters/transformers/ExpressionRewriterTransformer.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.bytecode.analysis.opgraph.op4rewriters.transformers; 2 | 3 | import org.benf.cfr.reader.bytecode.analysis.opgraph.Op04StructuredStatement; 4 | import org.benf.cfr.reader.bytecode.analysis.parse.rewriters.ExpressionRewriter; 5 | import org.benf.cfr.reader.bytecode.analysis.structured.StructuredScope; 6 | import org.benf.cfr.reader.bytecode.analysis.structured.StructuredStatement; 7 | 8 | public class ExpressionRewriterTransformer implements StructuredStatementTransformer { 9 | private final ExpressionRewriter expressionRewriter; 10 | 11 | public ExpressionRewriterTransformer(ExpressionRewriter expressionRewriter) { 12 | this.expressionRewriter = expressionRewriter; 13 | } 14 | 15 | public void transform(Op04StructuredStatement root) { 16 | StructuredScope structuredScope = new StructuredScope(); 17 | root.transform(this, structuredScope); 18 | } 19 | 20 | @Override 21 | public StructuredStatement transform(StructuredStatement in, StructuredScope scope) { 22 | // This is incapable of fundamentally changing the statement type. 23 | // Need a different rewriter if we're going to do that. 24 | in.rewriteExpressions(expressionRewriter); 25 | in.transformStructuredChildren(this, scope); 26 | return in; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/bytecode/analysis/opgraph/op4rewriters/transformers/StructuredStatementTransformer.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.bytecode.analysis.opgraph.op4rewriters.transformers; 2 | 3 | import org.benf.cfr.reader.bytecode.analysis.structured.StructuredScope; 4 | import org.benf.cfr.reader.bytecode.analysis.structured.StructuredStatement; 5 | 6 | public interface StructuredStatementTransformer { 7 | StructuredStatement transform(StructuredStatement in, StructuredScope scope); 8 | } 9 | -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/bytecode/analysis/opgraph/op4rewriters/transformers/TryResourceTransformerFinally.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.bytecode.analysis.opgraph.op4rewriters.transformers; 2 | 3 | import org.benf.cfr.reader.bytecode.analysis.opgraph.Op04StructuredStatement; 4 | import org.benf.cfr.reader.bytecode.analysis.structured.StructuredScope; 5 | import org.benf.cfr.reader.bytecode.analysis.structured.statement.StructuredTry; 6 | import org.benf.cfr.reader.entities.ClassFile; 7 | 8 | public abstract class TryResourceTransformerFinally extends TryResourcesTransformerBase{ 9 | public TryResourceTransformerFinally(ClassFile classFile) { 10 | super(classFile); 11 | } 12 | 13 | @Override 14 | protected ResourceMatch getResourceMatch(StructuredTry structuredTry, StructuredScope scope) { 15 | Op04StructuredStatement finallyBlock = structuredTry.getFinallyBlock(); 16 | return findResourceFinally(finallyBlock); 17 | } 18 | 19 | // If the finally block is 20 | // if (autoclosable != null) { 21 | // close(exception, autoclosable) 22 | // } 23 | // 24 | // or 25 | // 26 | // close(exception, autoclosable) 27 | // 28 | // we can lift the autocloseable into the try. 29 | protected abstract ResourceMatch findResourceFinally(Op04StructuredStatement finallyBlock); 30 | 31 | } 32 | -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/bytecode/analysis/opgraph/op4rewriters/transformers/UnusedAnonymousBlockFlattener.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.bytecode.analysis.opgraph.op4rewriters.transformers; 2 | 3 | import org.benf.cfr.reader.bytecode.analysis.structured.StructuredScope; 4 | import org.benf.cfr.reader.bytecode.analysis.structured.StructuredStatement; 5 | import org.benf.cfr.reader.bytecode.analysis.structured.statement.Block; 6 | 7 | public class UnusedAnonymousBlockFlattener implements StructuredStatementTransformer { 8 | @Override 9 | public StructuredStatement transform(StructuredStatement in, StructuredScope scope) { 10 | if (in instanceof Block) { 11 | ((Block)in).flattenOthersIn(); 12 | } 13 | in.transformStructuredChildren(this, scope); 14 | return in; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/bytecode/analysis/parse/StatementContainer.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.bytecode.analysis.parse; 2 | 3 | import org.benf.cfr.reader.bytecode.analysis.opgraph.InstrIndex; 4 | import org.benf.cfr.reader.bytecode.analysis.parse.utils.BlockIdentifier; 5 | import org.benf.cfr.reader.bytecode.analysis.parse.utils.SSAIdentifiers; 6 | 7 | import java.util.Set; 8 | 9 | public interface StatementContainer { 10 | T getStatement(); 11 | 12 | T getTargetStatement(int idx); 13 | 14 | String getLabel(); 15 | 16 | InstrIndex getIndex(); 17 | 18 | void nopOut(); 19 | 20 | void replaceStatement(T newTarget); 21 | 22 | void nopOutConditional(); 23 | 24 | SSAIdentifiers getSSAIdentifiers(); 25 | 26 | Set getBlockIdentifiers(); 27 | 28 | BlockIdentifier getBlockStarted(); 29 | 30 | Set getBlocksEnded(); 31 | 32 | void copyBlockInformationFrom(StatementContainer other); 33 | 34 | void copyBytecodeInformationFrom(StatementContainer other); 35 | } 36 | -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/bytecode/analysis/parse/expression/AbstractAssignmentExpression.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.bytecode.analysis.parse.expression; 2 | 3 | import org.benf.cfr.reader.bytecode.analysis.loc.BytecodeLoc; 4 | import org.benf.cfr.reader.bytecode.analysis.parse.LValue; 5 | import org.benf.cfr.reader.bytecode.analysis.types.discovery.InferredJavaType; 6 | 7 | public abstract class AbstractAssignmentExpression extends AbstractExpression { 8 | 9 | public AbstractAssignmentExpression(BytecodeLoc loc, InferredJavaType inferredJavaType) { 10 | super(loc, inferredJavaType); 11 | } 12 | 13 | public abstract boolean isSelfMutatingOp1(LValue lValue, ArithOp arithOp); 14 | 15 | public abstract ArithmeticPostMutationOperation getPostMutation(); 16 | 17 | public abstract ArithmeticPreMutationOperation getPreMutation(); 18 | 19 | public abstract LValue getUpdatedLValue(); 20 | } 21 | -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/bytecode/analysis/parse/expression/AbstractMutatingAssignmentExpression.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.bytecode.analysis.parse.expression; 2 | 3 | import org.benf.cfr.reader.bytecode.analysis.loc.BytecodeLoc; 4 | import org.benf.cfr.reader.bytecode.analysis.types.RawJavaType; 5 | import org.benf.cfr.reader.bytecode.analysis.types.discovery.InferredJavaType; 6 | import org.benf.cfr.reader.entities.exceptions.ExceptionCheck; 7 | 8 | public abstract class AbstractMutatingAssignmentExpression extends AbstractAssignmentExpression { 9 | AbstractMutatingAssignmentExpression(BytecodeLoc loc, InferredJavaType inferredJavaType) { 10 | super(loc, inferredJavaType); 11 | } 12 | 13 | @Override 14 | public boolean canThrow(ExceptionCheck caught) { 15 | return !(getInferredJavaType().getJavaTypeInstance() instanceof RawJavaType); 16 | } 17 | 18 | @Override 19 | public boolean isValidStatement() { 20 | return true; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/bytecode/analysis/parse/expression/AbstractNewArray.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.bytecode.analysis.parse.expression; 2 | 3 | import org.benf.cfr.reader.bytecode.analysis.loc.BytecodeLoc; 4 | import org.benf.cfr.reader.bytecode.analysis.parse.Expression; 5 | import org.benf.cfr.reader.bytecode.analysis.parse.expression.misc.Precedence; 6 | import org.benf.cfr.reader.bytecode.analysis.types.discovery.InferredJavaType; 7 | 8 | public abstract class AbstractNewArray extends AbstractExpression { 9 | AbstractNewArray(BytecodeLoc loc, InferredJavaType inferredJavaType) { 10 | super(loc, inferredJavaType); 11 | } 12 | 13 | @Override 14 | public Precedence getPrecedence() { 15 | return Precedence.PAREN_SUB_MEMBER; 16 | } 17 | 18 | public abstract int getNumDims(); 19 | 20 | public abstract int getNumSizedDims(); 21 | 22 | public abstract Expression getDimSize(int dim); 23 | } 24 | -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/bytecode/analysis/parse/expression/BoolOp.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.bytecode.analysis.parse.expression; 2 | 3 | import org.benf.cfr.reader.bytecode.analysis.parse.expression.misc.Precedence; 4 | import org.benf.cfr.reader.util.ConfusedCFRException; 5 | 6 | public enum BoolOp { 7 | OR("||", Precedence.LOG_OR), 8 | AND("&&", Precedence.LOG_AND); 9 | 10 | private final String showAs; 11 | private final Precedence precedence; 12 | 13 | BoolOp(String showAs, Precedence precedence) { 14 | this.showAs = showAs; 15 | this.precedence = precedence; 16 | } 17 | 18 | public String getShowAs() { 19 | return showAs; 20 | } 21 | 22 | public Precedence getPrecedence() { 23 | return precedence; 24 | } 25 | 26 | public BoolOp getDemorgan() { 27 | switch (this) { 28 | case OR: 29 | return AND; 30 | case AND: 31 | return OR; 32 | default: 33 | throw new ConfusedCFRException("Unknown op."); 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/bytecode/analysis/parse/expression/ConditionalExpression.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.bytecode.analysis.parse.expression; 2 | 3 | import org.benf.cfr.reader.bytecode.analysis.parse.Expression; 4 | import org.benf.cfr.reader.bytecode.analysis.parse.LValue; 5 | import org.benf.cfr.reader.bytecode.analysis.parse.expression.misc.Precedence; 6 | 7 | import java.util.Set; 8 | 9 | public interface ConditionalExpression extends Expression { 10 | ConditionalExpression getNegated(); 11 | 12 | int getSize(Precedence outerPrecedence); 13 | 14 | ConditionalExpression getDemorganApplied(boolean amNegating); 15 | 16 | /* 17 | * Normalise tree layout so ((a || b) || c) --> (a || (b || c)). 18 | * This is useful so any patterns can know what they're matching against. 19 | */ 20 | ConditionalExpression getRightDeep(); 21 | 22 | Set getLoopLValues(); 23 | 24 | ConditionalExpression optimiseForType(); 25 | 26 | ConditionalExpression simplify(); 27 | } 28 | -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/bytecode/analysis/parse/expression/LambdaExpressionCommon.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.bytecode.analysis.parse.expression; 2 | 3 | public interface LambdaExpressionCommon { 4 | } 5 | -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/bytecode/analysis/parse/expression/LiteralHex.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.bytecode.analysis.parse.expression; 2 | 3 | import org.benf.cfr.reader.bytecode.analysis.parse.literal.TypedLiteral; 4 | import org.benf.cfr.reader.util.output.Dumper; 5 | 6 | /* 7 | * It's debatable whether we should have this, or make it a temporary state of the dumper, such 8 | * that we dump literals immediately under a bitwise operation as hex. 9 | * 10 | * Currently, have gone for this, as the maintenance to force a reset if we have 11 | * 0xff | (0xf + foo(12, 23, 14)) 12 | * means we would need to undo any dumper state not just on the way back up, but also when we left 13 | * literals immediately inside the tree. This feels like it's a lot more work than it's worth. 14 | * 15 | * Doing things this way also means that if we eventually expose this class, we can allow a UI to tweak 16 | * this node... ;) 17 | */ 18 | public class LiteralHex extends Literal { 19 | 20 | public LiteralHex(TypedLiteral value) { 21 | super(value); 22 | } 23 | 24 | @Override 25 | public Dumper dumpInner(Dumper d) { 26 | return value.dumpWithHint(d, TypedLiteral.FormatHint.Hex); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/bytecode/analysis/parse/expression/misc/Precedence.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.bytecode.analysis.parse.expression.misc; 2 | 3 | public enum Precedence { 4 | HIGHEST(true), 5 | PAREN_SUB_MEMBER(true), 6 | LAMBDA(true), 7 | UNARY_POST(false), 8 | UNARY_OTHER(false), 9 | MUL_DIV_MOD(true), 10 | ADD_SUB(true), 11 | BITWISE_SHIFT(true), 12 | REL_CMP_INSTANCEOF(true), 13 | REL_EQ(true), 14 | BIT_AND(true), 15 | BIT_XOR(true), 16 | BIT_OR(true), 17 | LOG_AND(true, true), 18 | LOG_OR(true, true), 19 | CONDITIONAL(false), 20 | ASSIGNMENT(false), 21 | WEAKEST(true); 22 | 23 | private final boolean isLtoR; 24 | private final boolean commute; 25 | 26 | Precedence(boolean ltoR) { 27 | this.isLtoR = ltoR; 28 | this.commute = false; 29 | } 30 | 31 | Precedence(boolean ltoR, boolean commute) { 32 | this.isLtoR = ltoR; 33 | this.commute = commute; 34 | } 35 | 36 | public boolean isLtoR() { 37 | return isLtoR; 38 | } 39 | 40 | public boolean isCommutative() { 41 | return commute; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/bytecode/analysis/parse/expression/rewriteinterface/BoxingProcessor.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.bytecode.analysis.parse.expression.rewriteinterface; 2 | 3 | import org.benf.cfr.reader.bytecode.analysis.opgraph.op4rewriters.PrimitiveBoxingRewriter; 4 | import org.benf.cfr.reader.bytecode.analysis.parse.StatementContainer; 5 | import org.benf.cfr.reader.bytecode.analysis.parse.rewriters.ExpressionRewriter; 6 | import org.benf.cfr.reader.bytecode.analysis.parse.rewriters.ExpressionRewriterFlags; 7 | import org.benf.cfr.reader.bytecode.analysis.parse.utils.SSAIdentifiers; 8 | 9 | public interface BoxingProcessor { 10 | // return true if boxing finished. 11 | boolean rewriteBoxing(PrimitiveBoxingRewriter boxingRewriter); 12 | 13 | void applyNonArgExpressionRewriter(ExpressionRewriter expressionRewriter, SSAIdentifiers ssaIdentifiers, StatementContainer statementContainer, ExpressionRewriterFlags flags); 14 | } 15 | -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/bytecode/analysis/parse/expression/rewriteinterface/FunctionProcessor.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.bytecode.analysis.parse.expression.rewriteinterface; 2 | 3 | import org.benf.cfr.reader.bytecode.analysis.opgraph.op4rewriters.VarArgsRewriter; 4 | 5 | public interface FunctionProcessor { 6 | // This feels like it should be refactored into a generalised visitor interface 7 | void rewriteVarArgs(VarArgsRewriter varArgsRewriter); 8 | } 9 | -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/bytecode/analysis/parse/rewriters/AbstractExpressionVisitor.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.bytecode.analysis.parse.rewriters; 2 | 3 | import org.benf.cfr.reader.bytecode.analysis.parse.Expression; 4 | import org.benf.cfr.reader.bytecode.analysis.parse.expression.ArithmeticOperation; 5 | import org.benf.cfr.reader.bytecode.analysis.parse.expression.Literal; 6 | import org.benf.cfr.reader.bytecode.analysis.parse.expression.TernaryExpression; 7 | 8 | public class AbstractExpressionVisitor implements ExpressionVisitor { 9 | @Override 10 | public T visit(Expression e) { 11 | return null; 12 | } 13 | 14 | @Override 15 | public T visit(Literal l) { 16 | return null; 17 | } 18 | 19 | @Override 20 | public T visit(TernaryExpression e) { 21 | return null; 22 | } 23 | 24 | @Override 25 | public T visit(ArithmeticOperation e) { 26 | return null; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/bytecode/analysis/parse/rewriters/DeepCloneable.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.bytecode.analysis.parse.rewriters; 2 | 3 | public interface DeepCloneable { 4 | X deepClone(CloneHelper cloneHelper); 5 | 6 | // Outer deep clone exists to cause visitor action, as we've lost generic information at the 7 | // call site. 8 | X outerDeepClone(CloneHelper cloneHelper); 9 | } 10 | -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/bytecode/analysis/parse/rewriters/ExpressionRewriterFlags.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.bytecode.analysis.parse.rewriters; 2 | 3 | public enum ExpressionRewriterFlags { 4 | RVALUE, 5 | LVALUE, 6 | LANDRVALUE 7 | } 8 | -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/bytecode/analysis/parse/rewriters/ExpressionRewriterHelper.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.bytecode.analysis.parse.rewriters; 2 | 3 | import org.benf.cfr.reader.bytecode.analysis.parse.Expression; 4 | import org.benf.cfr.reader.bytecode.analysis.parse.StatementContainer; 5 | import org.benf.cfr.reader.bytecode.analysis.parse.utils.SSAIdentifiers; 6 | 7 | import java.util.List; 8 | 9 | public class ExpressionRewriterHelper { 10 | public static void applyForwards(List list, ExpressionRewriter expressionRewriter, SSAIdentifiers ssaIdentifiers, StatementContainer statementContainer, ExpressionRewriterFlags flags) { 11 | for (int x = 0; x < list.size(); ++x) { 12 | list.set(x, expressionRewriter.rewriteExpression(list.get(x), ssaIdentifiers, statementContainer, flags)); 13 | } 14 | } 15 | 16 | public static void applyBackwards(List list, ExpressionRewriter expressionRewriter, SSAIdentifiers ssaIdentifiers, StatementContainer statementContainer, ExpressionRewriterFlags flags) { 17 | for (int x = list.size()-1; x >= 0; --x) { 18 | list.set(x, expressionRewriter.rewriteExpression(list.get(x), ssaIdentifiers, statementContainer, flags)); 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/bytecode/analysis/parse/rewriters/ExpressionVisitor.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.bytecode.analysis.parse.rewriters; 2 | 3 | import org.benf.cfr.reader.bytecode.analysis.parse.Expression; 4 | import org.benf.cfr.reader.bytecode.analysis.parse.expression.ArithmeticOperation; 5 | import org.benf.cfr.reader.bytecode.analysis.parse.expression.Literal; 6 | import org.benf.cfr.reader.bytecode.analysis.parse.expression.TernaryExpression; 7 | 8 | public interface ExpressionVisitor { 9 | T visit(Expression e); 10 | 11 | T visit(Literal l); 12 | 13 | T visit(TernaryExpression e); 14 | 15 | T visit(ArithmeticOperation e); 16 | } 17 | -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/bytecode/analysis/parse/statement/AbstractAssignment.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.bytecode.analysis.parse.statement; 2 | 3 | import org.benf.cfr.reader.bytecode.analysis.loc.BytecodeLoc; 4 | import org.benf.cfr.reader.bytecode.analysis.parse.Expression; 5 | import org.benf.cfr.reader.bytecode.analysis.parse.LValue; 6 | import org.benf.cfr.reader.bytecode.analysis.parse.expression.AbstractAssignmentExpression; 7 | import org.benf.cfr.reader.bytecode.analysis.parse.expression.ArithOp; 8 | 9 | public abstract class AbstractAssignment extends AbstractStatement { 10 | 11 | public AbstractAssignment(BytecodeLoc loc) { 12 | super(loc); 13 | } 14 | 15 | public abstract boolean isSelfMutatingOperation(); 16 | 17 | public abstract boolean isSelfMutatingOp1(LValue lValue, ArithOp arithOp); 18 | 19 | public abstract Expression getPostMutation(); 20 | 21 | public abstract Expression getPreMutation(); 22 | 23 | public abstract AbstractAssignmentExpression getInliningExpression(); 24 | } 25 | -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/bytecode/analysis/parse/statement/JumpingStatement.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.bytecode.analysis.parse.statement; 2 | 3 | import org.benf.cfr.reader.bytecode.analysis.loc.BytecodeLoc; 4 | import org.benf.cfr.reader.bytecode.analysis.parse.Statement; 5 | import org.benf.cfr.reader.bytecode.analysis.parse.utils.JumpType; 6 | 7 | public abstract class JumpingStatement extends AbstractStatement { 8 | public JumpingStatement(BytecodeLoc loc) { 9 | super(loc); 10 | } 11 | 12 | public abstract Statement getJumpTarget(); 13 | 14 | public abstract JumpType getJumpType(); 15 | 16 | public abstract void setJumpType(JumpType jumpType); 17 | 18 | public abstract boolean isConditional(); 19 | } 20 | -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/bytecode/analysis/parse/statement/MonitorStatement.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.bytecode.analysis.parse.statement; 2 | 3 | import org.benf.cfr.reader.bytecode.analysis.loc.BytecodeLoc; 4 | 5 | public abstract class MonitorStatement extends AbstractStatement { 6 | public MonitorStatement(BytecodeLoc loc) { 7 | super(loc); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/bytecode/analysis/parse/statement/ReturnStatement.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.bytecode.analysis.parse.statement; 2 | 3 | import org.benf.cfr.reader.bytecode.analysis.loc.BytecodeLoc; 4 | import org.benf.cfr.reader.bytecode.analysis.parse.rewriters.CloneHelper; 5 | import org.benf.cfr.reader.bytecode.analysis.parse.rewriters.DeepCloneable; 6 | 7 | public abstract class ReturnStatement extends AbstractStatement { 8 | 9 | public ReturnStatement(BytecodeLoc loc) { 10 | super(loc); 11 | } 12 | 13 | @Override 14 | public boolean fallsToNext() { 15 | return false; 16 | } 17 | 18 | @Override 19 | public ReturnStatement outerDeepClone(CloneHelper cloneHelper) { 20 | throw new UnsupportedOperationException(); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/bytecode/analysis/parse/utils/BlockIdentifierFactory.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.bytecode.analysis.parse.utils; 2 | 3 | public class BlockIdentifierFactory { 4 | int idx = 0; 5 | 6 | public BlockIdentifier getNextBlockIdentifier(BlockType blockType) { 7 | return new BlockIdentifier(idx++, blockType); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/bytecode/analysis/parse/utils/BlockType.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.bytecode.analysis.parse.utils; 2 | 3 | public enum BlockType { 4 | WHILELOOP(true, true), 5 | DOLOOP(true, true), 6 | UNCONDITIONALDOLOOP(true, true), 7 | FORLOOP(true, true), 8 | TRYBLOCK(false, false), 9 | SIMPLE_IF_TAKEN(false, false), 10 | SIMPLE_IF_ELSE(false, false), 11 | CATCHBLOCK(false, false), 12 | SWITCH(true, false), 13 | CASE(false, false), 14 | ANONYMOUS(true, false), 15 | MONITOR(false, false); 16 | 17 | private final boolean breakable; 18 | private final boolean isloop; 19 | 20 | BlockType(boolean breakable, boolean isloop) { 21 | this.breakable = breakable; 22 | this.isloop = isloop; 23 | } 24 | 25 | public boolean isBreakable() { 26 | return breakable; 27 | } 28 | 29 | public boolean isLoop() { return isloop; } 30 | 31 | } 32 | -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/bytecode/analysis/parse/utils/ComparableUnderEC.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.bytecode.analysis.parse.utils; 2 | 3 | public interface ComparableUnderEC { 4 | boolean equivalentUnder(Object o, EquivalenceConstraint constraint); 5 | } 6 | -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/bytecode/analysis/parse/utils/EquivalenceConstraint.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.bytecode.analysis.parse.utils; 2 | 3 | import java.util.Collection; 4 | 5 | public interface EquivalenceConstraint { 6 | boolean equivalent(Object o1, Object o2); 7 | 8 | boolean equivalent(Collection o1, Collection o2); 9 | 10 | boolean equivalent(ComparableUnderEC o1, ComparableUnderEC o2); 11 | } 12 | -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/bytecode/analysis/parse/utils/JumpType.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.bytecode.analysis.parse.utils; 2 | 3 | public enum JumpType { 4 | NONE("none", false), 5 | GOTO("goto", true), 6 | GOTO_OUT_OF_IF("goto_out_of_if", false), 7 | GOTO_OUT_OF_TRY("goto_out_of_try", false), 8 | BREAK("break", false), 9 | BREAK_ANONYMOUS("break anon", false), 10 | CONTINUE("continue", false), 11 | END_BLOCK("// endblock", false); 12 | 13 | 14 | private final String description; 15 | private final boolean isUnknown; 16 | 17 | JumpType(String description, boolean isUnknown) { 18 | this.description = description; 19 | this.isUnknown = isUnknown; 20 | } 21 | 22 | public boolean isUnknown() { 23 | return isUnknown; 24 | } 25 | 26 | @Override 27 | public String toString() { 28 | return description; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/bytecode/analysis/parse/utils/LValueAssignmentCollector.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.bytecode.analysis.parse.utils; 2 | 3 | import org.benf.cfr.reader.bytecode.analysis.parse.Expression; 4 | import org.benf.cfr.reader.bytecode.analysis.parse.LValue; 5 | import org.benf.cfr.reader.bytecode.analysis.parse.StatementContainer; 6 | import org.benf.cfr.reader.bytecode.analysis.parse.lvalue.LocalVariable; 7 | import org.benf.cfr.reader.bytecode.analysis.parse.lvalue.StackSSALabel; 8 | 9 | public interface LValueAssignmentCollector { 10 | // TODO : Should these be StackSSALabels? Seems they should be lvalues. 11 | void collect(StackSSALabel lValue, StatementContainer statementContainer, Expression value); 12 | 13 | void collectMultiUse(StackSSALabel lValue, StatementContainer statementContainer, Expression value); 14 | 15 | void collectMutatedLValue(LValue lValue, StatementContainer statementContainer, Expression value); 16 | 17 | void collectLocalVariableAssignment(LocalVariable localVariable, StatementContainer statementContainer, Expression value); 18 | } 19 | -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/bytecode/analysis/parse/utils/LValueUsageCollector.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.bytecode.analysis.parse.utils; 2 | 3 | import org.benf.cfr.reader.bytecode.analysis.parse.LValue; 4 | 5 | public interface LValueUsageCollector { 6 | void collect(LValue lValue, ReadWrite rw); 7 | } 8 | -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/bytecode/analysis/parse/utils/LValueUsageCollectorSimple.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.bytecode.analysis.parse.utils; 2 | 3 | import org.benf.cfr.reader.bytecode.analysis.parse.LValue; 4 | import org.benf.cfr.reader.util.collections.SetFactory; 5 | 6 | import java.util.Collection; 7 | import java.util.Set; 8 | 9 | public class LValueUsageCollectorSimple implements LValueUsageCollector { 10 | private final Set used = SetFactory.newSet(); 11 | 12 | @Override 13 | public void collect(LValue lValue, ReadWrite rw) { 14 | used.add(lValue); 15 | } 16 | 17 | public Collection getUsedLValues() { 18 | return used; 19 | } 20 | 21 | public boolean isUsed(LValue lValue) { 22 | return used.contains(lValue); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/bytecode/analysis/parse/utils/LValueUsageCollectorSimpleRW.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.bytecode.analysis.parse.utils; 2 | 3 | import org.benf.cfr.reader.bytecode.analysis.parse.LValue; 4 | import org.benf.cfr.reader.util.collections.SetFactory; 5 | 6 | import java.util.Set; 7 | 8 | public class LValueUsageCollectorSimpleRW implements LValueUsageCollector { 9 | private final Set read = SetFactory.newSet(); 10 | private final Set write = SetFactory.newSet(); 11 | 12 | @Override 13 | public void collect(LValue lValue, ReadWrite rw) { 14 | switch (rw) { 15 | case READ: 16 | read.add(lValue); 17 | break; 18 | case READ_WRITE: 19 | read.add(lValue); 20 | case WRITE: 21 | write.add(lValue); 22 | break; 23 | } 24 | } 25 | 26 | public Set getRead() { 27 | return read; 28 | } 29 | 30 | public Set getWritten() { 31 | return write; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/bytecode/analysis/parse/utils/ReadWrite.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.bytecode.analysis.parse.utils; 2 | 3 | public enum ReadWrite { 4 | READ, 5 | WRITE, 6 | READ_WRITE 7 | } 8 | -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/bytecode/analysis/parse/utils/SSAIdentifierFactory.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.bytecode.analysis.parse.utils; 2 | 3 | import org.benf.cfr.reader.util.collections.MapFactory; 4 | import org.benf.cfr.reader.util.functors.UnaryFunction; 5 | 6 | import java.util.Map; 7 | 8 | public class SSAIdentifierFactory { 9 | private final Map nextIdentFor = MapFactory.newLazyMap( 10 | MapFactory.newOrderedMap(), 11 | new UnaryFunction() { 12 | @Override 13 | public Integer invoke(KEYTYPE ignore) { 14 | return 0; 15 | } 16 | }); 17 | 18 | private final UnaryFunction typeComparisonFunction; 19 | 20 | public SSAIdentifierFactory(UnaryFunction typeComparisonFunction) { 21 | this.typeComparisonFunction = typeComparisonFunction; 22 | } 23 | 24 | public SSAIdent getIdent(KEYTYPE lValue) { 25 | int val = nextIdentFor.get(lValue); 26 | nextIdentFor.put(lValue, val + 1); 27 | return new SSAIdent(val, typeComparisonFunction == null ? null : typeComparisonFunction.invoke(lValue)); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/bytecode/analysis/parse/utils/SSAIdentifierUtils.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.bytecode.analysis.parse.utils; 2 | 3 | import org.benf.cfr.reader.bytecode.analysis.parse.LValue; 4 | 5 | import java.util.Collection; 6 | 7 | public class SSAIdentifierUtils { 8 | public static boolean isMovableUnder(Collection lValues, LValue lValueMove, SSAIdentifiers atTarget, SSAIdentifiers atSource) { 9 | for (LValue lValue : lValues) { 10 | if (!atTarget.isValidReplacement(lValue, atSource)) return false; 11 | } 12 | SSAIdent afterSrc = atSource.getSSAIdentOnExit(lValueMove); 13 | if (afterSrc == null) return false; 14 | SSAIdent beforeTarget = atTarget.getSSAIdentOnEntry(lValueMove); 15 | if (beforeTarget == null) return false; 16 | if (beforeTarget.isSuperSet(afterSrc)) return true; 17 | // weird, but I suppose legitimate. 18 | SSAIdent afterTarget = atTarget.getSSAIdentOnExit(lValueMove); 19 | if (beforeTarget.equals(afterSrc) && afterTarget.equals(afterSrc)) return true; 20 | return false; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/bytecode/analysis/parse/utils/scope/ScopeDiscoverInfoCache.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.bytecode.analysis.parse.utils.scope; 2 | 3 | import org.benf.cfr.reader.bytecode.analysis.structured.StructuredStatement; 4 | import org.benf.cfr.reader.util.collections.MapFactory; 5 | 6 | import java.util.Map; 7 | 8 | public class ScopeDiscoverInfoCache { 9 | private final Map tests = MapFactory.newIdentityMap(); 10 | 11 | public Boolean get(StructuredStatement structuredStatement) { 12 | return tests.get(structuredStatement); 13 | } 14 | 15 | public void put(StructuredStatement structuredStatement, Boolean b) { 16 | tests.put(structuredStatement, b); 17 | } 18 | 19 | boolean anyFound() { 20 | for (Boolean value : tests.values()) { 21 | if (value) return true; 22 | } 23 | return false; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/bytecode/analysis/parse/wildcard/OptionalMatch.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.bytecode.analysis.parse.wildcard; 2 | 3 | import org.benf.cfr.reader.util.Optional; 4 | 5 | public class OptionalMatch { 6 | final Optional expected; // may be missing. 7 | T matched; 8 | 9 | OptionalMatch(Optional expected) { 10 | this.expected = expected; 11 | reset(); 12 | } 13 | 14 | public boolean match(T other) { 15 | if (matched != null) return matched.equals(other); 16 | matched = other; 17 | return true; 18 | } 19 | 20 | public void reset() { 21 | if (expected.isSet()) { 22 | matched = expected.getValue(); 23 | } else { 24 | matched = null; 25 | } 26 | } 27 | 28 | public T getMatch() { 29 | return matched; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/bytecode/analysis/parse/wildcard/Wildcard.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.bytecode.analysis.parse.wildcard; 2 | 3 | public interface Wildcard { 4 | X getMatch(); 5 | 6 | void resetMatch(); 7 | } 8 | -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/bytecode/analysis/stack/StackDelta.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.bytecode.analysis.stack; 2 | 3 | import org.benf.cfr.reader.bytecode.analysis.types.StackTypes; 4 | 5 | public interface StackDelta { 6 | boolean isNoOp(); 7 | 8 | StackTypes getConsumed(); 9 | 10 | StackTypes getProduced(); 11 | 12 | long getChange(); 13 | } 14 | -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/bytecode/analysis/stack/StackDeltaImpl.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.bytecode.analysis.stack; 2 | 3 | import org.benf.cfr.reader.bytecode.analysis.types.StackTypes; 4 | import org.benf.cfr.reader.util.ConfusedCFRException; 5 | 6 | public class StackDeltaImpl implements StackDelta { 7 | private final StackTypes consumed; 8 | private final StackTypes produced; 9 | 10 | public StackDeltaImpl(StackTypes consumed, StackTypes produced) { 11 | if (consumed == null || produced == null) { 12 | throw new ConfusedCFRException("Must not have null stackTypes"); 13 | } 14 | this.consumed = consumed; 15 | this.produced = produced; 16 | } 17 | 18 | @Override 19 | public boolean isNoOp() { 20 | return consumed.isEmpty() && produced.isEmpty(); 21 | } 22 | 23 | @Override 24 | public StackTypes getConsumed() { 25 | return consumed; 26 | } 27 | 28 | @Override 29 | public StackTypes getProduced() { 30 | return produced; 31 | } 32 | 33 | @Override 34 | public long getChange() { 35 | return produced.size() - consumed.size(); 36 | } 37 | 38 | @Override 39 | public String toString() { 40 | return "Consumes " + consumed + ", Produces " + produced; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/bytecode/analysis/stack/StackEntryHolder.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.bytecode.analysis.stack; 2 | 3 | import org.benf.cfr.reader.bytecode.analysis.types.StackType; 4 | import org.benf.cfr.reader.util.DecompilerComment; 5 | 6 | import java.util.Set; 7 | 8 | public class StackEntryHolder { 9 | private StackEntry stackEntry; 10 | 11 | StackEntryHolder(StackType stackType) { 12 | stackEntry = new StackEntry(stackType); 13 | } 14 | 15 | public void mergeWith(StackEntryHolder other, Set comments) { 16 | stackEntry.mergeWith(other.stackEntry, comments); 17 | other.stackEntry = stackEntry; 18 | } 19 | 20 | @Override 21 | public String toString() { 22 | return stackEntry.toString(); 23 | } 24 | 25 | public StackEntry getStackEntry() { 26 | return stackEntry; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/bytecode/analysis/structured/statement/AbstractStructuredContinue.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.bytecode.analysis.structured.statement; 2 | 3 | import org.benf.cfr.reader.bytecode.analysis.loc.BytecodeLoc; 4 | import org.benf.cfr.reader.bytecode.analysis.parse.utils.BlockIdentifier; 5 | 6 | public abstract class AbstractStructuredContinue extends AbstractStructuredStatement { 7 | public AbstractStructuredContinue(BytecodeLoc loc) { 8 | super(loc); 9 | } 10 | 11 | public abstract BlockIdentifier getContinueTgt(); 12 | } 13 | -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/bytecode/analysis/structured/statement/UnstructuredGoto.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.bytecode.analysis.structured.statement; 2 | 3 | import org.benf.cfr.reader.bytecode.analysis.loc.BytecodeLoc; 4 | import org.benf.cfr.reader.state.TypeUsageCollector; 5 | import org.benf.cfr.reader.util.output.Dumper; 6 | 7 | public class UnstructuredGoto extends AbstractUnStructuredStatement { 8 | 9 | public UnstructuredGoto(BytecodeLoc loc) { 10 | super(loc); 11 | } 12 | 13 | @Override 14 | public BytecodeLoc getCombinedLoc() { 15 | return getLoc(); 16 | } 17 | 18 | @Override 19 | public Dumper dump(Dumper dumper) { 20 | return dumper.print("** GOTO " + getContainer().getTargetLabel(0)).newln(); 21 | } 22 | 23 | @Override 24 | public void collectTypeUsages(TypeUsageCollector collector) { 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/bytecode/analysis/structured/statement/placeholder/ElseBlock.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.bytecode.analysis.structured.statement.placeholder; 2 | 3 | import org.benf.cfr.reader.bytecode.analysis.opgraph.op4rewriters.matchutil.MatchIterator; 4 | import org.benf.cfr.reader.bytecode.analysis.opgraph.op4rewriters.matchutil.MatchResultCollector; 5 | import org.benf.cfr.reader.bytecode.analysis.structured.StructuredStatement; 6 | 7 | public class ElseBlock extends AbstractPlaceholder { 8 | @Override 9 | public boolean match(MatchIterator matchIterator, MatchResultCollector matchResultCollector) { 10 | if (matchIterator.getCurrent() instanceof ElseBlock) { 11 | matchIterator.advance(); 12 | return true; 13 | } 14 | return false; 15 | } 16 | 17 | @Override 18 | public boolean supportsContinueBreak() { 19 | return false; 20 | } 21 | 22 | @Override 23 | public boolean supportsBreak() { 24 | return false; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/bytecode/analysis/structured/statement/placeholder/EndBlock.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.bytecode.analysis.structured.statement.placeholder; 2 | 3 | import org.benf.cfr.reader.bytecode.analysis.opgraph.op4rewriters.matchutil.MatchIterator; 4 | import org.benf.cfr.reader.bytecode.analysis.opgraph.op4rewriters.matchutil.MatchResultCollector; 5 | import org.benf.cfr.reader.bytecode.analysis.structured.StructuredStatement; 6 | import org.benf.cfr.reader.bytecode.analysis.structured.statement.Block; 7 | 8 | public class EndBlock extends AbstractPlaceholder { 9 | 10 | private final Block block; 11 | 12 | public EndBlock(Block block) { 13 | this.block = block; 14 | } 15 | 16 | @Override 17 | public boolean match(MatchIterator matchIterator, MatchResultCollector matchResultCollector) { 18 | StructuredStatement current = matchIterator.getCurrent(); 19 | if (current instanceof EndBlock) { 20 | EndBlock other = (EndBlock) current; 21 | if (block == null || block.equals(other.block)) { 22 | matchIterator.advance(); 23 | return true; 24 | } 25 | } 26 | return false; 27 | } 28 | 29 | @Override 30 | public boolean supportsContinueBreak() { 31 | return false; 32 | } 33 | 34 | @Override 35 | public boolean supportsBreak() { 36 | return false; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/bytecode/analysis/types/ClassNameUtils.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.bytecode.analysis.types; 2 | 3 | import org.benf.cfr.reader.bytecode.analysis.parse.utils.Pair; 4 | 5 | public class ClassNameUtils { 6 | public static String convertFromPath(String from) { 7 | return from.replace('/', '.'); 8 | } 9 | 10 | 11 | public static String convertToPath(String from) { 12 | return from.replace('.', '/'); 13 | } 14 | 15 | public static Pair getPackageAndClassNames(JavaTypeInstance type) { 16 | return getPackageAndClassNames(type.getRawName()); 17 | } 18 | 19 | public static Pair getPackageAndClassNames(String rawName) { 20 | String full = ClassNameUtils.convertFromPath(rawName); 21 | int idx = full.lastIndexOf('.'); 22 | if (idx == -1) return Pair.make("", rawName); 23 | return Pair.make(full.substring(0, idx), full.substring(idx + 1)); 24 | } 25 | 26 | public static String getTypeFixPrefix(JavaTypeInstance typ) { 27 | String rawName = typ.getRawName(); 28 | rawName = rawName.replace("[]", "_arr").replaceAll("[*?<>. ]","_"); 29 | return rawName + "_"; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/bytecode/analysis/types/DynamicInvokeType.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.bytecode.analysis.types; 2 | 3 | public enum DynamicInvokeType { 4 | UNKNOWN("?"), 5 | BOOTSTRAP("bootstrap"), // bootstrap - for groovy. 6 | METAFACTORY_1("metaFactory"), 7 | METAFACTORY_2("metafactory"), 8 | ALTMETAFACTORY_1("altMetaFactory"), 9 | ALTMETAFACTORY_2("altMetafactory"); 10 | 11 | private final String constName; 12 | 13 | DynamicInvokeType(String constName) { 14 | this.constName = constName; 15 | } 16 | 17 | public String getConstName() { 18 | return constName; 19 | } 20 | 21 | public static DynamicInvokeType lookup(String name) { 22 | if (name.equals(METAFACTORY_1.constName)) return METAFACTORY_1; 23 | if (name.equals(METAFACTORY_2.constName)) return METAFACTORY_2; 24 | if (name.equals(ALTMETAFACTORY_1.constName)) return ALTMETAFACTORY_1; 25 | if (name.equals(ALTMETAFACTORY_2.constName)) return ALTMETAFACTORY_2; 26 | if (name.equals(BOOTSTRAP.constName)) return BOOTSTRAP; 27 | return UNKNOWN; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/bytecode/analysis/types/InnerClassInfoUtils.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.bytecode.analysis.types; 2 | 3 | public class InnerClassInfoUtils { 4 | public static JavaRefTypeInstance getTransitiveOuterClass(JavaRefTypeInstance type) { 5 | while (type.getInnerClassHereInfo().isInnerClass()) { 6 | type = type.getInnerClassHereInfo().getOuterClass(); 7 | } 8 | return type; 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/bytecode/analysis/types/JavaGenericBaseInstance.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.bytecode.analysis.types; 2 | 3 | import org.benf.cfr.reader.entities.constantpool.ConstantPool; 4 | 5 | import java.util.List; 6 | import java.util.Map; 7 | 8 | public interface JavaGenericBaseInstance extends JavaTypeInstance { 9 | JavaTypeInstance getBoundInstance(GenericTypeBinder genericTypeBinder); 10 | 11 | boolean tryFindBinding(JavaTypeInstance other, GenericTypeBinder target); 12 | 13 | boolean hasUnbound(); 14 | 15 | boolean hasL01Wildcard(); 16 | 17 | JavaTypeInstance getWithoutL01Wildcard(); 18 | 19 | boolean hasForeignUnbound(ConstantPool cp, int depth, boolean noWildcard, Map externals); 20 | 21 | List getGenericTypes(); 22 | } 23 | -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/bytecode/analysis/types/MiscAnnotations.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.bytecode.analysis.types; 2 | 3 | import org.benf.cfr.reader.entities.annotations.AnnotationTableEntry; 4 | import org.benf.cfr.reader.entities.attributes.AttributeMap; 5 | import org.benf.cfr.reader.entities.attributes.AttributeRuntimeInvisibleAnnotations; 6 | import org.benf.cfr.reader.entities.attributes.AttributeRuntimeVisibleAnnotations; 7 | import org.benf.cfr.reader.util.collections.ListFactory; 8 | 9 | import java.util.List; 10 | 11 | public class MiscAnnotations { 12 | public static List BasicAnnotations(AttributeMap attributeMap) { 13 | AttributeRuntimeVisibleAnnotations a1 = attributeMap.getByName(AttributeRuntimeVisibleAnnotations.ATTRIBUTE_NAME); 14 | AttributeRuntimeInvisibleAnnotations a2 = attributeMap.getByName(AttributeRuntimeInvisibleAnnotations.ATTRIBUTE_NAME); 15 | List e1 = a1 == null ? null : a1.getEntryList(); 16 | List e2 = a2 == null ? null : a2.getEntryList(); 17 | return ListFactory.combinedOptimistic(e1,e2); 18 | } 19 | 20 | } 21 | -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/bytecode/analysis/types/StackType.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.bytecode.analysis.types; 2 | 3 | /** 4 | * See table 3.3 in JVM spec. 5 | */ 6 | public enum StackType { 7 | INT("int", 1, true), 8 | FLOAT("float", 1, true), 9 | REF("reference", 1, false), 10 | RETURNADDRESS("returnaddress", 1, false), 11 | RETURNADDRESSORREF("returnaddress or ref", 1, false), // Special, for astore. 12 | LONG("long", 2, true), 13 | DOUBLE("double", 2, true), 14 | VOID("void", 0, false); // not real, but useful. 15 | 16 | private final int computationCategory; 17 | private final StackTypes asList; 18 | private final boolean closed; 19 | private final String name; 20 | 21 | StackType(String name, int computationCategory, boolean closed) { 22 | this.name = name; 23 | this.computationCategory = computationCategory; 24 | this.asList = new StackTypes(this); 25 | this.closed = closed; 26 | } 27 | 28 | public int getComputationCategory() { 29 | return computationCategory; 30 | } 31 | 32 | public StackTypes asList() { 33 | return asList; 34 | } 35 | 36 | public boolean isClosed() { 37 | return closed; 38 | } 39 | 40 | @Override 41 | public String toString() { 42 | return name; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/bytecode/analysis/types/StackTypes.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.bytecode.analysis.types; 2 | 3 | import java.util.ArrayList; 4 | import java.util.Arrays; 5 | import java.util.List; 6 | 7 | /** 8 | * Really List but for legibility, shortened. 9 | */ 10 | public class StackTypes extends ArrayList { 11 | public static final StackTypes EMPTY = new StackTypes(); 12 | 13 | public StackTypes(StackType... stackTypes) { 14 | super(Arrays.asList(stackTypes)); 15 | } 16 | 17 | public StackTypes(List stackTypes) { 18 | super(stackTypes); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/bytecode/analysis/types/WildcardType.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.bytecode.analysis.types; 2 | 3 | public enum WildcardType { 4 | NONE(""), 5 | SUPER("super"), 6 | EXTENDS("extends"); 7 | 8 | private final String name; 9 | 10 | WildcardType(String name) { 11 | this.name = name; 12 | } 13 | 14 | 15 | @Override 16 | public String toString() { 17 | return name; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/bytecode/analysis/types/annotated/JavaAnnotatedTypeInstance.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.bytecode.analysis.types.annotated; 2 | 3 | import org.benf.cfr.reader.bytecode.analysis.types.JavaAnnotatedTypeIterator; 4 | import org.benf.cfr.reader.util.output.Dumpable; 5 | 6 | public interface JavaAnnotatedTypeInstance extends Dumpable { 7 | JavaAnnotatedTypeIterator pathIterator(); 8 | } 9 | -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/bytecode/analysis/types/discovery/CastAction.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.bytecode.analysis.types.discovery; 2 | 3 | import org.benf.cfr.reader.bytecode.analysis.loc.BytecodeLoc; 4 | import org.benf.cfr.reader.bytecode.analysis.parse.Expression; 5 | import org.benf.cfr.reader.bytecode.analysis.parse.expression.CastExpression; 6 | import org.benf.cfr.reader.bytecode.analysis.types.RawJavaType; 7 | 8 | public enum CastAction { 9 | None { 10 | public Expression performCastAction(Expression orig, InferredJavaType tgtType) { 11 | return orig; 12 | } 13 | }, 14 | InsertExplicit { 15 | public Expression performCastAction(Expression orig, InferredJavaType tgtType) { 16 | if (tgtType.getJavaTypeInstance() == RawJavaType.BOOLEAN) return orig; 17 | return new CastExpression(BytecodeLoc.NONE, tgtType, orig); 18 | } 19 | }; 20 | 21 | public abstract Expression performCastAction(Expression orig, InferredJavaType tgtType); 22 | } 23 | -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/bytecode/analysis/variables/Ident.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.bytecode.analysis.variables; 2 | 3 | public class Ident { 4 | private final int stackpos; 5 | private final int idx; 6 | 7 | public Ident(int stackpos, int idx) { 8 | this.stackpos = stackpos; 9 | this.idx = idx; 10 | } 11 | 12 | @Override 13 | public String toString() { 14 | if (idx == 0) return "" + stackpos; 15 | return "" + stackpos + "_" + idx; 16 | } 17 | 18 | @Override 19 | public boolean equals(Object o) { 20 | if (this == o) return true; 21 | if (o == null || getClass() != o.getClass()) return false; 22 | 23 | Ident ident = (Ident) o; 24 | 25 | if (idx != ident.idx) return false; 26 | if (stackpos != ident.stackpos) return false; 27 | 28 | return true; 29 | } 30 | 31 | public int getIdx() { 32 | return idx; 33 | } 34 | 35 | @Override 36 | public int hashCode() { 37 | int result = stackpos; 38 | result = 31 * result + idx; 39 | return result; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/bytecode/analysis/variables/NamedVariable.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.bytecode.analysis.variables; 2 | 3 | import org.benf.cfr.reader.util.output.Dumpable; 4 | import org.benf.cfr.reader.util.output.Dumper; 5 | 6 | public interface NamedVariable extends Dumpable { 7 | void forceName(String name); 8 | 9 | String getStringName(); 10 | 11 | boolean isGoodName(); 12 | 13 | @Override 14 | Dumper dump(Dumper d); 15 | 16 | Dumper dump(Dumper d, boolean defines); 17 | } 18 | -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/bytecode/analysis/variables/Slot.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.bytecode.analysis.variables; 2 | 3 | import org.benf.cfr.reader.bytecode.analysis.types.JavaTypeInstance; 4 | 5 | public class Slot { 6 | private final JavaTypeInstance javaTypeInstance; 7 | private final int idx; 8 | 9 | public Slot(JavaTypeInstance javaTypeInstance, int idx) { 10 | this.javaTypeInstance = javaTypeInstance; 11 | this.idx = idx; 12 | } 13 | 14 | @Override 15 | public boolean equals(Object o) { 16 | if (this == o) return true; 17 | if (o == null || getClass() != o.getClass()) return false; 18 | 19 | Slot slot = (Slot) o; 20 | 21 | if (idx != slot.idx) return false; 22 | 23 | return true; 24 | } 25 | 26 | public int getIdx() { 27 | return idx; 28 | } 29 | 30 | public JavaTypeInstance getJavaTypeInstance() { 31 | return javaTypeInstance; 32 | } 33 | 34 | @Override 35 | public String toString() { 36 | return "S{" + 37 | idx + 38 | '}'; 39 | } 40 | 41 | @Override 42 | public int hashCode() { 43 | return idx; 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/bytecode/analysis/variables/VariableNamer.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.bytecode.analysis.variables; 2 | 3 | import java.util.List; 4 | 5 | public interface VariableNamer { 6 | NamedVariable getName(int originalRawOffset, Ident ident, long stackPosition, boolean clashed); 7 | 8 | List getNamedVariables(); 9 | 10 | void mutatingRenameUnClash(NamedVariable toRename); 11 | 12 | void forceName(Ident ident, long stackPosition, String name); 13 | } 14 | -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/bytecode/analysis/variables/VariableNamerFactory.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.bytecode.analysis.variables; 2 | 3 | import org.benf.cfr.reader.entities.constantpool.ConstantPool; 4 | import org.benf.cfr.reader.entities.attributes.AttributeLocalVariableTable; 5 | 6 | public class VariableNamerFactory { 7 | public static VariableNamer getNamer(AttributeLocalVariableTable source, ConstantPool cp) { 8 | if (source == null) return new VariableNamerDefault(); 9 | return new VariableNamerHinted(source.getLocalVariableEntryList(), cp); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/bytecode/opcode/DecodedSwitch.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.bytecode.opcode; 2 | 3 | import java.util.List; 4 | 5 | public interface DecodedSwitch { 6 | 7 | List getJumpTargets(); 8 | } 9 | -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/bytecode/opcode/DecodedSwitchEntry.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.bytecode.opcode; 2 | 3 | import org.benf.cfr.reader.util.StringUtils; 4 | 5 | import java.util.List; 6 | 7 | public class DecodedSwitchEntry { 8 | private final List value; 9 | // TODO : Not useful past 0p01->Op02 stage. Create a different interface. 10 | private final int bytecodeTarget; 11 | 12 | public DecodedSwitchEntry(List value, int bytecodeTarget) { 13 | this.bytecodeTarget = bytecodeTarget; 14 | this.value = value; 15 | } 16 | 17 | public List getValue() { 18 | return value; 19 | } 20 | 21 | int getBytecodeTarget() { 22 | return bytecodeTarget; 23 | } 24 | 25 | @Override 26 | public String toString() { 27 | StringBuilder sb = new StringBuilder(); 28 | boolean first = true; 29 | sb.append("case "); 30 | for (Integer val : value) { 31 | first = StringUtils.comma(first, sb); 32 | sb.append(val == null ? "default" : val); 33 | } 34 | sb.append(" -> ").append(bytecodeTarget); 35 | return sb.toString(); 36 | } 37 | 38 | public boolean hasDefault() { 39 | return value.contains(null); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/bytecode/opcode/OperationFactory.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.bytecode.opcode; 2 | 3 | import org.benf.cfr.reader.bytecode.analysis.opgraph.Op01WithProcessedDataAndByteJumps; 4 | import org.benf.cfr.reader.bytecode.analysis.stack.StackDelta; 5 | import org.benf.cfr.reader.bytecode.analysis.stack.StackSim; 6 | import org.benf.cfr.reader.entities.constantpool.ConstantPool; 7 | import org.benf.cfr.reader.entities.constantpool.ConstantPoolEntry; 8 | import org.benf.cfr.reader.entities.Method; 9 | import org.benf.cfr.reader.util.bytestream.ByteData; 10 | 11 | public interface OperationFactory { 12 | /* 13 | * When an operation is being decoded, it may need to know about the method / class it's in 14 | * (eg invokedynamic); 15 | */ 16 | StackDelta getStackDelta(JVMInstr instr, byte[] data, ConstantPoolEntry[] cpEntries, 17 | StackSim stackSim, Method method); 18 | 19 | Op01WithProcessedDataAndByteJumps createOperation(JVMInstr instr, ByteData bd, ConstantPool cp, int offset); 20 | } 21 | -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/bytecode/opcode/OperationFactoryCPEntry.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.bytecode.opcode; 2 | 3 | import org.benf.cfr.reader.bytecode.analysis.opgraph.Op01WithProcessedDataAndByteJumps; 4 | import org.benf.cfr.reader.entities.constantpool.ConstantPool; 5 | import org.benf.cfr.reader.entities.constantpool.ConstantPoolEntry; 6 | import org.benf.cfr.reader.util.bytestream.ByteData; 7 | 8 | public class OperationFactoryCPEntry extends OperationFactoryDefault { 9 | private static final int LENGTH_OF_FIELD_INDEX = 1; 10 | 11 | @Override 12 | public Op01WithProcessedDataAndByteJumps createOperation(JVMInstr instr, ByteData bd, ConstantPool cp, int offset) { 13 | byte[] args = bd.getBytesAt(LENGTH_OF_FIELD_INDEX, 1); 14 | ConstantPoolEntry[] cpEntries = new ConstantPoolEntry[]{cp.getEntry(bd.getU1At(1))}; 15 | return new Op01WithProcessedDataAndByteJumps(instr, args, null, offset, cpEntries); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/bytecode/opcode/OperationFactoryCPEntryW.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.bytecode.opcode; 2 | 3 | import org.benf.cfr.reader.bytecode.analysis.opgraph.Op01WithProcessedDataAndByteJumps; 4 | import org.benf.cfr.reader.entities.constantpool.ConstantPool; 5 | import org.benf.cfr.reader.entities.constantpool.ConstantPoolEntry; 6 | import org.benf.cfr.reader.util.bytestream.ByteData; 7 | 8 | public class OperationFactoryCPEntryW extends OperationFactoryDefault { 9 | private static final int LENGTH_OF_FIELD_INDEX = 2; 10 | 11 | @Override 12 | public Op01WithProcessedDataAndByteJumps createOperation(JVMInstr instr, ByteData bd, ConstantPool cp, int offset) { 13 | byte[] args = bd.getBytesAt(LENGTH_OF_FIELD_INDEX, 1); 14 | ConstantPoolEntry[] cpEntries = new ConstantPoolEntry[]{cp.getEntry(bd.getU2At(1))}; 15 | return new Op01WithProcessedDataAndByteJumps(instr, args, null, offset, cpEntries); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/bytecode/opcode/OperationFactoryConditionalJump.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.bytecode.opcode; 2 | 3 | import org.benf.cfr.reader.bytecode.analysis.opgraph.Op01WithProcessedDataAndByteJumps; 4 | import org.benf.cfr.reader.entities.constantpool.ConstantPool; 5 | import org.benf.cfr.reader.util.bytestream.ByteData; 6 | 7 | public class OperationFactoryConditionalJump extends OperationFactoryDefault { 8 | 9 | private static final long OFFSET_OF_TARGET = 1; 10 | 11 | @Override 12 | public Op01WithProcessedDataAndByteJumps createOperation(JVMInstr instr, ByteData bd, ConstantPool cp, int offset) { 13 | byte[] args = bd.getBytesAt(instr.getRawLength(), 1); 14 | 15 | short targetOffset = bd.getS2At(OFFSET_OF_TARGET); 16 | 17 | int[] targetOffsets = new int[2]; // next instr is either successor, or targetOffset. 18 | targetOffsets[1] = targetOffset; 19 | targetOffsets[0] = instr.getRawLength() + 1; 20 | 21 | return new Op01WithProcessedDataAndByteJumps(instr, args, targetOffsets, offset); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/bytecode/opcode/OperationFactoryDup.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.bytecode.opcode; 2 | 3 | import org.benf.cfr.reader.bytecode.analysis.opgraph.Op01WithProcessedDataAndByteJumps; 4 | import org.benf.cfr.reader.bytecode.analysis.stack.StackDelta; 5 | import org.benf.cfr.reader.bytecode.analysis.stack.StackDeltaImpl; 6 | import org.benf.cfr.reader.bytecode.analysis.stack.StackSim; 7 | import org.benf.cfr.reader.bytecode.analysis.types.StackTypes; 8 | import org.benf.cfr.reader.entities.constantpool.ConstantPool; 9 | import org.benf.cfr.reader.entities.constantpool.ConstantPoolEntry; 10 | import org.benf.cfr.reader.entities.Method; 11 | import org.benf.cfr.reader.util.bytestream.ByteData; 12 | 13 | public class OperationFactoryDup extends OperationFactoryDupBase { 14 | 15 | @Override 16 | public StackDelta getStackDelta(JVMInstr instr, byte[] data, ConstantPoolEntry[] cpEntries, 17 | StackSim stackSim, Method method) { 18 | StackTypes popped = getStackTypes(stackSim, 0); 19 | StackTypes pushed = getStackTypes(stackSim, 0, 0); 20 | return new StackDeltaImpl(popped, pushed); 21 | } 22 | 23 | @Override 24 | public Op01WithProcessedDataAndByteJumps createOperation(JVMInstr instr, ByteData bd, ConstantPool cp, int offset) { 25 | return new Op01WithProcessedDataAndByteJumps(instr, null, null, offset); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/bytecode/opcode/OperationFactoryDupBase.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.bytecode.opcode; 2 | 3 | public abstract class OperationFactoryDupBase extends OperationFactoryDefault { 4 | } 5 | -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/bytecode/opcode/OperationFactoryDupX1.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.bytecode.opcode; 2 | 3 | import org.benf.cfr.reader.bytecode.analysis.opgraph.Op01WithProcessedDataAndByteJumps; 4 | import org.benf.cfr.reader.bytecode.analysis.stack.StackDelta; 5 | import org.benf.cfr.reader.bytecode.analysis.stack.StackDeltaImpl; 6 | import org.benf.cfr.reader.bytecode.analysis.stack.StackSim; 7 | import org.benf.cfr.reader.entities.constantpool.ConstantPool; 8 | import org.benf.cfr.reader.entities.constantpool.ConstantPoolEntry; 9 | import org.benf.cfr.reader.entities.Method; 10 | import org.benf.cfr.reader.util.bytestream.ByteData; 11 | 12 | public class OperationFactoryDupX1 extends OperationFactoryDupBase { 13 | 14 | @Override 15 | public StackDelta getStackDelta(JVMInstr instr, byte[] data, ConstantPoolEntry[] cpEntries, 16 | StackSim stackSim, Method method) { 17 | checkCat(stackSim, 0, 1); 18 | checkCat(stackSim, 1, 1); 19 | return new StackDeltaImpl( 20 | getStackTypes(stackSim, 0, 1), 21 | getStackTypes(stackSim, 0, 1, 0) 22 | ); 23 | } 24 | 25 | @Override 26 | public Op01WithProcessedDataAndByteJumps createOperation(JVMInstr instr, ByteData bd, ConstantPool cp, int offset) { 27 | return new Op01WithProcessedDataAndByteJumps(instr, null, null, offset); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/bytecode/opcode/OperationFactoryGetField.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.bytecode.opcode; 2 | 3 | import org.benf.cfr.reader.bytecode.analysis.stack.StackDelta; 4 | import org.benf.cfr.reader.bytecode.analysis.stack.StackDeltaImpl; 5 | import org.benf.cfr.reader.bytecode.analysis.stack.StackSim; 6 | import org.benf.cfr.reader.bytecode.analysis.types.StackType; 7 | import org.benf.cfr.reader.entities.constantpool.ConstantPoolEntry; 8 | import org.benf.cfr.reader.entities.constantpool.ConstantPoolEntryFieldRef; 9 | import org.benf.cfr.reader.entities.Method; 10 | import org.benf.cfr.reader.util.ConfusedCFRException; 11 | 12 | public class OperationFactoryGetField extends OperationFactoryCPEntryW { 13 | 14 | @Override 15 | public StackDelta getStackDelta(JVMInstr instr, byte[] data, ConstantPoolEntry[] cpEntries, 16 | StackSim stackSim, Method method) { 17 | ConstantPoolEntryFieldRef fieldRef = (ConstantPoolEntryFieldRef) cpEntries[0]; 18 | if (fieldRef == null) throw new ConfusedCFRException("Expecting fieldRef"); 19 | StackType stackType = fieldRef.getStackType(); 20 | return new StackDeltaImpl(StackType.REF.asList(), stackType.asList()); 21 | } 22 | 23 | } 24 | -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/bytecode/opcode/OperationFactoryGetStatic.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.bytecode.opcode; 2 | 3 | import org.benf.cfr.reader.bytecode.analysis.stack.StackDelta; 4 | import org.benf.cfr.reader.bytecode.analysis.stack.StackDeltaImpl; 5 | import org.benf.cfr.reader.bytecode.analysis.stack.StackSim; 6 | import org.benf.cfr.reader.bytecode.analysis.types.StackType; 7 | import org.benf.cfr.reader.bytecode.analysis.types.StackTypes; 8 | import org.benf.cfr.reader.entities.constantpool.ConstantPoolEntry; 9 | import org.benf.cfr.reader.entities.constantpool.ConstantPoolEntryFieldRef; 10 | import org.benf.cfr.reader.entities.Method; 11 | import org.benf.cfr.reader.util.ConfusedCFRException; 12 | 13 | public class OperationFactoryGetStatic extends OperationFactoryCPEntryW { 14 | 15 | @Override 16 | public StackDelta getStackDelta(JVMInstr instr, byte[] data, ConstantPoolEntry[] cpEntries, 17 | StackSim stackSim, Method method) { 18 | ConstantPoolEntryFieldRef fieldRef = (ConstantPoolEntryFieldRef) cpEntries[0]; 19 | if (fieldRef == null) throw new ConfusedCFRException("Expecting fieldRef"); 20 | StackType stackType = fieldRef.getStackType(); 21 | return new StackDeltaImpl(StackTypes.EMPTY, stackType.asList()); 22 | } 23 | 24 | } 25 | -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/bytecode/opcode/OperationFactoryGoto.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.bytecode.opcode; 2 | 3 | import org.benf.cfr.reader.bytecode.analysis.opgraph.Op01WithProcessedDataAndByteJumps; 4 | import org.benf.cfr.reader.entities.constantpool.ConstantPool; 5 | import org.benf.cfr.reader.util.bytestream.ByteData; 6 | 7 | public class OperationFactoryGoto extends OperationFactoryDefault { 8 | 9 | private static final long OFFSET_OF_TARGET = 1; 10 | 11 | 12 | @Override 13 | public Op01WithProcessedDataAndByteJumps createOperation(JVMInstr instr, ByteData bd, ConstantPool cp, int offset) { 14 | byte[] args = bd.getBytesAt(instr.getRawLength(), 1); 15 | 16 | short targetOffset = bd.getS2At(OFFSET_OF_TARGET); 17 | 18 | int[] targetOffsets = new int[1]; 19 | targetOffsets[0] = targetOffset; 20 | 21 | return new Op01WithProcessedDataAndByteJumps(instr, args, targetOffsets, offset); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/bytecode/opcode/OperationFactoryGotoW.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.bytecode.opcode; 2 | 3 | import org.benf.cfr.reader.bytecode.analysis.opgraph.Op01WithProcessedDataAndByteJumps; 4 | import org.benf.cfr.reader.entities.constantpool.ConstantPool; 5 | import org.benf.cfr.reader.util.bytestream.ByteData; 6 | 7 | public class OperationFactoryGotoW extends OperationFactoryDefault { 8 | 9 | private static final long OFFSET_OF_TARGET = 1; 10 | 11 | @Override 12 | public Op01WithProcessedDataAndByteJumps createOperation(JVMInstr instr, ByteData bd, ConstantPool cp, int offset) { 13 | byte[] args = bd.getBytesAt(instr.getRawLength(), 1); 14 | 15 | int targetOffset = bd.getS4At(OFFSET_OF_TARGET); 16 | 17 | int[] targetOffsets = new int[1]; 18 | targetOffsets[0] = targetOffset; 19 | 20 | return new Op01WithProcessedDataAndByteJumps(instr, args, targetOffsets, offset); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/bytecode/opcode/OperationFactoryLDC2W.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.bytecode.opcode; 2 | 3 | public class OperationFactoryLDC2W extends OperationFactoryLDCW { 4 | @Override 5 | protected int getRequiredComputationCategory() { 6 | return 2; 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/bytecode/opcode/OperationFactoryLDCW.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.bytecode.opcode; 2 | 3 | import org.benf.cfr.reader.bytecode.analysis.stack.StackDelta; 4 | import org.benf.cfr.reader.bytecode.analysis.stack.StackDeltaImpl; 5 | import org.benf.cfr.reader.bytecode.analysis.stack.StackSim; 6 | import org.benf.cfr.reader.bytecode.analysis.types.StackType; 7 | import org.benf.cfr.reader.bytecode.analysis.types.StackTypes; 8 | import org.benf.cfr.reader.entities.constantpool.ConstantPoolEntry; 9 | import org.benf.cfr.reader.entities.Method; 10 | import org.benf.cfr.reader.util.ConfusedCFRException; 11 | 12 | public class OperationFactoryLDCW extends OperationFactoryCPEntryW { 13 | 14 | @Override 15 | public StackDelta getStackDelta(JVMInstr instr, byte[] data, ConstantPoolEntry[] cpEntries, 16 | StackSim stackSim, Method method) { 17 | StackType stackType = OperationFactoryLDC.getStackType(cpEntries[0]); 18 | int requiredComputationCategory = getRequiredComputationCategory(); 19 | if (stackType.getComputationCategory() != requiredComputationCategory) { 20 | throw new ConfusedCFRException("Got a literal, but expected a different category"); 21 | } 22 | 23 | return new StackDeltaImpl(StackTypes.EMPTY, stackType.asList()); 24 | } 25 | 26 | protected int getRequiredComputationCategory() { 27 | return 1; 28 | } 29 | 30 | } 31 | -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/bytecode/opcode/OperationFactoryNew.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.bytecode.opcode; 2 | 3 | import org.benf.cfr.reader.bytecode.analysis.opgraph.Op01WithProcessedDataAndByteJumps; 4 | import org.benf.cfr.reader.entities.constantpool.ConstantPool; 5 | import org.benf.cfr.reader.entities.constantpool.ConstantPoolEntry; 6 | import org.benf.cfr.reader.util.bytestream.ByteData; 7 | 8 | public class OperationFactoryNew extends OperationFactoryDefault { 9 | private static final int LENGTH_OF_CLASS_INDEX = 2; 10 | 11 | @Override 12 | public Op01WithProcessedDataAndByteJumps createOperation(JVMInstr instr, ByteData bd, ConstantPool cp, int offset) { 13 | byte[] args = bd.getBytesAt(LENGTH_OF_CLASS_INDEX, 1); 14 | ConstantPoolEntry[] cpEntries = new ConstantPoolEntry[]{cp.getEntry(bd.getU2At(1))}; 15 | return new Op01WithProcessedDataAndByteJumps(instr, args, null, offset, cpEntries); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/bytecode/opcode/OperationFactoryPutField.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.bytecode.opcode; 2 | 3 | import org.benf.cfr.reader.bytecode.analysis.stack.StackDelta; 4 | import org.benf.cfr.reader.bytecode.analysis.stack.StackDeltaImpl; 5 | import org.benf.cfr.reader.bytecode.analysis.stack.StackSim; 6 | import org.benf.cfr.reader.bytecode.analysis.types.StackType; 7 | import org.benf.cfr.reader.bytecode.analysis.types.StackTypes; 8 | import org.benf.cfr.reader.entities.constantpool.ConstantPoolEntry; 9 | import org.benf.cfr.reader.entities.constantpool.ConstantPoolEntryFieldRef; 10 | import org.benf.cfr.reader.entities.Method; 11 | import org.benf.cfr.reader.util.ConfusedCFRException; 12 | 13 | public class OperationFactoryPutField extends OperationFactoryCPEntryW { 14 | 15 | @Override 16 | public StackDelta getStackDelta(JVMInstr instr, byte[] data, ConstantPoolEntry[] cpEntries, 17 | StackSim stackSim, Method method) { 18 | ConstantPoolEntryFieldRef fieldRef = (ConstantPoolEntryFieldRef) cpEntries[0]; 19 | if (fieldRef == null) throw new ConfusedCFRException("Expecting fieldRef"); 20 | StackType stackType = fieldRef.getStackType(); 21 | return new StackDeltaImpl(new StackTypes(StackType.REF, stackType), StackTypes.EMPTY); 22 | } 23 | 24 | } 25 | -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/bytecode/opcode/OperationFactoryPutStatic.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.bytecode.opcode; 2 | 3 | import org.benf.cfr.reader.bytecode.analysis.stack.StackDelta; 4 | import org.benf.cfr.reader.bytecode.analysis.stack.StackDeltaImpl; 5 | import org.benf.cfr.reader.bytecode.analysis.stack.StackSim; 6 | import org.benf.cfr.reader.bytecode.analysis.types.StackType; 7 | import org.benf.cfr.reader.bytecode.analysis.types.StackTypes; 8 | import org.benf.cfr.reader.entities.constantpool.ConstantPoolEntry; 9 | import org.benf.cfr.reader.entities.constantpool.ConstantPoolEntryFieldRef; 10 | import org.benf.cfr.reader.entities.Method; 11 | import org.benf.cfr.reader.util.ConfusedCFRException; 12 | 13 | public class OperationFactoryPutStatic extends OperationFactoryCPEntryW { 14 | 15 | @Override 16 | public StackDelta getStackDelta(JVMInstr instr, byte[] data, ConstantPoolEntry[] cpEntries, 17 | StackSim stackSim, Method method) { 18 | ConstantPoolEntryFieldRef fieldRef = (ConstantPoolEntryFieldRef) cpEntries[0]; 19 | if (fieldRef == null) throw new ConfusedCFRException("Expecting fieldRef"); 20 | StackType stackType = fieldRef.getStackType(); 21 | return new StackDeltaImpl(stackType.asList(), StackTypes.EMPTY); 22 | } 23 | 24 | } 25 | -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/bytecode/opcode/OperationFactoryReturn.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.bytecode.opcode; 2 | 3 | import org.benf.cfr.reader.bytecode.analysis.opgraph.Op01WithProcessedDataAndByteJumps; 4 | import org.benf.cfr.reader.entities.constantpool.ConstantPool; 5 | import org.benf.cfr.reader.util.bytestream.ByteData; 6 | 7 | public class OperationFactoryReturn extends OperationFactoryDefault { 8 | 9 | @Override 10 | public Op01WithProcessedDataAndByteJumps createOperation(JVMInstr instr, ByteData bd, ConstantPool cp, int offset) { 11 | byte[] args = instr.getRawLength() == 0 ? null : bd.getBytesAt(instr.getRawLength(), 1); 12 | int[] targetOffsets = new int[0]; // There are no targets. 13 | return new Op01WithProcessedDataAndByteJumps(instr, args, targetOffsets, offset); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/bytecode/opcode/OperationFactorySwap.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.bytecode.opcode; 2 | 3 | import org.benf.cfr.reader.bytecode.analysis.opgraph.Op01WithProcessedDataAndByteJumps; 4 | import org.benf.cfr.reader.bytecode.analysis.stack.StackDelta; 5 | import org.benf.cfr.reader.bytecode.analysis.stack.StackDeltaImpl; 6 | import org.benf.cfr.reader.bytecode.analysis.stack.StackSim; 7 | import org.benf.cfr.reader.bytecode.analysis.types.StackTypes; 8 | import org.benf.cfr.reader.entities.constantpool.ConstantPool; 9 | import org.benf.cfr.reader.entities.constantpool.ConstantPoolEntry; 10 | import org.benf.cfr.reader.entities.Method; 11 | import org.benf.cfr.reader.util.bytestream.ByteData; 12 | 13 | public class OperationFactorySwap extends OperationFactoryDefault { 14 | 15 | @Override 16 | public StackDelta getStackDelta(JVMInstr instr, byte[] data, ConstantPoolEntry[] cpEntries, 17 | StackSim stackSim, Method method) { 18 | StackTypes popped = getStackTypes(stackSim, 0, 1); 19 | StackTypes pushed = getStackTypes(stackSim, 1, 0); 20 | return new StackDeltaImpl(popped, pushed); 21 | } 22 | 23 | @Override 24 | public Op01WithProcessedDataAndByteJumps createOperation(JVMInstr instr, ByteData bd, ConstantPool cp, int offset) { 25 | return new Op01WithProcessedDataAndByteJumps(instr, null, null, offset); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/bytecode/opcode/OperationFactoryThrow.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.bytecode.opcode; 2 | 3 | import org.benf.cfr.reader.bytecode.analysis.opgraph.Op01WithProcessedDataAndByteJumps; 4 | import org.benf.cfr.reader.entities.constantpool.ConstantPool; 5 | import org.benf.cfr.reader.util.bytestream.ByteData; 6 | 7 | public class OperationFactoryThrow extends OperationFactoryDefault { 8 | 9 | @Override 10 | public Op01WithProcessedDataAndByteJumps createOperation(JVMInstr instr, ByteData bd, ConstantPool cp, int offset) { 11 | byte[] args = instr.getRawLength() == 0 ? null : bd.getBytesAt(instr.getRawLength(), 1); 12 | int[] targetOffsets = new int[0]; // There are no targets. 13 | return new Op01WithProcessedDataAndByteJumps(instr, args, targetOffsets, offset); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/entities/AbstractConstantPoolEntry.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.entities; 2 | 3 | import org.benf.cfr.reader.entities.constantpool.ConstantPool; 4 | import org.benf.cfr.reader.entities.constantpool.ConstantPoolEntry; 5 | 6 | public abstract class AbstractConstantPoolEntry implements ConstantPoolEntry { 7 | private final ConstantPool cp; 8 | 9 | protected AbstractConstantPoolEntry(ConstantPool cp) { 10 | this.cp = cp; 11 | } 12 | 13 | protected ConstantPool getCp() { 14 | if (!cp.isLoaded()) { 15 | throw new IllegalStateException("Attempt to use constant pool before it's fully loaded."); 16 | } 17 | return cp; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/entities/annotations/AnnotationTableTypeEntry.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.entities.annotations; 2 | 3 | import org.benf.cfr.reader.bytecode.analysis.types.JavaTypeInstance; 4 | import org.benf.cfr.reader.entities.attributes.TypeAnnotationEntryKind; 5 | import org.benf.cfr.reader.entities.attributes.TypeAnnotationEntryValue; 6 | import org.benf.cfr.reader.entities.attributes.TypeAnnotationTargetInfo; 7 | import org.benf.cfr.reader.entities.attributes.TypePath; 8 | 9 | import java.util.Map; 10 | 11 | public class AnnotationTableTypeEntry extends AnnotationTableEntry { 12 | private final TypeAnnotationEntryValue value; 13 | private final T targetInfo; 14 | private final TypePath typePath; 15 | 16 | public AnnotationTableTypeEntry(TypeAnnotationEntryValue value, T targetInfo, TypePath typePath, JavaTypeInstance type, Map elementValueMap) { 17 | super(type, elementValueMap); 18 | this.value = value; 19 | this.targetInfo = targetInfo; 20 | this.typePath = typePath; 21 | } 22 | 23 | public TypePath getTypePath() { 24 | return typePath; 25 | } 26 | 27 | public TypeAnnotationEntryValue getValue() { return value; } 28 | 29 | public TypeAnnotationEntryKind getKind() { 30 | return value.getKind(); 31 | } 32 | 33 | public T getTargetInfo() { 34 | return targetInfo; 35 | } 36 | } -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/entities/annotations/ElementValue.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.entities.annotations; 2 | 3 | import org.benf.cfr.reader.bytecode.analysis.types.JavaTypeInstance; 4 | import org.benf.cfr.reader.util.TypeUsageCollectable; 5 | import org.benf.cfr.reader.util.output.Dumpable; 6 | 7 | public interface ElementValue extends Dumpable, TypeUsageCollectable { 8 | ElementValue withTypeHint(JavaTypeInstance hint); 9 | } 10 | -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/entities/annotations/ElementValueAnnotation.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.entities.annotations; 2 | 3 | import org.benf.cfr.reader.bytecode.analysis.types.JavaTypeInstance; 4 | import org.benf.cfr.reader.state.TypeUsageCollector; 5 | import org.benf.cfr.reader.util.output.Dumper; 6 | 7 | public class ElementValueAnnotation implements ElementValue { 8 | private final AnnotationTableEntry annotationTableEntry; 9 | 10 | public ElementValueAnnotation(AnnotationTableEntry annotationTableEntry) { 11 | this.annotationTableEntry = annotationTableEntry; 12 | } 13 | 14 | @Override 15 | public Dumper dump(Dumper d) { 16 | return annotationTableEntry.dump(d); 17 | } 18 | 19 | @Override 20 | public void collectTypeUsages(TypeUsageCollector collector) { 21 | annotationTableEntry.collectTypeUsages(collector); 22 | } 23 | 24 | @Override 25 | public ElementValue withTypeHint(JavaTypeInstance hint) { 26 | return this; 27 | } 28 | 29 | @Override 30 | public boolean equals(Object obj) { 31 | if (obj == this) { 32 | return true; 33 | } 34 | else if (obj instanceof ElementValueAnnotation) { 35 | ElementValueAnnotation other = (ElementValueAnnotation) obj; 36 | return annotationTableEntry.equals(other.annotationTableEntry); 37 | } 38 | else { 39 | return false; 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/entities/annotations/ElementValueClass.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.entities.annotations; 2 | 3 | import org.benf.cfr.reader.bytecode.analysis.types.JavaTypeInstance; 4 | import org.benf.cfr.reader.state.TypeUsageCollector; 5 | import org.benf.cfr.reader.util.output.Dumper; 6 | 7 | public class ElementValueClass implements ElementValue { 8 | private final JavaTypeInstance classType; 9 | 10 | public ElementValueClass(JavaTypeInstance classType) { 11 | this.classType = classType; 12 | } 13 | 14 | @Override 15 | public Dumper dump(Dumper d) { 16 | return d.dump(classType).print(".class"); 17 | } 18 | 19 | @Override 20 | public void collectTypeUsages(TypeUsageCollector collector) { 21 | collector.collect(classType); 22 | } 23 | 24 | @Override 25 | public ElementValue withTypeHint(JavaTypeInstance hint) { 26 | return this; 27 | } 28 | 29 | @Override 30 | public boolean equals(Object obj) { 31 | if (obj == this) { 32 | return true; 33 | } 34 | else if (obj instanceof ElementValueClass) { 35 | ElementValueClass other = (ElementValueClass) obj; 36 | return classType.equals(other.classType); 37 | } 38 | else { 39 | return false; 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/entities/annotations/ElementValueEnum.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.entities.annotations; 2 | 3 | import org.benf.cfr.reader.bytecode.analysis.types.JavaTypeInstance; 4 | import org.benf.cfr.reader.state.TypeUsageCollector; 5 | import org.benf.cfr.reader.util.output.Dumper; 6 | 7 | public class ElementValueEnum implements ElementValue { 8 | private final JavaTypeInstance type; 9 | private final String valueName; 10 | 11 | public ElementValueEnum(JavaTypeInstance type, String valueName) { 12 | this.type = type; 13 | this.valueName = valueName; 14 | } 15 | 16 | @Override 17 | public Dumper dump(Dumper d) { 18 | return d.dump(type).print('.').print(valueName); 19 | } 20 | 21 | @Override 22 | public void collectTypeUsages(TypeUsageCollector collector) { 23 | collector.collect(type); 24 | } 25 | 26 | @Override 27 | public ElementValue withTypeHint(JavaTypeInstance hint) { 28 | return this; 29 | } 30 | 31 | @Override 32 | public boolean equals(Object obj) { 33 | if (obj == this) { 34 | return true; 35 | } 36 | else if (obj instanceof ElementValueEnum) { 37 | ElementValueEnum other = (ElementValueEnum) obj; 38 | return type.equals(other.type) && valueName.equals(other.valueName); 39 | } 40 | else { 41 | return false; 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/entities/attributes/Attribute.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.entities.attributes; 2 | 3 | import org.benf.cfr.reader.state.TypeUsageCollector; 4 | import org.benf.cfr.reader.util.KnowsRawName; 5 | import org.benf.cfr.reader.util.KnowsRawSize; 6 | import org.benf.cfr.reader.util.TypeUsageCollectable; 7 | import org.benf.cfr.reader.util.output.Dumpable; 8 | import org.benf.cfr.reader.util.output.Dumper; 9 | 10 | public abstract class Attribute implements KnowsRawSize, KnowsRawName, Dumpable, TypeUsageCollectable { 11 | 12 | @Override 13 | public abstract Dumper dump(Dumper d); 14 | 15 | @Override 16 | public void collectTypeUsages(TypeUsageCollector collector) { 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/entities/attributes/AttributeDeprecated.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.entities.attributes; 2 | 3 | import org.benf.cfr.reader.util.bytestream.ByteData; 4 | import org.benf.cfr.reader.util.output.Dumper; 5 | 6 | public class AttributeDeprecated extends Attribute { 7 | public static final String ATTRIBUTE_NAME = "Deprecated"; 8 | 9 | private static final long OFFSET_OF_ATTRIBUTE_LENGTH = 2; 10 | private static final long OFFSET_OF_REMAINDER = 6; 11 | 12 | private final int length; 13 | 14 | public AttributeDeprecated(ByteData raw) { 15 | this.length = raw.getS4At(OFFSET_OF_ATTRIBUTE_LENGTH); 16 | } 17 | 18 | @Override 19 | public String getRawName() { 20 | return ATTRIBUTE_NAME; 21 | } 22 | 23 | @Override 24 | public Dumper dump(Dumper d) { 25 | return d.print("Deprecated"); 26 | } 27 | 28 | @Override 29 | public long getRawByteLength() { 30 | return OFFSET_OF_REMAINDER + length; 31 | } 32 | 33 | @Override 34 | public String toString() { 35 | return "Deprecated"; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/entities/attributes/AttributeLocalVariableTypeTable.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.entities.attributes; 2 | 3 | import org.benf.cfr.reader.util.bytestream.ByteData; 4 | import org.benf.cfr.reader.util.output.Dumper; 5 | 6 | public class AttributeLocalVariableTypeTable extends Attribute { 7 | public final static String ATTRIBUTE_NAME = "LocalVariableTypeTable"; 8 | 9 | private static final long OFFSET_OF_ATTRIBUTE_LENGTH = 2; 10 | private static final long OFFSET_OF_REMAINDER = 6; 11 | 12 | private final int length; 13 | 14 | public AttributeLocalVariableTypeTable(ByteData raw) { 15 | this.length = raw.getS4At(OFFSET_OF_ATTRIBUTE_LENGTH); 16 | } 17 | 18 | @Override 19 | public String getRawName() { 20 | return ATTRIBUTE_NAME; 21 | } 22 | 23 | @Override 24 | public Dumper dump(Dumper d) { 25 | return d; 26 | } 27 | 28 | @Override 29 | public long getRawByteLength() { 30 | return OFFSET_OF_REMAINDER + length; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/entities/attributes/AttributeModuleClassMain.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.entities.attributes; 2 | 3 | import org.benf.cfr.reader.util.bytestream.ByteData; 4 | import org.benf.cfr.reader.util.output.Dumper; 5 | 6 | public class AttributeModuleClassMain extends Attribute { 7 | public static final String ATTRIBUTE_NAME = "ModuleClassMain"; 8 | 9 | private static final long OFFSET_OF_ATTRIBUTE_LENGTH = 2; 10 | private static final long OFFSET_OF_REMAINDER = 6; 11 | 12 | private final int length; 13 | 14 | public AttributeModuleClassMain(ByteData raw) { 15 | this.length = raw.getS4At(OFFSET_OF_ATTRIBUTE_LENGTH); 16 | } 17 | 18 | @Override 19 | public String getRawName() { 20 | return ATTRIBUTE_NAME; 21 | } 22 | 23 | @Override 24 | public Dumper dump(Dumper d) { 25 | return d.print(ATTRIBUTE_NAME); 26 | } 27 | 28 | @Override 29 | public long getRawByteLength() { 30 | return OFFSET_OF_REMAINDER + length; 31 | } 32 | 33 | @Override 34 | public String toString() { 35 | return ATTRIBUTE_NAME; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/entities/attributes/AttributeModulePackages.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.entities.attributes; 2 | 3 | import org.benf.cfr.reader.util.bytestream.ByteData; 4 | import org.benf.cfr.reader.util.output.Dumper; 5 | 6 | public class AttributeModulePackages extends Attribute { 7 | public static final String ATTRIBUTE_NAME = "ModulePackages"; 8 | 9 | private static final long OFFSET_OF_ATTRIBUTE_LENGTH = 2; 10 | private static final long OFFSET_OF_REMAINDER = 6; 11 | 12 | private final int length; 13 | 14 | public AttributeModulePackages(ByteData raw) { 15 | this.length = raw.getS4At(OFFSET_OF_ATTRIBUTE_LENGTH); 16 | } 17 | 18 | @Override 19 | public String getRawName() { 20 | return ATTRIBUTE_NAME; 21 | } 22 | 23 | @Override 24 | public Dumper dump(Dumper d) { 25 | return d.print(ATTRIBUTE_NAME); 26 | } 27 | 28 | @Override 29 | public long getRawByteLength() { 30 | return OFFSET_OF_REMAINDER + length; 31 | } 32 | 33 | @Override 34 | public String toString() { 35 | return ATTRIBUTE_NAME; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/entities/attributes/AttributeRuntimeInvisibleAnnotations.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.entities.attributes; 2 | 3 | import org.benf.cfr.reader.entities.constantpool.ConstantPool; 4 | import org.benf.cfr.reader.util.bytestream.ByteData; 5 | 6 | public class AttributeRuntimeInvisibleAnnotations extends AttributeAnnotations { 7 | public static final String ATTRIBUTE_NAME = "RuntimeInvisibleAnnotations"; 8 | 9 | public AttributeRuntimeInvisibleAnnotations(ByteData raw, ConstantPool cp) { 10 | super(raw, cp); 11 | } 12 | 13 | @Override 14 | public String getRawName() { 15 | return ATTRIBUTE_NAME; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/entities/attributes/AttributeRuntimeInvisibleParameterAnnotations.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.entities.attributes; 2 | 3 | import org.benf.cfr.reader.entities.constantpool.ConstantPool; 4 | import org.benf.cfr.reader.util.bytestream.ByteData; 5 | 6 | public class AttributeRuntimeInvisibleParameterAnnotations extends AttributeParameterAnnotations { 7 | public static final String ATTRIBUTE_NAME = "RuntimeInvisibleParameterAnnotations"; 8 | 9 | public AttributeRuntimeInvisibleParameterAnnotations(ByteData raw, ConstantPool cp) { 10 | super(raw, cp); 11 | } 12 | 13 | @Override 14 | public String getRawName() { 15 | return ATTRIBUTE_NAME; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/entities/attributes/AttributeRuntimeInvisibleTypeAnnotations.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.entities.attributes; 2 | 3 | import org.benf.cfr.reader.entities.constantpool.ConstantPool; 4 | import org.benf.cfr.reader.util.bytestream.ByteData; 5 | 6 | public class AttributeRuntimeInvisibleTypeAnnotations extends AttributeTypeAnnotations { 7 | public static final String ATTRIBUTE_NAME = "RuntimeInvisibleTypeAnnotations"; 8 | 9 | public AttributeRuntimeInvisibleTypeAnnotations(ByteData raw, ConstantPool cp) { 10 | super(raw, cp); 11 | } 12 | 13 | @Override 14 | public String getRawName() { 15 | return ATTRIBUTE_NAME; 16 | } 17 | 18 | @Override 19 | public String toString() { 20 | return ATTRIBUTE_NAME; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/entities/attributes/AttributeRuntimeVisibleAnnotations.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.entities.attributes; 2 | 3 | import org.benf.cfr.reader.entities.constantpool.ConstantPool; 4 | import org.benf.cfr.reader.util.bytestream.ByteData; 5 | 6 | public class AttributeRuntimeVisibleAnnotations extends AttributeAnnotations { 7 | public static final String ATTRIBUTE_NAME = "RuntimeVisibleAnnotations"; 8 | 9 | public AttributeRuntimeVisibleAnnotations(ByteData raw, ConstantPool cp) { 10 | super(raw, cp); 11 | } 12 | 13 | @Override 14 | public String getRawName() { 15 | return ATTRIBUTE_NAME; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/entities/attributes/AttributeRuntimeVisibleParameterAnnotations.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.entities.attributes; 2 | 3 | import org.benf.cfr.reader.entities.constantpool.ConstantPool; 4 | import org.benf.cfr.reader.util.bytestream.ByteData; 5 | 6 | public class AttributeRuntimeVisibleParameterAnnotations extends AttributeParameterAnnotations { 7 | public static final String ATTRIBUTE_NAME = "RuntimeVisibleParameterAnnotations"; 8 | 9 | public AttributeRuntimeVisibleParameterAnnotations(ByteData raw, ConstantPool cp) { 10 | super(raw, cp); 11 | } 12 | 13 | @Override 14 | public String getRawName() { 15 | return ATTRIBUTE_NAME; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/entities/attributes/AttributeRuntimeVisibleTypeAnnotations.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.entities.attributes; 2 | 3 | import org.benf.cfr.reader.entities.constantpool.ConstantPool; 4 | import org.benf.cfr.reader.util.bytestream.ByteData; 5 | 6 | public class AttributeRuntimeVisibleTypeAnnotations extends AttributeTypeAnnotations { 7 | public static final String ATTRIBUTE_NAME = "RuntimeVisibleTypeAnnotations"; 8 | 9 | public AttributeRuntimeVisibleTypeAnnotations(ByteData raw, ConstantPool cp) { 10 | super(raw, cp); 11 | } 12 | 13 | @Override 14 | public String getRawName() { 15 | return ATTRIBUTE_NAME; 16 | } 17 | 18 | @Override 19 | public String toString() { 20 | return ATTRIBUTE_NAME; 21 | } 22 | 23 | } 24 | -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/entities/attributes/AttributeScala.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.entities.attributes; 2 | 3 | import org.benf.cfr.reader.util.bytestream.ByteData; 4 | import org.benf.cfr.reader.util.output.Dumper; 5 | 6 | public class AttributeScala extends Attribute { 7 | public final static String ATTRIBUTE_NAME = "Scala"; 8 | 9 | private static final long OFFSET_OF_ATTRIBUTE_LENGTH = 2; 10 | private static final long OFFSET_OF_REMAINDER = 6; 11 | 12 | private final int length; 13 | 14 | public AttributeScala(ByteData raw) { 15 | this.length = raw.getS4At(OFFSET_OF_ATTRIBUTE_LENGTH); 16 | } 17 | 18 | @Override 19 | public String getRawName() { 20 | return ATTRIBUTE_NAME; 21 | } 22 | 23 | @Override 24 | public Dumper dump(Dumper d) { 25 | return d; 26 | } 27 | 28 | @Override 29 | public long getRawByteLength() { 30 | return OFFSET_OF_REMAINDER + length; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/entities/attributes/AttributeScalaSig.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.entities.attributes; 2 | 3 | import org.benf.cfr.reader.util.bytestream.ByteData; 4 | import org.benf.cfr.reader.util.output.Dumper; 5 | 6 | public class AttributeScalaSig extends Attribute { 7 | public final static String ATTRIBUTE_NAME = "ScalaSig"; 8 | 9 | private static final long OFFSET_OF_ATTRIBUTE_LENGTH = 2; 10 | private static final long OFFSET_OF_REMAINDER = 6; 11 | 12 | private final int length; 13 | 14 | public AttributeScalaSig(ByteData raw) { 15 | this.length = raw.getS4At(OFFSET_OF_ATTRIBUTE_LENGTH); 16 | } 17 | 18 | @Override 19 | public String getRawName() { 20 | return ATTRIBUTE_NAME; 21 | } 22 | 23 | @Override 24 | public Dumper dump(Dumper d) { 25 | return d; 26 | } 27 | 28 | @Override 29 | public long getRawByteLength() { 30 | return OFFSET_OF_REMAINDER + length; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/entities/attributes/AttributeSourceFile.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.entities.attributes; 2 | 3 | import org.benf.cfr.reader.util.bytestream.ByteData; 4 | import org.benf.cfr.reader.util.output.Dumper; 5 | 6 | public class AttributeSourceFile extends Attribute { 7 | public static final String ATTRIBUTE_NAME = "SourceFile"; 8 | 9 | private static final long OFFSET_OF_ATTRIBUTE_LENGTH = 2; 10 | private static final long OFFSET_OF_REMAINDER = 6; 11 | 12 | private final int length; 13 | 14 | public AttributeSourceFile(ByteData raw) { 15 | this.length = raw.getS4At(OFFSET_OF_ATTRIBUTE_LENGTH); 16 | } 17 | 18 | @Override 19 | public String getRawName() { 20 | return ATTRIBUTE_NAME; 21 | } 22 | 23 | @Override 24 | public Dumper dump(Dumper d) { 25 | return d.print(ATTRIBUTE_NAME); 26 | } 27 | 28 | @Override 29 | public long getRawByteLength() { 30 | return OFFSET_OF_REMAINDER + length; 31 | } 32 | 33 | @Override 34 | public String toString() { 35 | return ATTRIBUTE_NAME; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/entities/attributes/AttributeSynthetic.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.entities.attributes; 2 | 3 | import org.benf.cfr.reader.util.bytestream.ByteData; 4 | import org.benf.cfr.reader.util.output.Dumper; 5 | 6 | public class AttributeSynthetic extends Attribute { 7 | public final static String ATTRIBUTE_NAME = "Synthetic"; 8 | 9 | private static final long OFFSET_OF_ATTRIBUTE_LENGTH = 2; 10 | private static final long OFFSET_OF_REMAINDER = 6; 11 | 12 | private final int length; 13 | 14 | public AttributeSynthetic(ByteData raw) { 15 | this.length = raw.getS4At(OFFSET_OF_ATTRIBUTE_LENGTH); 16 | } 17 | 18 | @Override 19 | public String getRawName() { 20 | return ATTRIBUTE_NAME; 21 | } 22 | 23 | @Override 24 | public Dumper dump(Dumper d) { 25 | return d; 26 | } 27 | 28 | @Override 29 | public long getRawByteLength() { 30 | return OFFSET_OF_REMAINDER + length; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/entities/attributes/AttributeUnknown.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.entities.attributes; 2 | 3 | import org.benf.cfr.reader.util.bytestream.ByteData; 4 | import org.benf.cfr.reader.util.output.Dumper; 5 | 6 | public class AttributeUnknown extends Attribute { 7 | private static final long OFFSET_OF_ATTRIBUTE_LENGTH = 2; 8 | private static final long OFFSET_OF_REMAINDER = 6; 9 | 10 | private final int length; 11 | private final String name; 12 | 13 | public AttributeUnknown(ByteData raw, String name) { 14 | this.length = raw.getS4At(OFFSET_OF_ATTRIBUTE_LENGTH); 15 | this.name = name; 16 | } 17 | 18 | @Override 19 | public String getRawName() { 20 | return name; 21 | } 22 | 23 | @Override 24 | public Dumper dump(Dumper d) { 25 | return d.print("Unknown Attribute : " + name); 26 | } 27 | 28 | @Override 29 | public long getRawByteLength() { 30 | return OFFSET_OF_REMAINDER + length; 31 | } 32 | 33 | @Override 34 | public String toString() { 35 | return "Unknown Attribute : " + name; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/entities/attributes/BadAttributeException.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.entities.attributes; 2 | 3 | public class BadAttributeException extends RuntimeException { 4 | } 5 | -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/entities/attributes/LocalVariableEntry.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.entities.attributes; 2 | 3 | public class LocalVariableEntry { 4 | private final int startPc; 5 | private final int length; 6 | private final int nameIndex; 7 | private final int descriptorIndex; 8 | private final int index; 9 | 10 | public LocalVariableEntry(int startPc, int length, int nameIndex, int descriptorIndex, int index) { 11 | this.startPc = startPc; 12 | this.length = length; 13 | this.nameIndex = nameIndex; 14 | this.descriptorIndex = descriptorIndex; 15 | this.index = index; 16 | } 17 | 18 | public int getStartPc() { 19 | return startPc; 20 | } 21 | 22 | public int getEndPc() { 23 | return startPc + length; 24 | } 25 | 26 | public int getLength() { 27 | return length; 28 | } 29 | 30 | public int getNameIndex() { 31 | return nameIndex; 32 | } 33 | 34 | public int getDescriptorIndex() { 35 | return descriptorIndex; 36 | } 37 | 38 | public int getIndex() { 39 | return index; 40 | } 41 | 42 | } 43 | -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/entities/attributes/TypeAnnotationEntryKind.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.entities.attributes; 2 | 3 | public enum TypeAnnotationEntryKind { 4 | type_parameter_target, 5 | supertype_target, 6 | type_parameter_bound_target, 7 | empty_target, 8 | method_formal_parameter_target, 9 | throws_target, 10 | localvar_target, 11 | catch_target, 12 | offset_target, 13 | type_argument_target 14 | } 15 | -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/entities/attributes/TypeAnnotationLocation.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.entities.attributes; 2 | 3 | public enum TypeAnnotationLocation { 4 | ClassFile, 5 | method_info, 6 | field_info, 7 | Code 8 | } 9 | -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/entities/attributes/TypePath.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.entities.attributes; 2 | 3 | import java.util.List; 4 | 5 | public class TypePath { 6 | /* 7 | If the value of the type_path_kind item is 0, 1, or 2, then the value of the type_argument_index item is 0. 8 | 9 | If the value of the type_path_kind item is 3, then the value of the type_argument_index item specifies which 10 | type argument of a parameterized type is annotated, where 0 indicates the first type argument of a parameterized type. 11 | */ 12 | public final List segments; 13 | 14 | public TypePath(List segments) { 15 | this.segments = segments; 16 | } 17 | 18 | } 19 | -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/entities/attributes/TypePathAccessor.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.entities.attributes; 2 | 3 | public interface TypePathAccessor { 4 | } 5 | -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/entities/attributes/TypePathPart.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.entities.attributes; 2 | 3 | import org.benf.cfr.reader.bytecode.analysis.types.JavaAnnotatedTypeIterator; 4 | import org.benf.cfr.reader.util.DecompilerComments; 5 | 6 | public interface TypePathPart { 7 | JavaAnnotatedTypeIterator apply(JavaAnnotatedTypeIterator it, DecompilerComments comments); 8 | } 9 | -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/entities/attributes/TypePathPartArray.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.entities.attributes; 2 | 3 | import org.benf.cfr.reader.bytecode.analysis.types.JavaAnnotatedTypeIterator; 4 | import org.benf.cfr.reader.util.DecompilerComments; 5 | 6 | public class TypePathPartArray implements TypePathPart { 7 | public static final TypePathPartArray INSTANCE = new TypePathPartArray(); 8 | 9 | private TypePathPartArray() { 10 | } 11 | 12 | @Override 13 | public JavaAnnotatedTypeIterator apply(JavaAnnotatedTypeIterator it, DecompilerComments comments) { 14 | return it.moveArray(comments); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/entities/attributes/TypePathPartBound.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.entities.attributes; 2 | 3 | import org.benf.cfr.reader.bytecode.analysis.types.JavaAnnotatedTypeIterator; 4 | import org.benf.cfr.reader.util.DecompilerComments; 5 | 6 | public class TypePathPartBound implements TypePathPart { 7 | public static final TypePathPartBound INSTANCE = new TypePathPartBound(); 8 | 9 | private TypePathPartBound() { 10 | } 11 | 12 | @Override 13 | public JavaAnnotatedTypeIterator apply(JavaAnnotatedTypeIterator it, DecompilerComments comments) { 14 | return it.moveBound(comments); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/entities/attributes/TypePathPartNested.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.entities.attributes; 2 | 3 | import org.benf.cfr.reader.bytecode.analysis.types.JavaAnnotatedTypeIterator; 4 | import org.benf.cfr.reader.util.DecompilerComments; 5 | 6 | public class TypePathPartNested implements TypePathPart { 7 | public static final TypePathPartNested INSTANCE = new TypePathPartNested(); 8 | 9 | private TypePathPartNested() { 10 | } 11 | 12 | @Override 13 | public JavaAnnotatedTypeIterator apply(JavaAnnotatedTypeIterator it, DecompilerComments comments) { 14 | return it.moveNested(comments); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/entities/attributes/TypePathPartParameterized.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.entities.attributes; 2 | 3 | import org.benf.cfr.reader.bytecode.analysis.types.JavaAnnotatedTypeIterator; 4 | import org.benf.cfr.reader.util.DecompilerComments; 5 | 6 | public class TypePathPartParameterized implements TypePathPart { 7 | private final int index; 8 | 9 | public TypePathPartParameterized(int index) { 10 | this.index = index; 11 | } 12 | 13 | @Override 14 | public JavaAnnotatedTypeIterator apply(JavaAnnotatedTypeIterator it, DecompilerComments comments) { 15 | return it.moveParameterized(index, comments); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/entities/bootstrap/MethodHandleBehaviour.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.entities.bootstrap; 2 | 3 | public enum MethodHandleBehaviour { 4 | GET_FIELD, 5 | GET_STATIC, 6 | PUT_FIELD, 7 | PUT_STATIC, 8 | INVOKE_VIRTUAL, 9 | INVOKE_STATIC, 10 | INVOKE_SPECIAL, 11 | NEW_INVOKE_SPECIAL, 12 | INVOKE_INTERFACE; 13 | 14 | public static MethodHandleBehaviour decode(byte value) { 15 | switch (value) { 16 | case 1: 17 | return GET_FIELD; 18 | case 2: 19 | return GET_STATIC; 20 | case 3: 21 | return PUT_FIELD; 22 | case 4: 23 | return PUT_STATIC; 24 | case 5: 25 | return INVOKE_VIRTUAL; 26 | case 6: 27 | return INVOKE_STATIC; 28 | case 7: 29 | return INVOKE_SPECIAL; 30 | case 8: 31 | return NEW_INVOKE_SPECIAL; 32 | case 9: 33 | return INVOKE_INTERFACE; 34 | default: 35 | throw new IllegalArgumentException("Unknown method handle behaviour " + value); 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/entities/classfilehelpers/ClassFileDumper.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.entities.classfilehelpers; 2 | 3 | import org.benf.cfr.reader.entities.ClassFile; 4 | import org.benf.cfr.reader.state.TypeUsageCollector; 5 | import org.benf.cfr.reader.util.TypeUsageCollectable; 6 | import org.benf.cfr.reader.util.output.Dumper; 7 | 8 | public interface ClassFileDumper extends TypeUsageCollectable { 9 | enum InnerClassDumpType { 10 | NOT(false), 11 | INNER_CLASS(true), 12 | INLINE_CLASS(true); 13 | 14 | final boolean isInnerClass; 15 | 16 | InnerClassDumpType(boolean isInnerClass) { 17 | this.isInnerClass = isInnerClass; 18 | } 19 | 20 | public boolean isInnerClass() { 21 | return isInnerClass; 22 | } 23 | } 24 | 25 | Dumper dump(ClassFile classFile, InnerClassDumpType innerClass, Dumper d); 26 | 27 | /* 28 | * Some dumpers may need to request additional types - 29 | */ 30 | void collectTypeUsages(TypeUsageCollector collector); 31 | 32 | } 33 | -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/entities/constantpool/ConstantPoolEntryDouble.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.entities.constantpool; 2 | 3 | import org.benf.cfr.reader.bytecode.analysis.types.StackType; 4 | import org.benf.cfr.reader.entities.AbstractConstantPoolEntry; 5 | import org.benf.cfr.reader.util.bytestream.ByteData; 6 | import org.benf.cfr.reader.util.output.Dumper; 7 | 8 | public class ConstantPoolEntryDouble extends AbstractConstantPoolEntry implements ConstantPoolEntryLiteral { 9 | private final double value; 10 | 11 | public ConstantPoolEntryDouble(ConstantPool cp, ByteData data) { 12 | super(cp); 13 | this.value = data.getDoubleAt(1); 14 | } 15 | 16 | @Override 17 | public long getRawByteLength() { 18 | return 9; 19 | } 20 | 21 | @Override 22 | public void dump(Dumper d) { 23 | d.print("CONSTANT_Double " + value); 24 | } 25 | 26 | public double getValue() { 27 | return value; 28 | } 29 | 30 | @Override 31 | public StackType getStackType() { 32 | return StackType.DOUBLE; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/entities/constantpool/ConstantPoolEntryFloat.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.entities.constantpool; 2 | 3 | import org.benf.cfr.reader.bytecode.analysis.types.StackType; 4 | import org.benf.cfr.reader.entities.AbstractConstantPoolEntry; 5 | import org.benf.cfr.reader.util.bytestream.ByteData; 6 | import org.benf.cfr.reader.util.output.Dumper; 7 | 8 | public class ConstantPoolEntryFloat extends AbstractConstantPoolEntry implements ConstantPoolEntryLiteral { 9 | private final float value; 10 | 11 | public ConstantPoolEntryFloat(ConstantPool cp, ByteData data) { 12 | super(cp); 13 | this.value = data.getFloatAt(1); 14 | } 15 | 16 | @Override 17 | public long getRawByteLength() { 18 | return 5; 19 | } 20 | 21 | @Override 22 | public void dump(Dumper d) { 23 | d.print("CONSTANT_Float"); 24 | } 25 | 26 | @Override 27 | public StackType getStackType() { 28 | return StackType.FLOAT; 29 | } 30 | 31 | public float getValue() { 32 | return value; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/entities/constantpool/ConstantPoolEntryInteger.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.entities.constantpool; 2 | 3 | import org.benf.cfr.reader.bytecode.analysis.types.StackType; 4 | import org.benf.cfr.reader.entities.AbstractConstantPoolEntry; 5 | import org.benf.cfr.reader.util.bytestream.ByteData; 6 | import org.benf.cfr.reader.util.output.Dumper; 7 | 8 | public class ConstantPoolEntryInteger extends AbstractConstantPoolEntry implements ConstantPoolEntryLiteral { 9 | private static final long OFFSET_OF_BYTES = 1; 10 | 11 | private final int value; 12 | 13 | public ConstantPoolEntryInteger(ConstantPool cp, ByteData data) { 14 | super(cp); 15 | this.value = data.getS4At(OFFSET_OF_BYTES); 16 | } 17 | 18 | @Override 19 | public long getRawByteLength() { 20 | return 5; 21 | } 22 | 23 | @Override 24 | public void dump(Dumper d) { 25 | d.print("CONSTANT_Integer value=" + value); 26 | } 27 | 28 | public int getValue() { 29 | return value; 30 | } 31 | 32 | @Override 33 | public StackType getStackType() { 34 | return StackType.INT; 35 | } 36 | 37 | @Override 38 | public String toString() { 39 | return ("CONSTANT_Integer value=" + value); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/entities/constantpool/ConstantPoolEntryLiteral.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.entities.constantpool; 2 | 3 | import org.benf.cfr.reader.bytecode.analysis.types.StackType; 4 | 5 | public interface ConstantPoolEntryLiteral { 6 | StackType getStackType(); 7 | } 8 | -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/entities/constantpool/ConstantPoolEntryLong.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.entities.constantpool; 2 | 3 | import org.benf.cfr.reader.bytecode.analysis.types.StackType; 4 | import org.benf.cfr.reader.entities.AbstractConstantPoolEntry; 5 | import org.benf.cfr.reader.util.bytestream.ByteData; 6 | import org.benf.cfr.reader.util.output.Dumper; 7 | 8 | public class ConstantPoolEntryLong extends AbstractConstantPoolEntry implements ConstantPoolEntryLiteral { 9 | private final long value; 10 | 11 | public ConstantPoolEntryLong(ConstantPool cp, ByteData data) { 12 | super(cp); 13 | this.value = data.getLongAt(1); 14 | } 15 | 16 | @Override 17 | public long getRawByteLength() { 18 | return 9; 19 | } 20 | 21 | @Override 22 | public void dump(Dumper d) { 23 | d.print("CONSTANT_Long " + value); 24 | } 25 | 26 | @Override 27 | public String toString() { 28 | return "CONSTANT_Long[" + value + "]"; 29 | } 30 | 31 | public long getValue() { 32 | return value; 33 | } 34 | 35 | @Override 36 | public StackType getStackType() { 37 | return StackType.LONG; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/entities/constantpool/ConstantPoolEntryMethodType.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.entities.constantpool; 2 | 3 | import org.benf.cfr.reader.bytecode.analysis.types.JavaTypeInstance; 4 | import org.benf.cfr.reader.entities.AbstractConstantPoolEntry; 5 | import org.benf.cfr.reader.util.bytestream.ByteData; 6 | import org.benf.cfr.reader.util.output.Dumper; 7 | 8 | public class ConstantPoolEntryMethodType extends AbstractConstantPoolEntry { 9 | private static final long OFFSET_OF_DESCRIPTOR_INDEX = 1; 10 | 11 | private final int descriptorIndex; 12 | 13 | public ConstantPoolEntryMethodType(ConstantPool cp, ByteData data) { 14 | super(cp); 15 | this.descriptorIndex = data.getU2At(OFFSET_OF_DESCRIPTOR_INDEX); 16 | } 17 | 18 | public ConstantPool getCp() { 19 | return super.getCp(); 20 | } 21 | 22 | @Override 23 | public long getRawByteLength() { 24 | return 3; 25 | } 26 | 27 | @Override 28 | public void dump(Dumper d) { 29 | d.print(this.toString()); 30 | } 31 | 32 | public ConstantPoolEntryUTF8 getDescriptor() { 33 | return getCp().getUTF8Entry(descriptorIndex); 34 | } 35 | 36 | @Override 37 | public String toString() { 38 | return "MethodType value=" + descriptorIndex; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/entities/constantpool/ConstantPoolEntryModuleInfo.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.entities.constantpool; 2 | 3 | import org.benf.cfr.reader.entities.AbstractConstantPoolEntry; 4 | import org.benf.cfr.reader.util.bytestream.ByteData; 5 | import org.benf.cfr.reader.util.output.Dumper; 6 | 7 | public class ConstantPoolEntryModuleInfo extends AbstractConstantPoolEntry { 8 | private static final long OFFSET_OF_NAME_INDEX = 1; 9 | 10 | private final int nameIndex; 11 | 12 | ConstantPoolEntryModuleInfo(ConstantPool cp, ByteData data) { 13 | super(cp); 14 | this.nameIndex = data.getU2At(OFFSET_OF_NAME_INDEX); 15 | } 16 | 17 | public ConstantPool getCp() { 18 | return super.getCp(); 19 | } 20 | 21 | @Override 22 | public long getRawByteLength() { 23 | return 3; 24 | } 25 | 26 | @Override 27 | public void dump(Dumper d) { 28 | d.print(this.toString()); 29 | } 30 | 31 | public ConstantPoolEntryUTF8 getName() { 32 | return getCp().getUTF8Entry(nameIndex); 33 | } 34 | 35 | @Override 36 | public String toString() { 37 | return "NameIndex value=" + nameIndex; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/entities/constantpool/ConstantPoolEntryPackageInfo.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.entities.constantpool; 2 | 3 | import org.benf.cfr.reader.bytecode.analysis.types.ClassNameUtils; 4 | import org.benf.cfr.reader.entities.AbstractConstantPoolEntry; 5 | import org.benf.cfr.reader.util.bytestream.ByteData; 6 | import org.benf.cfr.reader.util.output.Dumper; 7 | 8 | public class ConstantPoolEntryPackageInfo extends AbstractConstantPoolEntry { 9 | private static final long OFFSET_OF_NAME_INDEX = 1; 10 | 11 | private final int nameIndex; 12 | 13 | ConstantPoolEntryPackageInfo(ConstantPool cp, ByteData data) { 14 | super(cp); 15 | this.nameIndex = data.getU2At(OFFSET_OF_NAME_INDEX); 16 | } 17 | 18 | public ConstantPool getCp() { 19 | return super.getCp(); 20 | } 21 | 22 | @Override 23 | public long getRawByteLength() { 24 | return 3; 25 | } 26 | 27 | @Override 28 | public void dump(Dumper d) { 29 | d.print(this.toString()); 30 | } 31 | 32 | public String getPackageName() { 33 | return ClassNameUtils.convertFromPath(getCp().getUTF8Entry(nameIndex).getValue()); 34 | } 35 | 36 | public ConstantPoolEntryUTF8 getName() { 37 | return getCp().getUTF8Entry(nameIndex); 38 | } 39 | 40 | @Override 41 | public String toString() { 42 | return "NameIndex value=" + nameIndex; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/entities/constantpool/ConstantPoolEntryString.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.entities.constantpool; 2 | 3 | import org.benf.cfr.reader.bytecode.analysis.parse.utils.QuotingUtils; 4 | import org.benf.cfr.reader.bytecode.analysis.types.StackType; 5 | import org.benf.cfr.reader.entities.AbstractConstantPoolEntry; 6 | import org.benf.cfr.reader.util.bytestream.ByteData; 7 | import org.benf.cfr.reader.util.output.Dumper; 8 | 9 | public class ConstantPoolEntryString extends AbstractConstantPoolEntry implements ConstantPoolEntryLiteral { 10 | private static final long OFFSET_OF_STRING_INDEX = 1; 11 | 12 | private final long stringIndex; 13 | private transient String string; 14 | 15 | public ConstantPoolEntryString(ConstantPool cp, ByteData data) { 16 | super(cp); 17 | this.stringIndex = data.getU2At(OFFSET_OF_STRING_INDEX); 18 | } 19 | 20 | @Override 21 | public long getRawByteLength() { 22 | return 3; 23 | } 24 | 25 | @Override 26 | public void dump(Dumper d) { 27 | d.print("String " + getValue()); 28 | } 29 | 30 | public String getValue() { 31 | if (string == null) { 32 | string = QuotingUtils.enquoteString(getCp().getUTF8Entry((int) stringIndex).getValue()); 33 | } 34 | return string; 35 | } 36 | 37 | @Override 38 | public StackType getStackType() { 39 | return StackType.REF; 40 | } 41 | } 42 | 43 | 44 | -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/entities/exceptions/ExceptionCheck.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.entities.exceptions; 2 | 3 | import org.benf.cfr.reader.bytecode.analysis.parse.Expression; 4 | import org.benf.cfr.reader.bytecode.analysis.parse.expression.AbstractMemberFunctionInvokation; 5 | import org.benf.cfr.reader.bytecode.analysis.types.JavaTypeInstance; 6 | 7 | import java.util.Set; 8 | 9 | public interface ExceptionCheck { 10 | boolean checkAgainst(Set thrown); 11 | 12 | // Might this throw in a way which means it can't be moved into the exception block? 13 | boolean checkAgainst(AbstractMemberFunctionInvokation functionInvokation); 14 | 15 | boolean checkAgainstException(Expression expression); 16 | 17 | boolean mightCatchUnchecked(); 18 | } 19 | -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/entities/exceptions/ExceptionCheckSimple.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.entities.exceptions; 2 | 3 | import org.benf.cfr.reader.bytecode.analysis.parse.Expression; 4 | import org.benf.cfr.reader.bytecode.analysis.parse.expression.AbstractMemberFunctionInvokation; 5 | import org.benf.cfr.reader.bytecode.analysis.types.JavaTypeInstance; 6 | 7 | import java.util.Set; 8 | 9 | public class ExceptionCheckSimple implements ExceptionCheck { 10 | public static final ExceptionCheck INSTANCE = new ExceptionCheckSimple(); 11 | 12 | private ExceptionCheckSimple() { 13 | } 14 | 15 | @Override 16 | public boolean checkAgainst(Set thrown) { 17 | return true; 18 | } 19 | 20 | @Override 21 | public boolean checkAgainst(AbstractMemberFunctionInvokation functionInvokation) { 22 | return true; 23 | } 24 | 25 | @Override 26 | public boolean checkAgainstException(Expression expression) { 27 | return true; 28 | } 29 | 30 | @Override 31 | public boolean mightCatchUnchecked() { 32 | return true; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/entities/innerclass/InnerClassAttributeInfo.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.entities.innerclass; 2 | 3 | import org.benf.cfr.reader.bytecode.analysis.types.JavaTypeInstance; 4 | import org.benf.cfr.reader.entities.AccessFlag; 5 | import org.benf.cfr.reader.util.annotation.Nullable; 6 | 7 | import java.util.Set; 8 | 9 | public class InnerClassAttributeInfo { 10 | private final 11 | @Nullable 12 | JavaTypeInstance innerClassInfo; 13 | private final 14 | @Nullable 15 | JavaTypeInstance outerClassInfo; 16 | private final 17 | @Nullable 18 | String innerName; 19 | private final Set accessFlags; 20 | 21 | public InnerClassAttributeInfo(JavaTypeInstance innerClassInfo, JavaTypeInstance outerClassInfo, String innerName, Set accessFlags) { 22 | this.innerClassInfo = innerClassInfo; 23 | this.outerClassInfo = outerClassInfo; 24 | this.innerName = innerName; 25 | this.accessFlags = accessFlags; 26 | } 27 | 28 | public JavaTypeInstance getInnerClassInfo() { 29 | return innerClassInfo; 30 | } 31 | 32 | private JavaTypeInstance getOuterClassInfo() { 33 | return outerClassInfo; 34 | } 35 | 36 | private String getInnerName() { 37 | return innerName; 38 | } 39 | 40 | public Set getAccessFlags() { 41 | return accessFlags; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/entityfactories/ContiguousEntityFactory.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.entityfactories; 2 | 3 | import org.benf.cfr.reader.util.KnowsRawSize; 4 | import org.benf.cfr.reader.util.functors.UnaryFunction; 5 | import org.benf.cfr.reader.util.bytestream.ByteData; 6 | import org.benf.cfr.reader.util.bytestream.OffsettingByteData; 7 | 8 | import java.util.List; 9 | 10 | public class ContiguousEntityFactory { 11 | 12 | public static long build(final ByteData raw, int count, List tgt, UnaryFunction func) 13 | { 14 | OffsettingByteData data = raw.getOffsettingOffsetData(0); 15 | for (int x=0;x long buildSized(final ByteData raw, int count, int itemLength, List tgt, UnaryFunction func) 25 | { 26 | OffsettingByteData data = raw.getOffsettingOffsetData(0); 27 | for (short x=0;x argTypes; 12 | 13 | public MethodMapping(String rename, String name, JavaTypeInstance res, List argTypes) { 14 | this.name = name; 15 | this.rename = rename; 16 | this.res = res; 17 | this.argTypes = argTypes; 18 | } 19 | 20 | public String getName() { 21 | return name; 22 | } 23 | 24 | public String getRename() { 25 | return rename; 26 | } 27 | 28 | public JavaTypeInstance getResultType() { 29 | return res; 30 | } 31 | 32 | public List getArgTypes() { 33 | return argTypes; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/mapping/ObfuscationMapping.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.mapping; 2 | 3 | import org.benf.cfr.reader.state.ObfuscationRewriter; 4 | import org.benf.cfr.reader.state.ObfuscationTypeMap; 5 | 6 | public interface ObfuscationMapping extends ObfuscationRewriter, ObfuscationTypeMap { 7 | } 8 | -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Created with IntelliJ IDEA. 3 | * User: lee 4 | * Date: 14/12/16 5 | * Time: 07:33 6 | */ 7 | package org.benf.cfr.reader; -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/state/AbstractTypeUsageCollector.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.state; 2 | 3 | import org.benf.cfr.reader.bytecode.analysis.types.JavaTypeInstance; 4 | import org.benf.cfr.reader.util.TypeUsageCollectable; 5 | 6 | import java.util.Collection; 7 | 8 | public abstract class AbstractTypeUsageCollector implements TypeUsageCollector { 9 | @Override 10 | public void collect(Collection types) { 11 | if (types == null) return; 12 | for (JavaTypeInstance type : types) collect(type); 13 | } 14 | 15 | @Override 16 | public void collectFrom(TypeUsageCollectable collectable) { 17 | if (collectable != null) collectable.collectTypeUsages(this); 18 | } 19 | 20 | @Override 21 | public void collectFromT(TypeUsageCollectable collectable) { 22 | collectFrom(collectable); 23 | } 24 | 25 | @Override 26 | public void collectFrom(Collection collectables) { 27 | if (collectables != null) { 28 | for (TypeUsageCollectable collectable : collectables) { 29 | if (collectable != null) collectable.collectTypeUsages(this); 30 | } 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/state/ClassNameFunction.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.state; 2 | 3 | import java.util.Map; 4 | 5 | public interface ClassNameFunction { 6 | Map apply(Map names); 7 | } 8 | -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/state/DetectedStaticImport.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.state; 2 | 3 | import org.benf.cfr.reader.bytecode.analysis.types.JavaTypeInstance; 4 | 5 | public class DetectedStaticImport { 6 | final JavaTypeInstance clazz; 7 | final String name; 8 | 9 | public JavaTypeInstance getClazz() { 10 | return clazz; 11 | } 12 | 13 | public String getName() { 14 | return name; 15 | } 16 | 17 | DetectedStaticImport(JavaTypeInstance clazz, String name) { 18 | this.clazz = clazz; 19 | this.name = name; 20 | } 21 | 22 | @Override 23 | public boolean equals(Object o) { 24 | if (this == o) return true; 25 | if (o == null || getClass() != o.getClass()) return false; 26 | 27 | DetectedStaticImport that = (DetectedStaticImport) o; 28 | 29 | if (!clazz.equals(that.clazz)) return false; 30 | if (!name.equals(that.name)) return false; 31 | 32 | return true; 33 | } 34 | 35 | @Override 36 | public int hashCode() { 37 | int result = clazz.hashCode(); 38 | result = 31 * result + name.hashCode(); 39 | return result; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/state/JarContentImpl.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.state; 2 | 3 | import org.benf.cfr.reader.apiunreleased.JarContent; 4 | import org.benf.cfr.reader.util.AnalysisType; 5 | 6 | import java.util.Collection; 7 | import java.util.Map; 8 | 9 | public class JarContentImpl implements JarContent { 10 | private final Collection classFiles; 11 | private final Map manifestEntries; 12 | private final AnalysisType analysisType; 13 | 14 | JarContentImpl(Collection classFiles, Map manifestEntries, AnalysisType analysisType) { 15 | this.classFiles = classFiles; 16 | this.manifestEntries = manifestEntries; 17 | this.analysisType = analysisType; 18 | } 19 | 20 | @Override 21 | public Collection getClassFiles() { 22 | return classFiles; 23 | } 24 | 25 | @Override 26 | public Map getManifestEntries() { 27 | return manifestEntries; 28 | } 29 | 30 | @Override 31 | public AnalysisType getAnalysisType() { 32 | return analysisType; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/state/ObfuscationRewriter.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.state; 2 | 3 | import org.benf.cfr.reader.bytecode.analysis.types.JavaTypeInstance; 4 | import org.benf.cfr.reader.util.output.Dumper; 5 | 6 | import java.util.List; 7 | 8 | public interface ObfuscationRewriter { 9 | Dumper wrap(Dumper d); 10 | 11 | JavaTypeInstance get(JavaTypeInstance t); 12 | 13 | List get(List types); 14 | } 15 | -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/state/ObfuscationTypeMap.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.state; 2 | 3 | import org.benf.cfr.reader.bytecode.analysis.types.JavaTypeInstance; 4 | import org.benf.cfr.reader.entities.innerclass.InnerClassAttributeInfo; 5 | import org.benf.cfr.reader.util.functors.UnaryFunction; 6 | 7 | import java.util.List; 8 | 9 | public interface ObfuscationTypeMap { 10 | boolean providesInnerClassInfo(); 11 | 12 | JavaTypeInstance get(JavaTypeInstance type); 13 | 14 | UnaryFunction getter(); 15 | 16 | List getInnerClassInfo(JavaTypeInstance classType); 17 | } 18 | -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/state/OverloadMethodSetCache.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.state; 2 | 3 | import org.benf.cfr.reader.bytecode.analysis.types.MethodPrototype; 4 | import org.benf.cfr.reader.entities.ClassFile; 5 | import org.benf.cfr.reader.entities.classfilehelpers.OverloadMethodSet; 6 | import org.benf.cfr.reader.util.collections.MapFactory; 7 | import org.benf.cfr.reader.util.functors.UnaryFunction; 8 | 9 | import java.util.Map; 10 | 11 | // The cost of retaining all overload information may become large. Keeping it centrally allows us to flush it if in low 12 | // memory mode. 13 | public class OverloadMethodSetCache { 14 | private final Map> content = MapFactory.newLazyMap(new UnaryFunction>() { 15 | @Override 16 | public Map invoke(ClassFile arg) { 17 | return MapFactory.newIdentityMap(); 18 | } 19 | }); 20 | 21 | public OverloadMethodSet get(ClassFile classFile, MethodPrototype methodPrototype) { 22 | return content.get(classFile).get(methodPrototype); 23 | } 24 | 25 | public void set(ClassFile classFile, MethodPrototype methodPrototype, OverloadMethodSet overloadMethodSet) { 26 | content.get(classFile).put(methodPrototype, overloadMethodSet); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/state/TypeUsageCollector.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.state; 2 | 3 | import org.benf.cfr.reader.bytecode.analysis.types.JavaRefTypeInstance; 4 | import org.benf.cfr.reader.bytecode.analysis.types.JavaTypeInstance; 5 | import org.benf.cfr.reader.util.TypeUsageCollectable; 6 | 7 | import java.util.Collection; 8 | 9 | public interface TypeUsageCollector { 10 | void collectRefType(JavaRefTypeInstance type); 11 | 12 | void collect(JavaTypeInstance type); 13 | 14 | void collect(Collection types); 15 | 16 | // Explicitly named helper to allow J8's less lenient bridging. 17 | void collectFromT(TypeUsageCollectable collectable); 18 | 19 | void collectFrom(TypeUsageCollectable collectable); 20 | 21 | void collectFrom(Collection collectables); 22 | 23 | TypeUsageInformation getTypeUsageInformation(); 24 | 25 | boolean isStatementRecursive(); 26 | } 27 | -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/state/TypeUsageInformation.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.state; 2 | 3 | import org.benf.cfr.reader.bytecode.analysis.types.JavaRefTypeInstance; 4 | import org.benf.cfr.reader.bytecode.analysis.types.JavaTypeInstance; 5 | import org.benf.cfr.reader.util.output.IllegalIdentifierDump; 6 | import org.benf.cfr.reader.util.output.TypeContext; 7 | 8 | import java.util.Set; 9 | 10 | public interface TypeUsageInformation { 11 | JavaRefTypeInstance getAnalysisType(); 12 | 13 | Set getShortenedClassTypes(); 14 | 15 | Set getUsedClassTypes(); 16 | 17 | Set getUsedInnerClassTypes(); 18 | 19 | boolean hasLocalInstance(JavaRefTypeInstance type); 20 | 21 | String getName(JavaTypeInstance type, TypeContext typeContext); 22 | 23 | boolean isNameClash(JavaTypeInstance type, String name, TypeContext typeContext); 24 | 25 | String generateInnerClassShortName(JavaRefTypeInstance clazz); 26 | 27 | String generateOverriddenName(JavaRefTypeInstance clazz); 28 | 29 | IllegalIdentifierDump getIid(); 30 | 31 | boolean isStaticImport(JavaTypeInstance clazz, String fixedName); 32 | 33 | Set getDetectedStaticImports(); 34 | } 35 | -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/util/AnalysisType.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.util; 2 | 3 | public enum AnalysisType { 4 | DETECT, 5 | JAR, 6 | WAR, 7 | CLASS 8 | } 9 | 10 | -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/util/BoolPair.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.util; 2 | 3 | /** 4 | * very simple enum to help switching on an XOR style decision. 5 | */ 6 | public enum BoolPair { 7 | NEITHER(0), 8 | FIRST(1), 9 | SECOND(1), 10 | BOTH(2); 11 | 12 | private final int count; 13 | 14 | BoolPair(int count) { 15 | this.count = count; 16 | } 17 | 18 | public static BoolPair get(boolean a, boolean b) { 19 | if (a) { 20 | if (b) return BOTH; 21 | return FIRST; 22 | } 23 | if (b) return SECOND; 24 | return NEITHER; 25 | } 26 | 27 | public int getCount() { 28 | return count; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/util/CannotLoadClassException.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.util; 2 | 3 | public class CannotLoadClassException extends RuntimeException { 4 | public CannotLoadClassException(String s, Throwable throwable) { 5 | super(s, throwable); 6 | } 7 | 8 | @Override 9 | public String toString() { 10 | return super.toString() + ((super.getCause() == null) ? "" : (" - " + super.getCause().toString())); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/util/CannotPerformDecode.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.util; 2 | 3 | public class CannotPerformDecode extends ConfusedCFRException { 4 | public CannotPerformDecode(String s) { 5 | super(s); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/util/ConfusedCFRException.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.util; 2 | 3 | public class ConfusedCFRException extends RuntimeException { 4 | public ConfusedCFRException(String s) 5 | { 6 | super(s); 7 | } 8 | public ConfusedCFRException(Exception e) 9 | { 10 | super(e); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/util/DecompilerCommentSource.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.util; 2 | 3 | import java.util.List; 4 | 5 | public interface DecompilerCommentSource { 6 | List getComments(); 7 | } 8 | -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/util/KnowsRawName.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.util; 2 | 3 | public interface KnowsRawName { 4 | String getRawName(); 5 | } 6 | -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/util/KnowsRawSize.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.util; 2 | 3 | public interface KnowsRawSize { 4 | long getRawByteLength(); 5 | } 6 | -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/util/MalformedPrototypeException.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.util; 2 | 3 | public class MalformedPrototypeException extends RuntimeException{ 4 | public MalformedPrototypeException(String message, Throwable cause) { 5 | super(message, cause); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/util/MiscConstants.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.util; 2 | 3 | import java.util.regex.Pattern; 4 | 5 | public interface MiscConstants { 6 | String CFR_HEADER_BRA = "Decompiled with CFR"; 7 | 8 | String INIT_METHOD = ""; 9 | String STATIC_INIT_METHOD = ""; 10 | String DOT_THIS = ".this"; 11 | String THIS = "this"; 12 | String CLASS = "class"; 13 | String NEW = "new"; 14 | String EQUALS = "equals"; 15 | String HASHCODE = "hashCode"; 16 | String TOSTRING = "toString"; 17 | String PACKAGE_INFO = "package-info"; 18 | 19 | String UNBOUND_GENERIC = "?"; 20 | char INNER_CLASS_SEP_CHAR = '$'; 21 | String INNER_CLASS_SEP_STR = "$"; 22 | 23 | String DESERIALISE_LAMBDA_METHOD = "$deserializeLambda$"; 24 | String SCALA_SERIAL_VERSION = "serialVersionUID"; 25 | String GET_CLASS_NAME = "getClass"; 26 | String REQUIRE_NON_NULL = "requireNonNull"; 27 | 28 | String MANIFEST_PATH = "META-INF/MANIFEST.MF"; 29 | String MULTI_RELEASE_KEY = "Multi-Release"; 30 | String MANIFEST_CLASS_PATH = "Class-Path"; 31 | String MULTI_RELEASE_PREFIX = "META-INF/versions/"; 32 | String WAR_PREFIX = "WEB-INF/classes/"; 33 | Pattern MULTI_RELEASE_PATH_PATTERN = Pattern.compile("^" + MULTI_RELEASE_PREFIX + "(\\d+)/(.*)$"); 34 | } 35 | -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/util/Optional.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.util; 2 | 3 | import org.benf.cfr.reader.util.functors.UnaryProcedure; 4 | 5 | public class Optional { 6 | private final T value; 7 | private final boolean set; 8 | private static final Optional Empty = new Optional(); 9 | 10 | private Optional(T val) { 11 | value = val; 12 | set = true; 13 | } 14 | 15 | private Optional() { 16 | set = false; 17 | value = null; 18 | } 19 | 20 | public boolean isSet() { 21 | return set; 22 | } 23 | 24 | public T getValue() { 25 | return value; 26 | } 27 | 28 | public void then(UnaryProcedure func) { 29 | func.call(value); 30 | } 31 | 32 | public static Optional of(T value) { 33 | return new Optional(value); 34 | } 35 | 36 | public static Optional empty() { 37 | //noinspection unchecked 38 | return (Optional)Optional.Empty; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/util/Troolean.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.util; 2 | 3 | /** 4 | * very simple enum to help switching on an XOR style decision. 5 | */ 6 | public enum Troolean { 7 | NEITHER, 8 | TRUE, 9 | FALSE; 10 | 11 | public static Troolean get(Boolean a) { 12 | if (a == null) return NEITHER; 13 | return a ? TRUE : FALSE; 14 | } 15 | 16 | public boolean boolValue(boolean ifNeither) { 17 | switch (this) { 18 | case TRUE: 19 | return true; 20 | case FALSE: 21 | return false; 22 | default: 23 | return ifNeither; 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/util/TypeUsageCollectable.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.util; 2 | 3 | import org.benf.cfr.reader.state.TypeUsageCollector; 4 | 5 | public interface TypeUsageCollectable { 6 | void collectTypeUsages(TypeUsageCollector collector); 7 | } 8 | -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/util/UnverifiableJumpException.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.util; 2 | 3 | public class UnverifiableJumpException extends RuntimeException { 4 | 5 | public UnverifiableJumpException() 6 | { 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/util/annotation/Nullable.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.util.annotation; 2 | 3 | public @interface Nullable { 4 | } 5 | -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/util/bytestream/BaseByteData.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.util.bytestream; 2 | 3 | public class BaseByteData extends AbstractBackedByteData { 4 | public BaseByteData(byte[] data) { 5 | super(data); 6 | } 7 | 8 | @Override 9 | public ByteData getOffsetData(long offset) { 10 | return new OffsetBackedByteData(d, offset); 11 | } 12 | 13 | @Override 14 | public OffsettingByteData getOffsettingOffsetData(long offset) { 15 | return new OffsettingBackedByteData(d, offset); 16 | } 17 | 18 | @Override 19 | int getRealOffset(int offset) { 20 | return offset; 21 | } 22 | 23 | } 24 | -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/util/bytestream/ByteData.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.util.bytestream; 2 | 3 | public interface ByteData { 4 | byte getS1At(long offset); 5 | 6 | short getU1At(long offset); 7 | 8 | short getS2At(long offset); 9 | 10 | int getU2At(long offset); 11 | 12 | int getS4At(long offset); 13 | 14 | double getDoubleAt(long o); 15 | 16 | float getFloatAt(long o); 17 | 18 | long getLongAt(long o); 19 | 20 | byte[] getBytesAt(int count, long offset); 21 | 22 | ByteData getOffsetData(long offset); 23 | 24 | OffsettingByteData getOffsettingOffsetData(long offset); 25 | } 26 | -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/util/bytestream/OffsetBackedByteData.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.util.bytestream; 2 | 3 | public class OffsetBackedByteData extends AbstractBackedByteData { 4 | private final int offset; 5 | 6 | OffsetBackedByteData(byte[] data, long offset) { 7 | super(data); 8 | this.offset = (int) offset; 9 | } 10 | 11 | @Override 12 | public ByteData getOffsetData(long offset) { 13 | return new OffsetBackedByteData(d, this.offset + offset); 14 | } 15 | 16 | @Override 17 | public OffsettingByteData getOffsettingOffsetData(long offset) { 18 | return new OffsettingBackedByteData(d, this.offset + offset); 19 | } 20 | 21 | @Override 22 | int getRealOffset(int o) { 23 | return o + offset; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/util/bytestream/OffsettingBackedByteData.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.util.bytestream; 2 | 3 | public class OffsettingBackedByteData extends AbstractBackedByteData implements OffsettingByteData { 4 | private final int originalOffset; 5 | private int mutableOffset; 6 | 7 | OffsettingBackedByteData(byte[] data, long offset) { 8 | super(data); 9 | this.originalOffset = (int) offset; 10 | this.mutableOffset = 0; 11 | } 12 | 13 | @Override 14 | public void advance(long offset) { 15 | mutableOffset += offset; 16 | } 17 | 18 | @Override 19 | public long getOffset() { 20 | return mutableOffset; 21 | } 22 | 23 | @Override 24 | public ByteData getOffsetData(long offset) { 25 | return new OffsetBackedByteData(d, originalOffset + mutableOffset + offset); 26 | } 27 | 28 | @Override 29 | public OffsettingByteData getOffsettingOffsetData(long offset) { 30 | return new OffsettingBackedByteData(d, originalOffset + mutableOffset + offset); 31 | } 32 | 33 | @Override 34 | int getRealOffset(int offset) { 35 | return originalOffset + mutableOffset + offset; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/util/bytestream/OffsettingByteData.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.util.bytestream; 2 | 3 | public interface OffsettingByteData extends ByteData { 4 | void advance(long offset); 5 | long getOffset(); 6 | } 7 | -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/util/collections/CollectionUtils.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.util.collections; 2 | 3 | import java.util.Collection; 4 | import java.util.Set; 5 | 6 | public class CollectionUtils { 7 | public static String join(Collection in, String sep) { 8 | StringBuilder sb = new StringBuilder(); 9 | boolean first = true; 10 | for (Object o : in) { 11 | if (first) { 12 | first = false; 13 | } else { 14 | sb.append(sep); 15 | } 16 | sb.append(o.toString()); 17 | } 18 | return sb.toString(); 19 | } 20 | 21 | public static String joinPostFix(Collection in, String sep) { 22 | StringBuilder sb = new StringBuilder(); 23 | for (Object o : in) { 24 | sb.append(o.toString()); 25 | sb.append(sep); 26 | } 27 | return sb.toString(); 28 | } 29 | 30 | public static X getSingle(Collection a) { 31 | return a.iterator().next(); 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/util/collections/LazyExceptionRetainingMap.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.util.collections; 2 | 3 | import org.benf.cfr.reader.util.functors.UnaryFunction; 4 | 5 | import java.util.Map; 6 | 7 | public class LazyExceptionRetainingMap extends LazyMap { 8 | private final Map exceptionMap = MapFactory.newMap(); 9 | 10 | LazyExceptionRetainingMap(Map inner, UnaryFunction factory) { 11 | super(inner, factory); 12 | } 13 | 14 | @Override 15 | public Y get(Object o) { 16 | RuntimeException exception = exceptionMap.get(o); 17 | if (exception == null) { 18 | try { 19 | return super.get(o); 20 | } catch (RuntimeException e) { 21 | exception = e; 22 | //noinspection unchecked 23 | exceptionMap.put((X) o, e); 24 | } 25 | } 26 | throw exception; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/util/collections/StackFactory.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.util.collections; 2 | 3 | import java.util.Stack; 4 | 5 | public class StackFactory { 6 | public static Stack newStack() { 7 | return new Stack(); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/util/functors/BinaryFunction.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.util.functors; 2 | 3 | public interface BinaryFunction { 4 | Z invoke(X arg, Y arg2); 5 | } 6 | -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/util/functors/BinaryPredicate.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.util.functors; 2 | 3 | public interface BinaryPredicate { 4 | boolean test(X a, Y b); 5 | } 6 | -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/util/functors/BinaryProcedure.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.util.functors; 2 | 3 | public interface BinaryProcedure { 4 | void call(X arg1, Y arg2); 5 | } 6 | -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/util/functors/NonaryFunction.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.util.functors; 2 | 3 | public interface NonaryFunction { 4 | T invoke(); 5 | } 6 | -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/util/functors/Predicate.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.util.functors; 2 | 3 | public interface Predicate { 4 | boolean test(X in); 5 | } 6 | -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/util/functors/TrinaryFunction.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.util.functors; 2 | 3 | public interface TrinaryFunction { 4 | R invoke(X arg1, Y arg2, Z arg3); 5 | } 6 | -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/util/functors/UnaryFunction.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.util.functors; 2 | 3 | public interface UnaryFunction { 4 | Y invoke(X arg); 5 | } 6 | -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/util/functors/UnaryProcedure.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.util.functors; 2 | 3 | public interface UnaryProcedure { 4 | void call(T arg); 5 | } 6 | -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/util/getopt/BadParametersException.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.util.getopt; 2 | 3 | public class BadParametersException extends IllegalArgumentException { 4 | private final PermittedOptionProvider.ArgumentParam option; 5 | 6 | BadParametersException(String s, PermittedOptionProvider.ArgumentParam option) { 7 | super(s); 8 | this.option = option; 9 | } 10 | 11 | @Override 12 | public String toString() { 13 | String sb = "While processing argument '" + option.getName() + "':\n" + 14 | super.getMessage() + "\n" + 15 | "Valid argument range: " + option.getFn().getRangeDescription() + "\n"; 16 | return sb; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/util/getopt/GetOptSinkFactory.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.util.getopt; 2 | 3 | import java.util.Map; 4 | 5 | public interface GetOptSinkFactory extends PermittedOptionProvider { 6 | T create(Map opts); 7 | } 8 | -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/util/getopt/OptionDecoder.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.util.getopt; 2 | 3 | public interface OptionDecoder extends OptionDecoderParam { 4 | } 5 | 6 | -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/util/getopt/OptionDecoderParam.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.util.getopt; 2 | 3 | import org.benf.cfr.reader.util.functors.TrinaryFunction; 4 | 5 | public interface OptionDecoderParam extends TrinaryFunction { 6 | String getRangeDescription(); 7 | 8 | String getDefaultValue(); 9 | } -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/util/getopt/Options.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.util.getopt; 2 | 3 | public interface Options { 4 | 5 | boolean optionIsSet(PermittedOptionProvider.ArgumentParam option); 6 | 7 | T getOption(PermittedOptionProvider.ArgumentParam option); 8 | 9 | T getOption(PermittedOptionProvider.ArgumentParam option, A arg); 10 | } 11 | -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/util/graph/GraphVisitor.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.util.graph; 2 | 3 | import java.util.Collection; 4 | 5 | public interface GraphVisitor { 6 | 7 | void enqueue(T next); 8 | 9 | void enqueue(Collection next); 10 | 11 | void process(); 12 | 13 | void abort(); 14 | 15 | boolean wasAborted(); 16 | 17 | Collection getVisitedNodes(); 18 | } 19 | 20 | -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/util/graph/GraphVisitorFIFO.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.util.graph; 2 | 3 | import org.benf.cfr.reader.util.functors.BinaryProcedure; 4 | 5 | public class GraphVisitorFIFO extends AbstractGraphVisitorFI { 6 | public GraphVisitorFIFO(T first, BinaryProcedure> callee) { 7 | super(first, callee); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/util/output/BlockCommentState.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.util.output; 2 | 3 | enum BlockCommentState { 4 | InLine, 5 | In, 6 | Not 7 | } -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/util/output/BytecodeDumpConsumer.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.util.output; 2 | 3 | import org.benf.cfr.reader.entities.Method; 4 | 5 | import java.util.Collection; 6 | import java.util.NavigableMap; 7 | import java.util.TreeMap; 8 | 9 | public interface BytecodeDumpConsumer { 10 | interface Item { 11 | Method getMethod(); 12 | /** return a map of BYTECODE LOCATION IN METHOD to LINE NUMBER. 13 | * Note that this is ordered by BYTECODE LOCATION. 14 | **/ 15 | NavigableMap getBytecodeLocs(); 16 | } 17 | 18 | void accept(Collection items); 19 | } 20 | -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/util/output/Dumpable.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.util.output; 2 | 3 | public interface Dumpable { 4 | Dumper dump(Dumper d); 5 | } 6 | -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/util/output/DumpableWithPrecedence.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.util.output; 2 | 3 | import org.benf.cfr.reader.bytecode.analysis.parse.expression.misc.Precedence; 4 | import org.benf.cfr.reader.util.Troolean; 5 | 6 | public interface DumpableWithPrecedence extends Dumpable { 7 | 8 | Precedence getPrecedence(); 9 | 10 | Dumper dumpWithOuterPrecedence(Dumper d, Precedence outerPrecedence, Troolean isLhs); 11 | 12 | } 13 | -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/util/output/DumperFactory.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.util.output; 2 | 3 | import org.benf.cfr.reader.bytecode.analysis.types.JavaTypeInstance; 4 | import org.benf.cfr.reader.state.TypeUsageInformation; 5 | 6 | public interface DumperFactory { 7 | 8 | Dumper getNewTopLevelDumper(JavaTypeInstance classType, SummaryDumper summaryDumper, TypeUsageInformation typeUsageInformation, IllegalIdentifierDump illegalIdentifierDump); 9 | 10 | // If we support line numbers, we'll be wrapped around the top level dumper. 11 | Dumper wrapLineNoDumper(Dumper dumper); 12 | 13 | ProgressDumper getProgressDumper(); 14 | 15 | SummaryDumper getSummaryDumper(); 16 | 17 | ExceptionDumper getExceptionDumper(); 18 | 19 | DumperFactory getFactoryWithPrefix(String prefix, int version); 20 | } 21 | -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/util/output/ExceptionDumper.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.util.output; 2 | 3 | public interface ExceptionDumper { 4 | void noteException(String path, String comment, Exception e); 5 | } 6 | -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/util/output/LogFormatter.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.util.output; 2 | 3 | import java.util.logging.Formatter; 4 | import java.util.logging.LogRecord; 5 | 6 | public class LogFormatter extends Formatter { 7 | @Override 8 | public String format(LogRecord logRecord) { 9 | return logRecord.getMessage() + "\n"; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/util/output/LoggerFactory.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.util.output; 2 | 3 | import java.util.logging.*; 4 | 5 | /** 6 | * Small wrapper around the bog standard java logger. 7 | */ 8 | public class LoggerFactory { 9 | 10 | private static Handler handler = getHandler(); 11 | private static Level level = Level.WARNING; 12 | 13 | private static Handler getHandler() { 14 | Handler handler = new ConsoleHandler(); 15 | Formatter formatter = new LogFormatter(); 16 | handler.setFormatter(formatter); 17 | return handler; 18 | } 19 | 20 | public static Logger create(Class clazz) { 21 | Logger logger = Logger.getLogger(clazz.getName()); 22 | logger.setUseParentHandlers(false); 23 | logger.addHandler(handler); 24 | logger.setLevel(level); 25 | return logger; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/util/output/MethodErrorCollector.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.util.output; 2 | 3 | import org.benf.cfr.reader.bytecode.analysis.types.JavaTypeInstance; 4 | import org.benf.cfr.reader.entities.Method; 5 | 6 | public interface MethodErrorCollector { 7 | void addSummaryError(Method method, String s); 8 | 9 | static class SummaryDumperMethodErrorCollector implements MethodErrorCollector { 10 | private final JavaTypeInstance type; 11 | private final SummaryDumper summaryDumper; 12 | 13 | public SummaryDumperMethodErrorCollector(JavaTypeInstance type, SummaryDumper summaryDumper) { 14 | this.type = type; 15 | this.summaryDumper = summaryDumper; 16 | } 17 | 18 | @Override 19 | public void addSummaryError(Method method, String s) { 20 | summaryDumper.notifyError(type, method, s); 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/util/output/MovableDumperContext.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.util.output; 2 | 3 | class MovableDumperContext { 4 | BlockCommentState inBlockComment = BlockCommentState.Not; 5 | boolean atStart = true; 6 | boolean pendingCR = false; 7 | int indent; 8 | int outputCount = 0; 9 | int currentLine = 1; // lines are 1 based. Sigh. 10 | } 11 | -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/util/output/NopSummaryDumper.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.util.output; 2 | 3 | import org.benf.cfr.reader.bytecode.analysis.types.JavaTypeInstance; 4 | import org.benf.cfr.reader.entities.Method; 5 | 6 | public class NopSummaryDumper implements SummaryDumper { 7 | 8 | @Override 9 | public void notify(String message) { 10 | } 11 | 12 | @Override 13 | public void notifyError(JavaTypeInstance controllingType, Method method, String error) { 14 | } 15 | 16 | @Override 17 | public void close() { 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/util/output/ProgressDumper.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.util.output; 2 | 3 | import org.benf.cfr.reader.bytecode.analysis.types.JavaTypeInstance; 4 | 5 | public interface ProgressDumper { 6 | void analysingType(JavaTypeInstance type); 7 | void analysingPath(String path); 8 | } 9 | -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/util/output/ProgressDumperNop.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.util.output; 2 | 3 | import org.benf.cfr.reader.bytecode.analysis.types.JavaTypeInstance; 4 | 5 | public class ProgressDumperNop implements ProgressDumper { 6 | public static final ProgressDumper INSTANCE = new ProgressDumperNop(); 7 | 8 | private ProgressDumperNop() {} 9 | 10 | @Override 11 | public void analysingType(JavaTypeInstance type) { 12 | } 13 | 14 | @Override 15 | public void analysingPath(String path) { 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/util/output/ProgressDumperStdErr.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.util.output; 2 | 3 | import org.benf.cfr.reader.bytecode.analysis.types.JavaTypeInstance; 4 | import org.benf.cfr.reader.util.getopt.OptionsImpl; 5 | 6 | public class ProgressDumperStdErr implements ProgressDumper { 7 | 8 | @Override 9 | public void analysingType(JavaTypeInstance type) { 10 | System.err.println("Processing " + type.getRawName()); 11 | } 12 | 13 | @Override 14 | public void analysingPath(String path) { 15 | System.err.println("Processing " + path + " (use " + OptionsImpl.SILENT.getName() + " to silence)"); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/util/output/SinkSummaryDumper.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.util.output; 2 | 3 | import org.benf.cfr.reader.api.OutputSinkFactory; 4 | import org.benf.cfr.reader.bytecode.analysis.types.JavaTypeInstance; 5 | import org.benf.cfr.reader.entities.Method; 6 | 7 | public class SinkSummaryDumper implements SummaryDumper { 8 | private final OutputSinkFactory.Sink sink; 9 | 10 | private transient JavaTypeInstance lastControllingType = null; 11 | private transient Method lastMethod = null; 12 | 13 | SinkSummaryDumper(OutputSinkFactory.Sink sink) { 14 | this.sink = sink; 15 | } 16 | 17 | @Override 18 | public void notify(String message) { 19 | sink.write(message + "\n"); 20 | } 21 | 22 | @Override 23 | public void notifyError(JavaTypeInstance controllingType, Method method, String error) { 24 | if (lastControllingType != controllingType) { 25 | lastControllingType = controllingType; 26 | lastMethod = null; 27 | sink.write("\n\n" + controllingType.getRawName() + "\n----------------------------\n\n"); 28 | } 29 | if (method != lastMethod) { 30 | sink.write(method.getMethodPrototype().toString() + "\n"); 31 | lastMethod = method; 32 | } 33 | sink.write(" " + error + "\n"); 34 | } 35 | 36 | @Override 37 | public void close() { 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/util/output/StdErrExceptionDumper.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.util.output; 2 | 3 | import org.benf.cfr.reader.util.CannotLoadClassException; 4 | 5 | public class StdErrExceptionDumper implements ExceptionDumper { 6 | @Override 7 | public void noteException(String path, String comment, Exception e) { 8 | if (comment != null) { 9 | System.err.println(comment); 10 | } 11 | if (e instanceof CannotLoadClassException) { 12 | System.err.println("Can't load the class specified:"); 13 | System.err.println(e.toString()); 14 | } else { 15 | System.err.println(e.toString()); 16 | for (Object x : e.getStackTrace()) { 17 | System.err.println(x); 18 | } 19 | } 20 | 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/util/output/SummaryDumper.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.util.output; 2 | 3 | import org.benf.cfr.reader.bytecode.analysis.types.JavaTypeInstance; 4 | import org.benf.cfr.reader.entities.Method; 5 | 6 | public interface SummaryDumper { 7 | void notify(String message); 8 | 9 | void notifyError(JavaTypeInstance controllingType, Method method, String error); 10 | 11 | void close(); 12 | } 13 | -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/util/output/TypeContext.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.util.output; 2 | 3 | public enum TypeContext { 4 | None, // Nothing worth noting. 5 | Static; 6 | } 7 | -------------------------------------------------------------------------------- /src/org/benf/cfr/reader/util/output/TypeOverridingDumper.java: -------------------------------------------------------------------------------- 1 | package org.benf.cfr.reader.util.output; 2 | 3 | import org.benf.cfr.reader.bytecode.analysis.types.JavaTypeInstance; 4 | import org.benf.cfr.reader.state.TypeUsageInformation; 5 | 6 | public class TypeOverridingDumper extends DelegatingDumper { 7 | private final TypeUsageInformation typeUsageInformation; 8 | 9 | TypeOverridingDumper(Dumper delegate, TypeUsageInformation typeUsageInformation) { 10 | super(delegate); 11 | this.typeUsageInformation = typeUsageInformation; 12 | } 13 | 14 | @Override 15 | public TypeUsageInformation getTypeUsageInformation() { 16 | return typeUsageInformation; 17 | } 18 | 19 | @Override 20 | public Dumper dump(JavaTypeInstance javaTypeInstance) { 21 | return dump(javaTypeInstance, TypeContext.None); 22 | } 23 | 24 | @Override 25 | public Dumper dump(JavaTypeInstance javaTypeInstance, TypeContext typeContext) { 26 | javaTypeInstance.dumpInto(this, typeUsageInformation, typeContext); 27 | return this; 28 | } 29 | 30 | @Override 31 | public Dumper withTypeUsageInformation(TypeUsageInformation innerclassTypeUsageInformation) { 32 | return new TypeOverridingDumper(delegate, innerclassTypeUsageInformation); 33 | } 34 | } 35 | --------------------------------------------------------------------------------