public override TextBuffer ToJava(int indent, BytecodeMappingTracer tracer) { TextBuffer buffer = new TextBuffer(); tracer.AddMapping(bytecode); if (classDef) { ClassesProcessor.ClassNode child = DecompilerContext.GetClassProcessor().GetMapRootClasses ().GetOrNull(varType.value); new ClassWriter().ClassToJava(child, buffer, indent, tracer); tracer.IncrementCurrentSourceLine(buffer.CountLines()); } else { VarVersionPair varVersion = GetVarVersionPair(); string name = null; if (processor != null) { name = processor.GetVarName(varVersion); } if (definition) { if (processor != null && processor.GetVarFinal(varVersion) == VarTypeProcessor.Var_Explicit_Final) { buffer.Append("final "); } AppendDefinitionType(buffer); buffer.Append(" "); } buffer.Append(name == null ? ("var" + index + (this.version == 0 ? string.Empty : "_" + this.version)) : name); } return(buffer); }
private static bool IsQualifiedNewGetClass(Exprent first, Exprent second) { if (first.type == Exprent.Exprent_Invocation) { InvocationExprent invocation = (InvocationExprent)first; if (!invocation.IsStatic() && invocation.GetInstance().type == Exprent.Exprent_Var && invocation.GetName().Equals("getClass") && invocation.GetStringDescriptor(). Equals("()Ljava/lang/Class;")) { List <Exprent> lstExprents = second.GetAllExprents(); lstExprents.Add(second); foreach (Exprent expr in lstExprents) { if (expr.type == Exprent.Exprent_New) { NewExprent newExpr = (NewExprent)expr; if (newExpr.GetConstructor() != null && !(newExpr.GetConstructor().GetLstParameters ().Count == 0) && newExpr.GetConstructor().GetLstParameters()[0].Equals(invocation .GetInstance())) { string classname = newExpr.GetNewType().value; ClassesProcessor.ClassNode node = DecompilerContext.GetClassProcessor().GetMapRootClasses ().GetOrNull(classname); if (node != null && node.type != ClassesProcessor.ClassNode.Class_Root) { return(true); } } } } } } return(false); }
private static Exprent IsLambda(Exprent exprent, StructClass cl) { List <Exprent> lst = exprent.GetAllExprents(); foreach (Exprent expr in lst) { Exprent ret = IsLambda(expr, cl); if (ret != null) { exprent.ReplaceExprent(expr, ret); } } if (exprent.type == Exprent.Exprent_Invocation) { InvocationExprent @in = (InvocationExprent)exprent; if (@in.GetInvocationTyp() == InvocationExprent.Invoke_Dynamic) { string lambda_class_name = cl.qualifiedName + @in.GetInvokeDynamicClassSuffix(); ClassesProcessor.ClassNode lambda_class = DecompilerContext.GetClassProcessor().GetMapRootClasses ().GetOrNull(lambda_class_name); if (lambda_class != null) { // real lambda class found, replace invocation with an anonymous class NewExprent newExpr = new NewExprent(new VarType(lambda_class_name, true), null, 0 , @in.bytecode); newExpr.SetConstructor(@in); // note: we don't set the instance to null with in.setInstance(null) like it is done for a common constructor invocation // lambda can also be a reference to a virtual method (e.g. String x; ...(x::toString);) // in this case instance will hold the corresponding object return(newExpr); } } } return(null); }
public static List <VarVersionPair> GetSyntheticParametersMask(string className, string descriptor, int parameters) { ClassesProcessor.ClassNode node = DecompilerContext.GetClassProcessor().GetMapRootClasses ().GetOrNull(className); return(node != null?GetSyntheticParametersMask(node, descriptor, parameters) : null); }
private static string GetQualifiedNewInstance(string classname, List <Exprent> lstParams , int indent, BytecodeMappingTracer tracer) { ClassesProcessor.ClassNode node = DecompilerContext.GetClassProcessor().GetMapRootClasses ().GetOrNull(classname); if (node != null && node.type != ClassesProcessor.ClassNode.Class_Root && node.type != ClassesProcessor.ClassNode.Class_Local && (node.access & ICodeConstants.Acc_Static ) == 0) { if (!(lstParams.Count == 0)) { Exprent enclosing = lstParams[0]; bool isQualifiedNew = false; if (enclosing.type == Exprent.Exprent_Var) { VarExprent varEnclosing = (VarExprent)enclosing; StructClass current_class = ((ClassesProcessor.ClassNode)DecompilerContext.GetProperty (DecompilerContext.Current_Class_Node)).classStruct; string this_classname = varEnclosing.GetProcessor().GetThisVars().GetOrNull(new VarVersionPair (varEnclosing)); if (!current_class.qualifiedName.Equals(this_classname)) { isQualifiedNew = true; } } else { isQualifiedNew = true; } if (isQualifiedNew) { return(enclosing.ToJava(indent, tracer).ToString()); } } } return(null); }
public NewExprent(VarType newType, List <Exprent> lstDims, HashSet <int> bytecodeOffsets ) : base(Exprent_New) { this.newType = newType; this.lstDims = lstDims; anonymous = false; lambda = false; if (newType.type == ICodeConstants.Type_Object && newType.arrayDim == 0) { ClassesProcessor.ClassNode node = DecompilerContext.GetClassProcessor().GetMapRootClasses ().GetOrNull(newType.value); if (node != null && (node.type == ClassesProcessor.ClassNode.Class_Anonymous || node .type == ClassesProcessor.ClassNode.Class_Lambda)) { anonymous = true; if (node.type == ClassesProcessor.ClassNode.Class_Lambda) { lambda = true; } } } AddBytecodeOffsets(bytecodeOffsets); }
public static void Simplify(SwitchStatement switchStatement) { SwitchExprent switchExprent = (SwitchExprent)switchStatement.GetHeadexprent(); Exprent value = switchExprent.GetValue(); if (IsEnumArray(value)) { List <List <Exprent> > caseValues = switchStatement.GetCaseValues(); Dictionary <Exprent, Exprent> mapping = new Dictionary <Exprent, Exprent>(caseValues .Count); ArrayExprent array = (ArrayExprent)value; FieldExprent arrayField = (FieldExprent)array.GetArray(); ClassesProcessor.ClassNode classNode = DecompilerContext.GetClassProcessor().GetMapRootClasses ().GetOrNull(arrayField.GetClassname()); if (classNode != null) { MethodWrapper wrapper = classNode.GetWrapper().GetMethodWrapper(ICodeConstants.Clinit_Name , "()V"); if (wrapper != null && wrapper.root != null) { wrapper.GetOrBuildGraph().IterateExprents((Exprent exprent) => { if (exprent is AssignmentExprent) { AssignmentExprent assignment = (AssignmentExprent)exprent; Exprent left = assignment.GetLeft(); if (left.type == Exprent.Exprent_Array && ((ArrayExprent)left).GetArray().Equals( arrayField)) { Sharpen.Collections.Put(mapping, assignment.GetRight(), ((InvocationExprent)((ArrayExprent )left).GetIndex()).GetInstance()); } } return(0); } ); } } List <List <Exprent> > realCaseValues = new List <List <Exprent> >(caseValues.Count); foreach (List <Exprent> caseValue in caseValues) { List <Exprent> values = new List <Exprent>(caseValue.Count); realCaseValues.Add(values); foreach (Exprent exprent in caseValue) { if (exprent == null) { values.Add(null); } else { Exprent realConst = mapping.GetOrNull(exprent); if (realConst == null) { DecompilerContext.GetLogger().WriteMessage("Unable to simplify switch on enum: " + exprent + " not found, available: " + mapping, IFernflowerLogger.Severity.Error ); return; } values.Add(realConst.Copy()); } } } caseValues.Clear(); Sharpen.Collections.AddAll(caseValues, realCaseValues); switchExprent.ReplaceExprent(value, ((InvocationExprent)array.GetIndex()).GetInstance ().Copy()); } }
private Exprent ReplaceAccessExprent(ClassesProcessor.ClassNode caller, MethodWrapper methdest, InvocationExprent invexpr) { ClassesProcessor.ClassNode node = DecompilerContext.GetClassProcessor().GetMapRootClasses ().GetOrNull(invexpr.GetClassname()); MethodWrapper methsource = null; if (node != null && node.GetWrapper() != null) { methsource = node.GetWrapper().GetMethodWrapper(invexpr.GetName(), invexpr.GetStringDescriptor ()); } if (methsource == null || !mapMethodType.ContainsKey(methsource)) { return(null); } // if same method, return if (node.classStruct.qualifiedName.Equals(caller.classStruct.qualifiedName) && methsource .methodStruct.GetName().Equals(methdest.methodStruct.GetName()) && methsource.methodStruct .GetDescriptor().Equals(methdest.methodStruct.GetDescriptor())) { // no recursive invocations permitted! return(null); } NestedMemberAccess.MethodAccess type = mapMethodType.GetOrNull(methsource); // // FIXME: impossible case. MethodAccess.NORMAL is not saved in the map // if(type == MethodAccess.NORMAL) { // return null; // } if (!SameTree(caller, node)) { return(null); } DirectGraph graph = methsource.GetOrBuildGraph(); Exprent source = graph.first.exprents[0]; Exprent retexprent = null; switch (type.ordinal()) { case 1: { ExitExprent exsource = (ExitExprent)source; if (exsource.GetValue().type == Exprent.Exprent_Var) { // qualified this VarExprent var = (VarExprent)exsource.GetValue(); string varname = methsource.varproc.GetVarName(new VarVersionPair(var)); if (!methdest.setOuterVarNames.Contains(varname)) { VarNamesCollector vnc = new VarNamesCollector(); vnc.AddName(varname); methdest.varproc.RefreshVarNames(vnc); methdest.setOuterVarNames.Add(varname); } int index = methdest.counter.GetCounterAndIncrement(CounterContainer.Var_Counter); VarExprent ret = new VarExprent(index, var.GetVarType(), methdest.varproc); methdest.varproc.SetVarName(new VarVersionPair(index, 0), varname); retexprent = ret; } else { // field FieldExprent ret = (FieldExprent)exsource.GetValue().Copy(); if (!ret.IsStatic()) { ret.ReplaceExprent(ret.GetInstance(), invexpr.GetLstParameters()[0]); } retexprent = ret; } break; } case 2: { AssignmentExprent ret_1; if (source.type == Exprent.Exprent_Exit) { ExitExprent extex = (ExitExprent)source; ret_1 = (AssignmentExprent)extex.GetValue().Copy(); } else { ret_1 = (AssignmentExprent)source.Copy(); } FieldExprent fexpr = (FieldExprent)ret_1.GetLeft(); if (fexpr.IsStatic()) { ret_1.ReplaceExprent(ret_1.GetRight(), invexpr.GetLstParameters()[0]); } else { ret_1.ReplaceExprent(ret_1.GetRight(), invexpr.GetLstParameters()[1]); fexpr.ReplaceExprent(fexpr.GetInstance(), invexpr.GetLstParameters()[0]); } // do not use copied bytecodes ret_1.GetLeft().bytecode = null; ret_1.GetRight().bytecode = null; retexprent = ret_1; break; } case 4: { retexprent = ReplaceFunction(invexpr, source); break; } case 3: { if (source.type == Exprent.Exprent_Exit) { source = ((ExitExprent)source).GetValue(); } InvocationExprent invret = (InvocationExprent)source.Copy(); int index_1 = 0; if (!invret.IsStatic()) { invret.ReplaceExprent(invret.GetInstance(), invexpr.GetLstParameters()[0]); index_1 = 1; } for (int i = 0; i < invret.GetLstParameters().Count; i++) { invret.ReplaceExprent(invret.GetLstParameters()[i], invexpr.GetLstParameters()[i + index_1]); } retexprent = invret; break; } } if (retexprent != null) { // preserve original bytecodes retexprent.bytecode = null; retexprent.AddBytecodeOffsets(invexpr.bytecode); // hide synthetic access method bool hide = true; if (node.type == ClassesProcessor.ClassNode.Class_Root || (node.access & ICodeConstants .Acc_Static) != 0) { StructMethod mt = methsource.methodStruct; if (!mt.IsSynthetic()) { hide = false; } } if (hide) { node.GetWrapper().GetHiddenMembers().Add(InterpreterUtil.MakeUniqueKey(invexpr.GetName (), invexpr.GetStringDescriptor())); } } return(retexprent); }
public virtual string GetShortName(string fullName, bool imported) { ClassesProcessor.ClassNode node = DecompilerContext.GetClassProcessor().GetMapRootClasses ().GetOrNull(fullName.Replace('.', '/')); //todo[r.sh] anonymous classes? string result = null; if (node != null && node.classStruct.IsOwn()) { result = node.simpleName; while (node.parent != null && node.type == ClassesProcessor.ClassNode.Class_Member ) { //noinspection StringConcatenationInLoop result = node.parent.simpleName + '.' + result; node = node.parent; } if (node.type == ClassesProcessor.ClassNode.Class_Root) { fullName = node.classStruct.qualifiedName; fullName = fullName.Replace('/', '.'); } else { return(result); } } else { fullName = fullName.Replace('$', '.'); } string shortName = fullName; string packageName = string.Empty; int lastDot = fullName.LastIndexOf('.'); if (lastDot >= 0) { shortName = Sharpen.Runtime.Substring(fullName, lastDot + 1); packageName = Sharpen.Runtime.Substring(fullName, 0, lastDot); } StructContext context = DecompilerContext.GetStructContext(); // check for another class which could 'shadow' this one. Three cases: // 1) class with the same short name in the current package // 2) class with the same short name in the default package // 3) inner class with the same short name in the current class, a super class, or an implemented interface bool existsDefaultClass = (context.GetClass(currentPackageSlash + shortName) != null && !packageName.Equals(currentPackagePoint)) || (context.GetClass(shortName) != null && !(currentPackagePoint.Length == 0)) || setInnerClassNames.Contains(shortName ); // current package // default package // inner class if (existsDefaultClass || (mapSimpleNames.ContainsKey(shortName) && !packageName. Equals(mapSimpleNames.GetOrNull(shortName)))) { // don't return full name because if the class is a inner class, full name refers to the parent full name, not the child full name return(result == null ? fullName : (packageName + "." + result)); } else if (!mapSimpleNames.ContainsKey(shortName)) { Sharpen.Collections.Put(mapSimpleNames, shortName, packageName); if (!imported) { setNotImportedNames.Add(shortName); } } return(result == null ? shortName : result); }
public override TextBuffer ToJava(int indent, BytecodeMappingTracer tracer) { TextBuffer buf = new TextBuffer(); string super_qualifier = null; bool isInstanceThis = false; tracer.AddMapping(bytecode); if (instance is InvocationExprent) { ((InvocationExprent)instance).MarkUsingBoxingResult(); } if (isStatic__) { if (IsBoxingCall() && canIgnoreBoxing) { // process general "boxing" calls, e.g. 'Object[] data = { true }' or 'Byte b = 123' // here 'byte' and 'short' values do not need an explicit narrowing type cast ExprProcessor.GetCastedExprent(lstParameters[0], descriptor.@params[0], buf, indent , false, false, false, false, tracer); return(buf); } ClassesProcessor.ClassNode node = (ClassesProcessor.ClassNode)DecompilerContext.GetProperty (DecompilerContext.Current_Class_Node); if (node == null || !classname.Equals(node.classStruct.qualifiedName)) { buf.Append(DecompilerContext.GetImportCollector().GetShortNameInClassContext(ExprProcessor .BuildJavaClassName(classname))); } } else { if (instance != null && instance.type == Exprent.Exprent_Var) { VarExprent instVar = (VarExprent)instance; VarVersionPair varPair = new VarVersionPair(instVar); VarProcessor varProc = instVar.GetProcessor(); if (varProc == null) { MethodWrapper currentMethod = (MethodWrapper)DecompilerContext.GetProperty(DecompilerContext .Current_Method_Wrapper); if (currentMethod != null) { varProc = currentMethod.varproc; } } string this_classname = null; if (varProc != null) { this_classname = varProc.GetThisVars().GetOrNull(varPair); } if (this_classname != null) { isInstanceThis = true; if (invocationTyp == Invoke_Special) { if (!classname.Equals(this_classname)) { // TODO: direct comparison to the super class? StructClass cl = DecompilerContext.GetStructContext().GetClass(classname); bool isInterface = cl != null && cl.HasModifier(ICodeConstants.Acc_Interface); super_qualifier = !isInterface ? this_classname : classname; } } } } if (functype == Typ_General) { if (super_qualifier != null) { TextUtil.WriteQualifiedSuper(buf, super_qualifier); } else if (instance != null) { TextBuffer res = instance.ToJava(indent, tracer); if (IsUnboxingCall()) { // we don't print the unboxing call - no need to bother with the instance wrapping / casting buf.Append(res); return(buf); } VarType rightType = instance.GetExprType(); VarType leftType = new VarType(ICodeConstants.Type_Object, 0, classname); if (rightType.Equals(VarType.Vartype_Object) && !leftType.Equals(rightType)) { buf.Append("((").Append(ExprProcessor.GetCastTypeName(leftType)).Append(")"); if (instance.GetPrecedence() >= FunctionExprent.GetPrecedence(FunctionExprent.Function_Cast )) { res.Enclose("(", ")"); } buf.Append(res).Append(")"); } else if (instance.GetPrecedence() > GetPrecedence()) { buf.Append("(").Append(res).Append(")"); } else { buf.Append(res); } } } } switch (functype) { case Typ_General: { if (VarExprent.Var_Nameless_Enclosure.Equals(buf.ToString())) { buf = new TextBuffer(); } if (buf.Length() > 0) { buf.Append("."); } buf.Append(name); if (invocationTyp == Invoke_Dynamic) { buf.Append("<invokedynamic>"); } buf.Append("("); break; } case Typ_Clinit: { throw new Exception("Explicit invocation of " + ICodeConstants.Clinit_Name); } case Typ_Init: { if (super_qualifier != null) { buf.Append("super("); } else if (isInstanceThis) { buf.Append("this("); } else if (instance != null) { buf.Append(instance.ToJava(indent, tracer)).Append(".<init>("); } else { throw new Exception("Unrecognized invocation of " + ICodeConstants.Init_Name); } break; } } List <VarVersionPair> mask = null; bool isEnum = false; if (functype == Typ_Init) { ClassesProcessor.ClassNode newNode = DecompilerContext.GetClassProcessor().GetMapRootClasses ().GetOrNull(classname); if (newNode != null) { mask = ExprUtil.GetSyntheticParametersMask(newNode, stringDescriptor, lstParameters .Count); isEnum = newNode.classStruct.HasModifier(ICodeConstants.Acc_Enum) && DecompilerContext .GetOption(IFernflowerPreferences.Decompile_Enum); } } BitSet setAmbiguousParameters = GetAmbiguousParameters(); // omit 'new Type[] {}' for the last parameter of a vararg method call if (lstParameters.Count == [email protected] && IsVarArgCall()) { Exprent lastParam = lstParameters[lstParameters.Count - 1]; if (lastParam.type == Exprent_New && lastParam.GetExprType().arrayDim >= 1) { ((NewExprent)lastParam).SetVarArgParam(true); } } bool firstParameter = true; int start = isEnum ? 2 : 0; for (int i = start; i < lstParameters.Count; i++) { if (mask == null || mask[i] == null) { TextBuffer buff = new TextBuffer(); bool ambiguous = setAmbiguousParameters.Get(i); // 'byte' and 'short' literals need an explicit narrowing type cast when used as a parameter ExprProcessor.GetCastedExprent(lstParameters[i], descriptor.@params[i], buff, indent , true, ambiguous, true, true, tracer); // the last "new Object[0]" in the vararg call is not printed if (buff.Length() > 0) { if (!firstParameter) { buf.Append(", "); } buf.Append(buff); } firstParameter = false; } } buf.Append(')'); return(buf); }
public override VarType GetExprType() { return(anonymous ? DecompilerContext.GetClassProcessor().GetMapRootClasses().GetOrNull (newType.value).anonymousClassType : newType); }
private static bool ProbablySyntheticParameter(string className) { ClassesProcessor.ClassNode node = DecompilerContext.GetClassProcessor().GetMapRootClasses ().GetOrNull(className); return(node != null && node.type == ClassesProcessor.ClassNode.Class_Anonymous); }
// precedence of new public override TextBuffer ToJava(int indent, BytecodeMappingTracer tracer) { TextBuffer buf = new TextBuffer(); if (anonymous) { ClassesProcessor.ClassNode child = DecompilerContext.GetClassProcessor().GetMapRootClasses ().GetOrNull(newType.value); // IDEA-204310 - avoid backtracking later on for lambdas (causes spurious imports) if (!enumConst && (!lambda || DecompilerContext.GetOption(IFernflowerPreferences .Lambda_To_Anonymous_Class))) { string enclosing = null; if (!lambda && constructor != null) { enclosing = GetQualifiedNewInstance(child.anonymousClassType.value, constructor.GetLstParameters (), indent, tracer); if (enclosing != null) { buf.Append(enclosing).Append('.'); } } buf.Append("new "); string typename = ExprProcessor.GetCastTypeName(child.anonymousClassType); if (enclosing != null) { ClassesProcessor.ClassNode anonymousNode = DecompilerContext.GetClassProcessor(). GetMapRootClasses().GetOrNull(child.anonymousClassType.value); if (anonymousNode != null) { typename = anonymousNode.simpleName; } else { typename = Sharpen.Runtime.Substring(typename, typename.LastIndexOf('.') + 1); } } GenericClassDescriptor descriptor = ClassWriter.GetGenericClassDescriptor(child.classStruct ); if (descriptor != null) { if ((descriptor.superinterfaces.Count == 0)) { buf.Append(GenericMain.GetGenericCastTypeName(descriptor.superclass)); } else { if (descriptor.superinterfaces.Count > 1 && !lambda) { DecompilerContext.GetLogger().WriteMessage("Inconsistent anonymous class signature: " + child.classStruct.qualifiedName, IFernflowerLogger.Severity.Warn); } buf.Append(GenericMain.GetGenericCastTypeName(descriptor.superinterfaces[0])); } } else { buf.Append(typename); } } buf.Append('('); if (!lambda && constructor != null) { List <Exprent> parameters = constructor.GetLstParameters(); List <VarVersionPair> mask = child.GetWrapper().GetMethodWrapper(ICodeConstants.Init_Name , constructor.GetStringDescriptor()).synthParameters; if (mask == null) { InvocationExprent superCall = child.superInvocation; mask = ExprUtil.GetSyntheticParametersMask(superCall.GetClassname(), superCall.GetStringDescriptor (), parameters.Count); } int start = enumConst ? 2 : 0; bool firstParam = true; for (int i = start; i < parameters.Count; i++) { if (mask == null || mask[i] == null) { if (!firstParam) { buf.Append(", "); } ExprProcessor.GetCastedExprent(parameters[i], constructor.GetDescriptor().@params [i], buf, indent, true, tracer); firstParam = false; } } } buf.Append(')'); if (enumConst && buf.Length() == 2) { buf.SetLength(0); } if (lambda) { if (!DecompilerContext.GetOption(IFernflowerPreferences.Lambda_To_Anonymous_Class )) { buf.SetLength(0); } // remove the usual 'new <class>()', it will be replaced with lambda style '() ->' Exprent methodObject = constructor == null ? null : constructor.GetInstance(); TextBuffer clsBuf = new TextBuffer(); new ClassWriter().ClassLambdaToJava(child, clsBuf, methodObject, indent, tracer); buf.Append(clsBuf); tracer.IncrementCurrentSourceLine(clsBuf.CountLines()); } else { TextBuffer clsBuf = new TextBuffer(); new ClassWriter().ClassToJava(child, clsBuf, indent, tracer); buf.Append(clsBuf); tracer.IncrementCurrentSourceLine(clsBuf.CountLines()); } } else if (directArrayInit) { VarType leftType = newType.DecreaseArrayDim(); buf.Append('{'); for (int i = 0; i < lstArrayElements.Count; i++) { if (i > 0) { buf.Append(", "); } ExprProcessor.GetCastedExprent(lstArrayElements[i], leftType, buf, indent, false, tracer); } buf.Append('}'); } else if (newType.arrayDim == 0) { if (!enumConst) { string enclosing = null; if (constructor != null) { enclosing = GetQualifiedNewInstance(newType.value, constructor.GetLstParameters() , indent, tracer); if (enclosing != null) { buf.Append(enclosing).Append('.'); } } buf.Append("new "); string typename = ExprProcessor.GetTypeName(newType); if (enclosing != null) { ClassesProcessor.ClassNode newNode = DecompilerContext.GetClassProcessor().GetMapRootClasses ().GetOrNull(newType.value); if (newNode != null) { typename = newNode.simpleName; } else { typename = Sharpen.Runtime.Substring(typename, typename.LastIndexOf('.') + 1); } } buf.Append(typename); } if (constructor != null) { List <Exprent> parameters = constructor.GetLstParameters(); List <VarVersionPair> mask = ExprUtil.GetSyntheticParametersMask(constructor.GetClassname (), constructor.GetStringDescriptor(), parameters.Count); int start = enumConst ? 2 : 0; if (!enumConst || start < parameters.Count) { buf.Append('('); bool firstParam = true; for (int i = start; i < parameters.Count; i++) { if (mask == null || mask[i] == null) { Exprent expr = parameters[i]; VarType leftType = constructor.GetDescriptor().@params[i]; if (i == parameters.Count - 1 && expr.GetExprType() == VarType.Vartype_Null && ProbablySyntheticParameter (leftType.value)) { break; } // skip last parameter of synthetic constructor call if (!firstParam) { buf.Append(", "); } ExprProcessor.GetCastedExprent(expr, leftType, buf, indent, true, false, true, true , tracer); firstParam = false; } } buf.Append(')'); } } } else if (isVarArgParam) { // just print the array elements VarType leftType = newType.DecreaseArrayDim(); for (int i = 0; i < lstArrayElements.Count; i++) { if (i > 0) { buf.Append(", "); } // new String[][]{{"abc"}, {"DEF"}} => new String[]{"abc"}, new String[]{"DEF"} Exprent element = lstArrayElements[i]; if (element.type == Exprent_New) { ((NewExprent)element).SetDirectArrayInit(false); } ExprProcessor.GetCastedExprent(element, leftType, buf, indent, false, tracer); } // if there is just one element of Object[] type it needs to be casted to resolve ambiguity if (lstArrayElements.Count == 1) { VarType elementType = lstArrayElements[0].GetExprType(); if (elementType.type == ICodeConstants.Type_Object && elementType.value.Equals("java/lang/Object" ) && elementType.arrayDim >= 1) { buf.Prepend("(Object)"); } } } else { buf.Append("new ").Append(ExprProcessor.GetTypeName(newType)); if ((lstArrayElements.Count == 0)) { for (int i = 0; i < newType.arrayDim; i++) { buf.Append('['); if (i < lstDims.Count) { buf.Append(lstDims[i].ToJava(indent, tracer)); } buf.Append(']'); } } else { for (int i = 0; i < newType.arrayDim; i++) { buf.Append("[]"); } VarType leftType = newType.DecreaseArrayDim(); buf.Append('{'); for (int i = 0; i < lstArrayElements.Count; i++) { if (i > 0) { buf.Append(", "); } ExprProcessor.GetCastedExprent(lstArrayElements[i], leftType, buf, indent, false, tracer); } buf.Append('}'); } } return(buf); }
/// <exception cref="IOException"/> public virtual void ProcessClass(ClassesProcessor.ClassNode node) { foreach (ClassesProcessor.ClassNode child in node.nested) { ProcessClass(child); } ClassesProcessor clProcessor = DecompilerContext.GetClassProcessor(); StructClass cl = node.classStruct; if (cl.GetBytecodeVersion() < ICodeConstants.Bytecode_Java_8) { // lambda beginning with Java 8 return; } StructBootstrapMethodsAttribute bootstrap = cl.GetAttribute(StructGeneralAttribute .Attribute_Bootstrap_Methods); if (bootstrap == null || bootstrap.GetMethodsNumber() == 0) { return; } // no bootstrap constants in pool BitSet lambda_methods = new BitSet(); // find lambda bootstrap constants for (int i = 0; i < bootstrap.GetMethodsNumber(); ++i) { LinkConstant method_ref = bootstrap.GetMethodReference(i); // method handle // FIXME: extend for Eclipse etc. at some point if (Javac_Lambda_Class.Equals(method_ref.classname) && (Javac_Lambda_Method.Equals (method_ref.elementname) || Javac_Lambda_Alt_Method.Equals(method_ref.elementname ))) { lambda_methods.Set(i); } } if (lambda_methods.IsEmpty()) { return; } // no lambda bootstrap constant found Dictionary <string, string> mapMethodsLambda = new Dictionary <string, string>(); // iterate over code and find invocations of bootstrap methods. Replace them with anonymous classes. foreach (StructMethod mt in cl.GetMethods()) { mt.ExpandData(); InstructionSequence seq = mt.GetInstructionSequence(); if (seq != null && seq.Length() > 0) { int len = seq.Length(); for (int i = 0; i < len; ++i) { Instruction instr = seq.GetInstr(i); if (instr.opcode == ICodeConstants.opc_invokedynamic) { LinkConstant invoke_dynamic = cl.GetPool().GetLinkConstant(instr.Operand(0)); if (lambda_methods.Get(invoke_dynamic.index1)) { // lambda invocation found List <PooledConstant> bootstrap_arguments = bootstrap.GetMethodArguments(invoke_dynamic .index1); MethodDescriptor md = MethodDescriptor.ParseDescriptor(invoke_dynamic.descriptor); string lambda_class_name = md.ret.value; string lambda_method_name = invoke_dynamic.elementname; string lambda_method_descriptor = ((PrimitiveConstant)bootstrap_arguments[2]).GetString (); // method type LinkConstant content_method_handle = (LinkConstant)bootstrap_arguments[1]; ClassesProcessor.ClassNode node_lambda = new ClassesProcessor.ClassNode(content_method_handle .classname, content_method_handle.elementname, content_method_handle.descriptor, content_method_handle.index1, lambda_class_name, lambda_method_name, lambda_method_descriptor , cl); node_lambda.simpleName = cl.qualifiedName + "##Lambda_" + invoke_dynamic.index1 + "_" + invoke_dynamic.index2; node_lambda.enclosingMethod = InterpreterUtil.MakeUniqueKey(mt.GetName(), mt.GetDescriptor ()); node.nested.Add(node_lambda); node_lambda.parent = node; Sharpen.Collections.Put(clProcessor.GetMapRootClasses(), node_lambda.simpleName, node_lambda); if (!node_lambda.lambdaInformation.is_method_reference) { Sharpen.Collections.Put(mapMethodsLambda, node_lambda.lambdaInformation.content_method_key , node_lambda.simpleName); } } } } } mt.ReleaseResources(); } // build class hierarchy on lambda foreach (ClassesProcessor.ClassNode nd in node.nested) { if (nd.type == ClassesProcessor.ClassNode.Class_Lambda) { string parent_class_name = mapMethodsLambda.GetOrNull(nd.enclosingMethod); if (parent_class_name != null) { ClassesProcessor.ClassNode parent_class = clProcessor.GetMapRootClasses().GetOrNull (parent_class_name); parent_class.nested.Add(nd); nd.parent = parent_class; } } } }