AS3 direct edit: trait imports refactoring, function traits

This commit is contained in:
Jindra Petřík
2015-11-09 21:18:35 +01:00
parent c4748e8026
commit 7fdca1992a
7 changed files with 413 additions and 353 deletions

View File

@@ -834,36 +834,40 @@ public class ActionScript3Parser {
}
constr = (method(isPrivate, metadata, pkg, false, customAccess, new Reference<>(false), importedClasses, false, false, thisType, openedNamespaces, false, namespace, "", true, constrVariables));
} else {
MethodAVM2Item ft = method(isPrivate, metadata, pkg, isInterface, customAccess, new Reference<>(false), importedClasses, isOverride, isFinal, thisType, openedNamespaces, isStatic, namespace, fname, true, new ArrayList<>());
if (isGetter) {
if (!ft.paramTypes.isEmpty()) {
throw new AVM2ParseException("Getter can't have any parameters", lexer.yyline());
}
}
if (isSetter) {
if (ft.paramTypes.size() != 1) {
throw new AVM2ParseException("Getter must have exactly one parameter", lexer.yyline());
}
}
if (isStatic && isInterface) {
if (isInterface) {
throw new AVM2ParseException("Interface cannot have static fields", lexer.yyline());
}
}
GraphTargetItem t;
if (isGetter) {
GetterAVM2Item g = new GetterAVM2Item(ft.isPrivate(), ft.metadata, ft.pkg, isInterface, customAccess, ft.needsActivation, ft.hasRest, ft.line, ft.isOverride(), ft.isFinal(), isStatic, ft.namespace, ft.functionName, ft.paramTypes, ft.paramNames, ft.paramValues, ft.body, ft.subvariables, ft.retType);
t = g;
} else if (isSetter) {
SetterAVM2Item st = new SetterAVM2Item(ft.isPrivate(), ft.metadata, ft.pkg, isInterface, customAccess, ft.needsActivation, ft.hasRest, ft.line, ft.isOverride(), ft.isFinal(), isStatic, ft.namespace, ft.functionName, ft.paramTypes, ft.paramNames, ft.paramValues, ft.body, ft.subvariables, ft.retType);
t = st;
} else {
t = ft;
}
if (classNameStr != null) {
MethodAVM2Item ft = method(isPrivate, metadata, pkg, isInterface, customAccess, new Reference<>(false), importedClasses, isOverride, isFinal, thisType, openedNamespaces, isStatic, namespace, fname, true, new ArrayList<>());
if (isGetter) {
if (!ft.paramTypes.isEmpty()) {
throw new AVM2ParseException("Getter can't have any parameters", lexer.yyline());
}
}
if (isSetter) {
if (ft.paramTypes.size() != 1) {
throw new AVM2ParseException("Getter must have exactly one parameter", lexer.yyline());
}
}
if (isStatic && isInterface) {
if (isInterface) {
throw new AVM2ParseException("Interface cannot have static fields", lexer.yyline());
}
}
if (isGetter) {
GetterAVM2Item g = new GetterAVM2Item(ft.isPrivate(), ft.metadata, ft.pkg, isInterface, customAccess, ft.needsActivation, ft.hasRest, ft.line, ft.isOverride(), ft.isFinal(), isStatic, ft.namespace, ft.functionName, ft.paramTypes, ft.paramNames, ft.paramValues, ft.body, ft.subvariables, ft.retType);
t = g;
} else if (isSetter) {
SetterAVM2Item st = new SetterAVM2Item(ft.isPrivate(), ft.metadata, ft.pkg, isInterface, customAccess, ft.needsActivation, ft.hasRest, ft.line, ft.isOverride(), ft.isFinal(), isStatic, ft.namespace, ft.functionName, ft.paramTypes, ft.paramNames, ft.paramValues, ft.body, ft.subvariables, ft.retType);
t = st;
} else {
t = ft;
}
} else {
t = function(metadata, pkg, isInterface, new Reference<Boolean>(false), importedClasses, namespace, thisType, openedNamespaces, fname, false, new ArrayList<AssignableAVM2Item>());
}
traits.add(t);
}
//}

View File

@@ -19,9 +19,25 @@ package com.jpexs.decompiler.flash.abc.types.traits;
import com.jpexs.decompiler.flash.IdentifiersDeobfuscation;
import com.jpexs.decompiler.flash.abc.ABC;
import com.jpexs.decompiler.flash.abc.ClassPath;
import com.jpexs.decompiler.flash.abc.avm2.AVM2Code;
import com.jpexs.decompiler.flash.abc.avm2.instructions.AVM2Instruction;
import com.jpexs.decompiler.flash.abc.avm2.instructions.alchemy.AlchemyTypeIns;
import com.jpexs.decompiler.flash.abc.avm2.instructions.construction.NewFunctionIns;
import com.jpexs.decompiler.flash.abc.avm2.instructions.other.FindPropertyIns;
import com.jpexs.decompiler.flash.abc.avm2.instructions.other.FindPropertyStrictIns;
import com.jpexs.decompiler.flash.abc.avm2.instructions.other.GetLexIns;
import com.jpexs.decompiler.flash.abc.avm2.instructions.types.AsTypeIns;
import com.jpexs.decompiler.flash.abc.avm2.instructions.types.CoerceIns;
import com.jpexs.decompiler.flash.abc.avm2.model.InitVectorAVM2Item;
import com.jpexs.decompiler.flash.abc.types.ABCException;
import com.jpexs.decompiler.flash.abc.types.ClassInfo;
import com.jpexs.decompiler.flash.abc.types.ConvertData;
import com.jpexs.decompiler.flash.abc.types.InstanceInfo;
import com.jpexs.decompiler.flash.abc.types.MethodBody;
import com.jpexs.decompiler.flash.abc.types.Multiname;
import com.jpexs.decompiler.flash.abc.types.Namespace;
import com.jpexs.decompiler.flash.abc.types.NamespaceSet;
import com.jpexs.decompiler.flash.abc.types.ScriptInfo;
import com.jpexs.decompiler.flash.exporters.modes.ScriptExportMode;
import com.jpexs.decompiler.flash.helpers.GraphTextWriter;
import com.jpexs.decompiler.flash.helpers.NulWriter;
@@ -94,6 +110,300 @@ public abstract class Trait implements Cloneable, Serializable {
return ret;
}
protected void parseImportsUsagesFromMultiname(ABC abc, List<DottedChain> imports, List<String> uses, Multiname m, DottedChain ignorePackage, List<DottedChain> fullyQualifiedNames) {
if (m != null) {
if (m.kind == Multiname.TYPENAME) {
if (m.qname_index != 0) {
parseImportsUsagesFromMultiname(abc, imports, uses, abc.constants.getMultiname(m.qname_index), ignorePackage, fullyQualifiedNames);
}
for (Integer i : m.params) {
if (i != 0) {
parseImportsUsagesFromMultiname(abc, imports, uses, abc.constants.getMultiname(i), ignorePackage, fullyQualifiedNames);
}
}
return;
}
Namespace ns = m.getNamespace(abc.constants);
String name = m.getName(abc.constants, fullyQualifiedNames, true);
NamespaceSet nss = m.getNamespaceSet(abc.constants);
if (ns != null) {
parseImportsUsagesFromNS(abc, imports, uses, m.namespace_index, ignorePackage, name);
}
if (nss != null) {
for (int n : nss.namespaces) {
parseImportsUsagesFromNS(abc, imports, uses, n, ignorePackage, nss.namespaces.length > 1 ? "" : name);
}
}
}
}
private boolean parseUsagesFromNS(ABC abc, List<DottedChain> imports, List<String> uses, int namespace_index, DottedChain ignorePackage, String name) {
Namespace ns = abc.constants.getNamespace(namespace_index);
if (name.isEmpty()) {
name = "*";
}
boolean raw = ns.kind == Namespace.KIND_NAMESPACE;
DottedChain newimport = ns.getName(abc.constants);
//Note: Following is weird and probably wrong - FIXIT!
/*if ((ns.kind != Namespace.KIND_PACKAGE)
&& (ns.kind != Namespace.KIND_NAMESPACE)
&& (ns.kind != Namespace.KIND_STATIC_PROTECTED)) {
return false;
}*/
/*if (ns.kind == Namespace.KIND_NAMESPACE)*/ {
DottedChain oldimport = newimport;
newimport = new DottedChain();
for (ABCContainerTag abcTag : abc.getAbcTags()) {
DottedChain newname = abcTag.getABC().nsValueToName(oldimport.toRawString()); /* why this? */
if (newname.size() == 1 && newname.get(0).equals("-")) {
return true;
}
if (!newname.isEmpty() && !newname.isTopLevel()) {
newimport = newname;
break;
}
}
/* if (newimport.isEmpty()) {
newimport = oldimport.add(name);
}*/
if (!newimport.isEmpty() && !newimport.isTopLevel()) {
/* if(ns.kind==Namespace.KIND_PACKAGE){
newimport+=".*";
}*/
if (!imports.contains(newimport)) {
//??
/*if (newimport.contains(":")) {
return true;
}*/
DottedChain pkg = newimport.getWithoutLast();
String usname = newimport.getLast();
if (ns.kind == Namespace.KIND_PACKAGE) {
if (!pkg.equals(ignorePackage)) {
if (!pkg.equals(InitVectorAVM2Item.VECTOR_PACKAGE)) { //Automatic import
imports.add(newimport);
}
}
}
if (ns.kind == Namespace.KIND_NAMESPACE) {
if (!usname.equals("*")) {
/*if (!uses.contains(usname)) {
uses.add(usname);
}*/
if (!pkg.equals(ignorePackage)) {
imports.add(newimport);
}
}
}
}
return true;
}
}
return false;
}
protected void parseImportsUsagesFromNS(ABC abc, List<DottedChain> imports, List<String> uses, int namespace_index, DottedChain ignorePackage, String name) {
Namespace ns = abc.constants.getNamespace(namespace_index);
if (name.isEmpty()) {
name = "*";
}
DottedChain newimport = ns.getName(abc.constants);
if (parseUsagesFromNS(abc, imports, uses, namespace_index, ignorePackage, name)) {
return;
} else if ((ns.kind != Namespace.KIND_PACKAGE) && (ns.kind != Namespace.KIND_PACKAGE_INTERNAL)) {
return;
}
newimport = newimport.add(name);
if (!imports.contains(newimport)) {
DottedChain pkg = newimport.getWithoutLast(); //.substring(0, newimport.lastIndexOf('.'));
if (pkg.equals(InitVectorAVM2Item.VECTOR_PACKAGE)) { //special case - is imported always
return;
}
if (!pkg.equals(ignorePackage)) {
imports.add(newimport);
}
}
//}
}
protected void parseUsagesFromMultiname(ABC abc, List<DottedChain> imports, List<String> uses, Multiname m, DottedChain ignorePackage, List<DottedChain> fullyQualifiedNames) {
if (m != null) {
if (m.kind == Multiname.TYPENAME) {
if (m.qname_index != 0) {
parseUsagesFromMultiname(abc, imports, uses, abc.constants.getMultiname(m.qname_index), ignorePackage, fullyQualifiedNames);
}
for (Integer i : m.params) {
if (i != 0) {
parseUsagesFromMultiname(abc, imports, uses, abc.constants.getMultiname(i), ignorePackage, fullyQualifiedNames);
}
}
return;
}
Namespace ns = m.getNamespace(abc.constants);
String name = m.getName(abc.constants, fullyQualifiedNames, false);
NamespaceSet nss = m.getNamespaceSet(abc.constants);
if (ns != null) {
parseUsagesFromNS(abc, imports, uses, m.namespace_index, ignorePackage, name);
}
if (nss != null) {
if (nss.namespaces.length == 1) {
parseUsagesFromNS(abc, imports, uses, nss.namespaces[0], ignorePackage, name);
} else {
for (int n : nss.namespaces) {
parseUsagesFromNS(abc, imports, uses, n, ignorePackage, "");
}
}
}
}
}
protected DottedChain getPackage(ABC abc) {
return getName(abc).getNamespace(abc.constants).getName(abc.constants);
}
public void getImportsUsages(ABC abc, List<DottedChain> imports, List<String> uses, DottedChain ignorePackage, List<DottedChain> fullyQualifiedNames) {
parseUsagesFromMultiname(abc, imports, uses, getName(abc), ignorePackage, fullyQualifiedNames);
}
private static final String[] builtInClasses = {"ArgumentError", "arguments", "Array", "Boolean", "Class", "Date", "DefinitionError", "Error", "EvalError", "Function", "int", "JSON", "Math", "Namespace", "Number", "Object", "QName", "RangeError", "ReferenceError", "RegExp", "SecurityError", "String", "SyntaxError", "TypeError", "uint", "URIError", "VerifyError", "XML", "XMLList"};
private static boolean isBuiltInClass(String name) {
for (String g : builtInClasses) {
if (g.equals(name)) {
return true;
}
}
return false;
}
public void writeImportsUsages(ABC abc, GraphTextWriter writer, DottedChain ignorePackage, List<DottedChain> fullyQualifiedNames) {
List<String> namesInThisPackage = new ArrayList<>();
for (ABCContainerTag tag : abc.getAbcTags()) {
for (ScriptInfo si : tag.getABC().script_info) {
for (Trait t : si.traits.traits) {
ClassPath classPath = t.getPath(tag.getABC());
if (classPath.packageStr.equals(ignorePackage)) {
namesInThisPackage.add(classPath.className);
}
}
}
}
//imports
List<DottedChain> imports = new ArrayList<>();
List<String> uses = new ArrayList<>();
getImportsUsages(abc, imports, uses, ignorePackage, new ArrayList<>());
List<String> importnames = new ArrayList<>();
importnames.addAll(namesInThisPackage);
for (int i = 0; i < imports.size(); i++) {
DottedChain ipath = imports.get(i);
String name = ipath.getLast();
if (importnames.contains(name) || isBuiltInClass(name)) {
imports.remove(i);
i--;
fullyQualifiedNames.add(new DottedChain(name));
} else {
importnames.add(name);
}
}
for (int i = 0; i < imports.size(); i++) {
DottedChain imp = imports.get(i);
DottedChain pkg = imp.getWithoutLast();
String name = imp.getLast();
if (name.equals("*")) {
continue;
}
DottedChain dAll = pkg.add("*");
if (imports.contains(dAll)) {
imports.remove(i);
i--;
}
}
boolean hasImport = false;
for (DottedChain imp : imports) {
if (imp.size() > 1) { //No imports from root package
writer.appendNoHilight("import " + imp.toPrintableString(true) + ";").newLine();
hasImport = true;
}
}
if (hasImport) {
writer.newLine();
}
for (String us : uses) {
writer.appendNoHilight("use namespace " + us + ";").newLine();
}
if (uses.size() > 0) {
writer.newLine();
}
}
protected void parseImportsUsagesFromMethodInfo(ABC abc, int method_index, List<DottedChain> imports, List<String> uses, DottedChain ignorePackage, List<DottedChain> fullyQualifiedNames, List<Integer> visitedMethods) {
if ((method_index < 0) || (method_index >= abc.method_info.size())) {
return;
}
visitedMethods.add(method_index);
if (abc.method_info.get(method_index).ret_type != 0) {
parseImportsUsagesFromMultiname(abc, imports, uses, abc.constants.getMultiname(abc.method_info.get(method_index).ret_type), ignorePackage, fullyQualifiedNames);
}
for (int t : abc.method_info.get(method_index).param_types) {
if (t != 0) {
parseImportsUsagesFromMultiname(abc, imports, uses, abc.constants.getMultiname(t), ignorePackage, fullyQualifiedNames);
}
}
MethodBody body = abc.findBody(method_index);
if (body != null) {
body.traits.getImportsUsages(abc, imports, uses, ignorePackage, fullyQualifiedNames);
for (ABCException ex : body.exceptions) {
parseImportsUsagesFromMultiname(abc, imports, uses, abc.constants.getMultiname(ex.type_index), ignorePackage, fullyQualifiedNames);
}
for (AVM2Instruction ins : body.getCode().code) {
if (ins.definition instanceof AlchemyTypeIns) {
DottedChain nimport = AlchemyTypeIns.ALCHEMY_PACKAGE.add(ins.definition.instructionName);
if (!imports.contains(nimport)) {
imports.add(nimport);
}
}
if (ins.definition instanceof NewFunctionIns) {
if (ins.operands[0] != method_index) {
if (!visitedMethods.contains(ins.operands[0])) {
parseImportsUsagesFromMethodInfo(abc, ins.operands[0], imports, uses, ignorePackage, fullyQualifiedNames, visitedMethods);
}
}
}
if ((ins.definition instanceof FindPropertyStrictIns)
|| (ins.definition instanceof FindPropertyIns)
|| (ins.definition instanceof GetLexIns)
|| (ins.definition instanceof CoerceIns)
|| (ins.definition instanceof AsTypeIns)) {
int m = ins.operands[0];
if (m != 0) {
if (m < abc.constants.getMultinameCount()) {
parseImportsUsagesFromMultiname(abc, imports, uses, abc.constants.getMultiname(m), ignorePackage, fullyQualifiedNames);
}
}
} else {
for (int k = 0; k < ins.definition.operands.length; k++) {
if (ins.definition.operands[k] == AVM2Code.DAT_MULTINAME_INDEX) {
int multinameIndex = ins.operands[k];
if (multinameIndex < abc.constants.getMultinameCount()) {
parseUsagesFromMultiname(abc, imports, uses, abc.constants.getMultiname(multinameIndex), ignorePackage, fullyQualifiedNames);
}
}
}
}
}
}
}
public final GraphTextWriter getMetaData(ABC abc, GraphTextWriter writer) {
List<Entry<String, Map<String, String>>> md = getMetaDataTable(abc);
for (Entry<String, Map<String, String>> en : md) {

View File

@@ -53,8 +53,6 @@ public class TraitClass extends Trait implements TraitWithSlot {
public int class_info;
private static final String[] builtInClasses = {"ArgumentError", "arguments", "Array", "Boolean", "Class", "Date", "DefinitionError", "Error", "EvalError", "Function", "int", "JSON", "Math", "Namespace", "Number", "Object", "QName", "RangeError", "ReferenceError", "RegExp", "SecurityError", "String", "SyntaxError", "TypeError", "uint", "URIError", "VerifyError", "XML", "XMLList"};
private boolean classInitializerIsEmpty;
@Override
@@ -83,255 +81,14 @@ public class TraitClass extends Trait implements TraitWithSlot {
return slot_id;
}
private static boolean isBuiltInClass(String name) {
for (String g : builtInClasses) {
if (g.equals(name)) {
return true;
}
}
return false;
}
@Override
public String toString(ABC abc, List<DottedChain> fullyQualifiedNames) {
return "Class " + abc.constants.getMultiname(name_index).toString(abc.constants, fullyQualifiedNames) + " slot=" + slot_id + " class_info=" + class_info + " metadata=" + Helper.intArrToString(metadata);
}
private boolean parseUsagesFromNS(ABC abc, List<DottedChain> imports, List<String> uses, int namespace_index, DottedChain ignorePackage, String name) {
Namespace ns = abc.constants.getNamespace(namespace_index);
if (name.isEmpty()) {
name = "*";
}
boolean raw = ns.kind == Namespace.KIND_NAMESPACE;
DottedChain newimport = ns.getName(abc.constants);
//Note: Following is weird and probably wrong - FIXIT!
/*if ((ns.kind != Namespace.KIND_PACKAGE)
&& (ns.kind != Namespace.KIND_NAMESPACE)
&& (ns.kind != Namespace.KIND_STATIC_PROTECTED)) {
return false;
}*/
/*if (ns.kind == Namespace.KIND_NAMESPACE)*/ {
DottedChain oldimport = newimport;
newimport = new DottedChain();
for (ABCContainerTag abcTag : abc.getAbcTags()) {
DottedChain newname = abcTag.getABC().nsValueToName(oldimport.toRawString()); /* why this? */
if (newname.size() == 1 && newname.get(0).equals("-")) {
return true;
}
if (!newname.isEmpty() && !newname.isTopLevel()) {
newimport = newname;
break;
}
}
/* if (newimport.isEmpty()) {
newimport = oldimport.add(name);
}*/
if (!newimport.isEmpty() && !newimport.isTopLevel()) {
/* if(ns.kind==Namespace.KIND_PACKAGE){
newimport+=".*";
}*/
if (!imports.contains(newimport)) {
//??
/*if (newimport.contains(":")) {
return true;
}*/
DottedChain pkg = newimport.getWithoutLast();
String usname = newimport.getLast();
if (ns.kind == Namespace.KIND_PACKAGE) {
if (!pkg.equals(ignorePackage)) {
if (!pkg.equals(InitVectorAVM2Item.VECTOR_PACKAGE)) { //Automatic import
imports.add(newimport);
}
}
}
if (ns.kind == Namespace.KIND_NAMESPACE) {
if (!usname.equals("*")) {
/*if (!uses.contains(usname)) {
uses.add(usname);
}*/
if (!pkg.equals(ignorePackage)) {
imports.add(newimport);
}
}
}
}
return true;
}
}
return false;
}
private void parseImportsUsagesFromNS(ABC abc, List<DottedChain> imports, List<String> uses, int namespace_index, DottedChain ignorePackage, String name) {
Namespace ns = abc.constants.getNamespace(namespace_index);
if (name.isEmpty()) {
name = "*";
}
DottedChain newimport = ns.getName(abc.constants);
if (parseUsagesFromNS(abc, imports, uses, namespace_index, ignorePackage, name)) {
return;
} else if ((ns.kind != Namespace.KIND_PACKAGE) && (ns.kind != Namespace.KIND_PACKAGE_INTERNAL)) {
return;
}
newimport = newimport.add(name);
if (!imports.contains(newimport)) {
DottedChain pkg = newimport.getWithoutLast(); //.substring(0, newimport.lastIndexOf('.'));
if (pkg.equals(InitVectorAVM2Item.VECTOR_PACKAGE)) { //special case - is imported always
return;
}
if (!pkg.equals(ignorePackage)) {
imports.add(newimport);
}
}
//}
}
private void parseUsagesFromMultiname(ABC abc, List<DottedChain> imports, List<String> uses, Multiname m, DottedChain ignorePackage, List<DottedChain> fullyQualifiedNames) {
if (m != null) {
if (m.kind == Multiname.TYPENAME) {
if (m.qname_index != 0) {
parseUsagesFromMultiname(abc, imports, uses, abc.constants.getMultiname(m.qname_index), ignorePackage, fullyQualifiedNames);
}
for (Integer i : m.params) {
if (i != 0) {
parseUsagesFromMultiname(abc, imports, uses, abc.constants.getMultiname(i), ignorePackage, fullyQualifiedNames);
}
}
return;
}
Namespace ns = m.getNamespace(abc.constants);
String name = m.getName(abc.constants, fullyQualifiedNames, false);
NamespaceSet nss = m.getNamespaceSet(abc.constants);
if (ns != null) {
parseUsagesFromNS(abc, imports, uses, m.namespace_index, ignorePackage, name);
}
if (nss != null) {
if (nss.namespaces.length == 1) {
parseUsagesFromNS(abc, imports, uses, nss.namespaces[0], ignorePackage, name);
} else {
for (int n : nss.namespaces) {
parseUsagesFromNS(abc, imports, uses, n, ignorePackage, "");
}
}
}
}
}
private void parseImportsUsagesFromMultiname(ABC abc, List<DottedChain> imports, List<String> uses, Multiname m, DottedChain ignorePackage, List<DottedChain> fullyQualifiedNames) {
if (m != null) {
if (m.kind == Multiname.TYPENAME) {
if (m.qname_index != 0) {
parseImportsUsagesFromMultiname(abc, imports, uses, abc.constants.getMultiname(m.qname_index), ignorePackage, fullyQualifiedNames);
}
for (Integer i : m.params) {
if (i != 0) {
parseImportsUsagesFromMultiname(abc, imports, uses, abc.constants.getMultiname(i), ignorePackage, fullyQualifiedNames);
}
}
return;
}
Namespace ns = m.getNamespace(abc.constants);
String name = m.getName(abc.constants, fullyQualifiedNames, true);
NamespaceSet nss = m.getNamespaceSet(abc.constants);
if (ns != null) {
parseImportsUsagesFromNS(abc, imports, uses, m.namespace_index, ignorePackage, name);
}
if (nss != null) {
for (int n : nss.namespaces) {
parseImportsUsagesFromNS(abc, imports, uses, n, ignorePackage, nss.namespaces.length > 1 ? "" : name);
}
}
}
}
private void parseImportsUsagesFromMethodInfo(ABC abc, int method_index, List<DottedChain> imports, List<String> uses, DottedChain ignorePackage, List<DottedChain> fullyQualifiedNames, List<Integer> visitedMethods) {
if ((method_index < 0) || (method_index >= abc.method_info.size())) {
return;
}
visitedMethods.add(method_index);
if (abc.method_info.get(method_index).ret_type != 0) {
parseImportsUsagesFromMultiname(abc, imports, uses, abc.constants.getMultiname(abc.method_info.get(method_index).ret_type), ignorePackage, fullyQualifiedNames);
}
for (int t : abc.method_info.get(method_index).param_types) {
if (t != 0) {
parseImportsUsagesFromMultiname(abc, imports, uses, abc.constants.getMultiname(t), ignorePackage, fullyQualifiedNames);
}
}
MethodBody body = abc.findBody(method_index);
if (body != null) {
parseImportsUsagesFromTraits(abc, body.traits, imports, uses, ignorePackage, fullyQualifiedNames);
for (ABCException ex : body.exceptions) {
parseImportsUsagesFromMultiname(abc, imports, uses, abc.constants.getMultiname(ex.type_index), ignorePackage, fullyQualifiedNames);
}
for (AVM2Instruction ins : body.getCode().code) {
if (ins.definition instanceof AlchemyTypeIns) {
DottedChain nimport = AlchemyTypeIns.ALCHEMY_PACKAGE.add(ins.definition.instructionName);
if (!imports.contains(nimport)) {
imports.add(nimport);
}
}
if (ins.definition instanceof NewFunctionIns) {
if (ins.operands[0] != method_index) {
if (!visitedMethods.contains(ins.operands[0])) {
parseImportsUsagesFromMethodInfo(abc, ins.operands[0], imports, uses, ignorePackage, fullyQualifiedNames, visitedMethods);
}
}
}
if ((ins.definition instanceof FindPropertyStrictIns)
|| (ins.definition instanceof FindPropertyIns)
|| (ins.definition instanceof GetLexIns)
|| (ins.definition instanceof CoerceIns)
|| (ins.definition instanceof AsTypeIns)) {
int m = ins.operands[0];
if (m != 0) {
if (m < abc.constants.getMultinameCount()) {
parseImportsUsagesFromMultiname(abc, imports, uses, abc.constants.getMultiname(m), ignorePackage, fullyQualifiedNames);
}
}
} else {
for (int k = 0; k < ins.definition.operands.length; k++) {
if (ins.definition.operands[k] == AVM2Code.DAT_MULTINAME_INDEX) {
int multinameIndex = ins.operands[k];
if (multinameIndex < abc.constants.getMultinameCount()) {
parseUsagesFromMultiname(abc, imports, uses, abc.constants.getMultiname(multinameIndex), ignorePackage, fullyQualifiedNames);
}
}
}
}
}
}
}
private void parseImportsUsagesFromTraits(ABC abc, Traits ts, List<DottedChain> imports, List<String> uses, DottedChain ignorePackage, List<DottedChain> fullyQualifiedNames) {
for (Trait t : ts.traits) {
parseImportsUsagesFromTrait(abc, t, imports, uses, ignorePackage, fullyQualifiedNames);
}
}
private void parseImportsUsagesFromTrait(ABC abc, Trait t, List<DottedChain> imports, List<String> uses, DottedChain ignorePackage, List<DottedChain> fullyQualifiedNames) {
if (t instanceof TraitMethodGetterSetter) {
TraitMethodGetterSetter tm = (TraitMethodGetterSetter) t;
parseImportsUsagesFromMultiname(abc, imports, uses, abc.constants.getMultiname(tm.name_index), ignorePackage, fullyQualifiedNames);
if (tm.method_info != 0) {
parseImportsUsagesFromMethodInfo(abc, tm.method_info, imports, uses, ignorePackage, fullyQualifiedNames, new ArrayList<>());
}
}
parseImportsUsagesFromMultiname(abc, imports, uses, t.getName(abc), ignorePackage, fullyQualifiedNames);
if (t instanceof TraitSlotConst) {
TraitSlotConst ts = (TraitSlotConst) t;
parseImportsUsagesFromMultiname(abc, imports, uses, abc.constants.getMultiname(ts.name_index), ignorePackage, fullyQualifiedNames);
parseImportsUsagesFromMultiname(abc, imports, uses, abc.constants.getMultiname(ts.type_index), ignorePackage, fullyQualifiedNames);
}
}
private List<DottedChain> getImportsUsages(ABC abc, List<DottedChain> imports, List<String> uses, List<DottedChain> fullyQualifiedNames) {
//constructor
@Override
public void getImportsUsages(ABC abc, List<DottedChain> imports, List<String> uses, DottedChain ignorePackage, List<DottedChain> fullyQualifiedNames) {
super.getImportsUsages(abc, imports, uses, ignorePackage == null ? getPackage(abc) : ignorePackage, fullyQualifiedNames);
ClassInfo classInfo = abc.class_info.get(class_info);
InstanceInfo instanceInfo = abc.instance_info.get(class_info);
DottedChain packageName = instanceInfo.getName(abc.constants).getNamespace(abc.constants).getName(abc.constants); //assume not null name
@@ -346,17 +103,16 @@ public class TraitClass extends Trait implements TraitWithSlot {
}
//static
parseImportsUsagesFromTraits(abc, classInfo.static_traits, imports, uses, packageName, fullyQualifiedNames);
classInfo.static_traits.getImportsUsages(abc, imports, uses, packageName, fullyQualifiedNames);
//static initializer
parseImportsUsagesFromMethodInfo(abc, classInfo.cinit_index, imports, uses, packageName, fullyQualifiedNames, new ArrayList<>());
//instance
parseImportsUsagesFromTraits(abc, instanceInfo.instance_traits, imports, uses, packageName, fullyQualifiedNames);
instanceInfo.instance_traits.getImportsUsages(abc, imports, uses, packageName, fullyQualifiedNames);
//instance initializer
parseImportsUsagesFromMethodInfo(abc, instanceInfo.iinit_index, imports, uses, packageName, fullyQualifiedNames, new ArrayList<>());
return imports;
}
@Override
@@ -374,71 +130,12 @@ public class TraitClass extends Trait implements TraitWithSlot {
InstanceInfo instanceInfo = abc.instance_info.get(class_info);
Multiname instanceInfoMultiname = instanceInfo.getName(abc.constants);
String instanceInfoName = instanceInfoMultiname.getName(abc.constants, fullyQualifiedNames, false);
DottedChain packageName = instanceInfoMultiname.getNamespace(abc.constants).getName(abc.constants); //assume not null name
List<String> namesInThisPackage = new ArrayList<>();
for (ABCContainerTag tag : abc.getAbcTags()) {
for (ScriptInfo si : tag.getABC().script_info) {
for (Trait t : si.traits.traits) {
ClassPath classPath = t.getPath(tag.getABC());
if (classPath.packageStr.equals(packageName)) {
namesInThisPackage.add(classPath.className);
}
}
}
}
//imports
List<DottedChain> imports = new ArrayList<>();
List<String> uses = new ArrayList<>();
getImportsUsages(abc, imports, uses, new ArrayList<>());
fullyQualifiedNames = new ArrayList<>();
writeImportsUsages(abc, writer, packageName, fullyQualifiedNames);
List<String> importnames = new ArrayList<>();
importnames.addAll(namesInThisPackage);
for (int i = 0; i < imports.size(); i++) {
DottedChain ipath = imports.get(i);
String name = ipath.getLast();
if (importnames.contains(name) || isBuiltInClass(name)) {
imports.remove(i);
i--;
fullyQualifiedNames.add(new DottedChain(name));
} else {
importnames.add(name);
}
}
for (int i = 0; i < imports.size(); i++) {
DottedChain imp = imports.get(i);
DottedChain pkg = imp.getWithoutLast();
String name = imp.getLast();
if (name.equals("*")) {
continue;
}
DottedChain dAll = pkg.add("*");
if (imports.contains(dAll)) {
imports.remove(i);
i--;
}
}
boolean hasImport = false;
for (DottedChain imp : imports) {
if (imp.size() > 1) { //No imports from root package
writer.appendNoHilight("import " + imp.toPrintableString(true) + ";").newLine();
hasImport = true;
}
}
if (hasImport) {
writer.newLine();
}
for (String us : uses) {
writer.appendNoHilight("use namespace " + us + ";").newLine();
}
if (uses.size() > 0) {
writer.newLine();
}
String instanceInfoName = instanceInfoMultiname.getName(abc.constants, fullyQualifiedNames, false);
writer.startClass(class_info);

View File

@@ -26,6 +26,7 @@ import com.jpexs.decompiler.flash.helpers.hilight.HighlightSpecialType;
import com.jpexs.decompiler.graph.DottedChain;
import com.jpexs.decompiler.graph.ScopeStack;
import com.jpexs.helpers.Helper;
import java.util.ArrayList;
import java.util.List;
public class TraitFunction extends Trait implements TraitWithSlot {
@@ -72,20 +73,18 @@ public class TraitFunction extends Trait implements TraitWithSlot {
@Override
public GraphTextWriter toString(Trait parent, ConvertData convertData, String path, ABC abc, boolean isStatic, ScriptExportMode exportMode, int scriptIndex, int classIndex, GraphTextWriter writer, List<DottedChain> fullyQualifiedNames, boolean parallel) throws InterruptedException {
writeImportsUsages(abc, writer, getPackage(abc), fullyQualifiedNames);
getMetaData(abc, writer);
writer.startMethod(method_info);
toStringHeader(parent, convertData, path, abc, isStatic, exportMode, scriptIndex, classIndex, writer, fullyQualifiedNames, parallel);
if (abc.instance_info.get(classIndex).isInterface()) {
writer.appendNoHilight(";");
} else {
writer.appendNoHilight(" {").newLine();
int bodyIndex = abc.findBodyIndex(method_info);
if (bodyIndex != -1) {
abc.bodies.get(bodyIndex).toString(path + "." + abc.constants.getMultiname(name_index).getName(abc.constants, fullyQualifiedNames, false), exportMode, abc, this, writer, fullyQualifiedNames);
}
writer.newLine();
writer.appendNoHilight("}");
writer.startBlock();
int bodyIndex = abc.findBodyIndex(method_info);
if (bodyIndex != -1) {
abc.bodies.get(bodyIndex).toString(path + "." + abc.constants.getMultiname(name_index).getName(abc.constants, fullyQualifiedNames, false), exportMode, abc, this, writer, fullyQualifiedNames);
}
writer.endBlock();
writer.newLine();
writer.endMethod();
return writer;
@@ -93,13 +92,13 @@ public class TraitFunction extends Trait implements TraitWithSlot {
@Override
public void convert(Trait parent, ConvertData convertData, String path, ABC abc, boolean isStatic, ScriptExportMode exportMode, int scriptIndex, int classIndex, NulWriter writer, List<DottedChain> fullyQualifiedNames, boolean parallel) throws InterruptedException {
fullyQualifiedNames = new ArrayList<>();
writeImportsUsages(abc, writer, getPackage(abc), fullyQualifiedNames);
writer.startMethod(method_info);
convertHeader(parent, convertData, path, abc, isStatic, exportMode, scriptIndex, classIndex, writer, fullyQualifiedNames, parallel);
if (!abc.instance_info.get(classIndex).isInterface()) {
int bodyIndex = abc.findBodyIndex(method_info);
if (bodyIndex != -1) {
abc.bodies.get(bodyIndex).convert(convertData, path + "." + abc.constants.getMultiname(name_index).getName(abc.constants, fullyQualifiedNames, false), exportMode, isStatic, method_info, scriptIndex, classIndex, abc, this, new ScopeStack(), 0, writer, fullyQualifiedNames, null, true);
}
int bodyIndex = abc.findBodyIndex(method_info);
if (bodyIndex != -1) {
abc.bodies.get(bodyIndex).convert(convertData, path + "." + abc.constants.getMultiname(name_index).getName(abc.constants, fullyQualifiedNames, false), exportMode, isStatic, method_info, scriptIndex, classIndex, abc, this, new ScopeStack(), 0, writer, fullyQualifiedNames, null, true);
}
writer.endMethod();
}
@@ -118,4 +117,17 @@ public class TraitFunction extends Trait implements TraitWithSlot {
TraitFunction ret = (TraitFunction) super.clone();
return ret;
}
@Override
public void getImportsUsages(ABC abc, List<DottedChain> imports, List<String> uses, DottedChain ignorePackage, List<DottedChain> fullyQualifiedNames) {
if (ignorePackage == null) {
ignorePackage = getPackage(abc);
}
super.getImportsUsages(abc, imports, uses, ignorePackage, fullyQualifiedNames);
//if (method_info != 0)
{
parseImportsUsagesFromMethodInfo(abc, method_info, imports, uses, ignorePackage, fullyQualifiedNames, new ArrayList<>());
}
}
}

View File

@@ -26,6 +26,7 @@ import com.jpexs.decompiler.flash.helpers.hilight.HighlightSpecialType;
import com.jpexs.decompiler.graph.DottedChain;
import com.jpexs.decompiler.graph.ScopeStack;
import com.jpexs.helpers.Helper;
import java.util.ArrayList;
import java.util.List;
public class TraitMethodGetterSetter extends Trait {
@@ -49,6 +50,19 @@ public class TraitMethodGetterSetter extends Trait {
public void convertHeader(Trait parent, ConvertData convertData, String path, ABC abc, boolean isStatic, ScriptExportMode exportMode, int scriptIndex, int classIndex, NulWriter writer, List<DottedChain> fullyQualifiedNames, boolean parallel) {
}
@Override
public void getImportsUsages(ABC abc, List<DottedChain> imports, List<String> uses, DottedChain ignorePackage, List<DottedChain> fullyQualifiedNames) {
if (ignorePackage == null) {
ignorePackage = getPackage(abc);
}
super.getImportsUsages(abc, imports, uses, ignorePackage, fullyQualifiedNames);
//if (method_info != 0)
{
parseImportsUsagesFromMethodInfo(abc, method_info, imports, uses, ignorePackage, fullyQualifiedNames, new ArrayList<>());
}
}
@Override
public GraphTextWriter toStringHeader(Trait parent, ConvertData convertData, String path, ABC abc, boolean isStatic, ScriptExportMode exportMode, int scriptIndex, int classIndex, GraphTextWriter writer, List<DottedChain> fullyQualifiedNames, boolean parallel) {
String addKind = "";
@@ -76,6 +90,9 @@ public class TraitMethodGetterSetter extends Trait {
@Override
public void convert(Trait parent, ConvertData convertData, String path, ABC abc, boolean isStatic, ScriptExportMode exportMode, int scriptIndex, int classIndex, NulWriter writer, List<DottedChain> fullyQualifiedNames, boolean parallel) throws InterruptedException {
if (classIndex < 0) {
writeImportsUsages(abc, writer, getPackage(abc), fullyQualifiedNames);
}
writer.startMethod(method_info);
path = path + "." + getName(abc).getName(abc.constants, fullyQualifiedNames, false);
convertHeader(parent, convertData, path, abc, isStatic, exportMode, scriptIndex, classIndex, writer, fullyQualifiedNames, parallel);
@@ -90,6 +107,10 @@ public class TraitMethodGetterSetter extends Trait {
@Override
public GraphTextWriter toString(Trait parent, ConvertData convertData, String path, ABC abc, boolean isStatic, ScriptExportMode exportMode, int scriptIndex, int classIndex, GraphTextWriter writer, List<DottedChain> fullyQualifiedNames, boolean parallel) throws InterruptedException {
if (classIndex < 0) {
writeImportsUsages(abc, writer, getPackage(abc), fullyQualifiedNames);
}
getMetaData(abc, writer);
writer.startMethod(method_info);
path = path + "." + getName(abc).getName(abc.constants, fullyQualifiedNames, false);

View File

@@ -181,4 +181,14 @@ public class TraitSlotConst extends Trait implements TraitWithSlot {
TraitSlotConst ret = (TraitSlotConst) super.clone();
return ret;
}
@Override
public void getImportsUsages(ABC abc, List<DottedChain> imports, List<String> uses, DottedChain ignorePackage, List<DottedChain> fullyQualifiedNames) {
if (ignorePackage == null) {
ignorePackage = getPackage(abc);
}
super.getImportsUsages(abc, imports, uses, ignorePackage, fullyQualifiedNames);
parseImportsUsagesFromMultiname(abc, imports, uses, abc.constants.getMultiname(type_index), getPackage(abc), fullyQualifiedNames);
}
}

View File

@@ -236,4 +236,10 @@ public class Traits implements Cloneable, Serializable {
throw new RuntimeException();
}
}
public void getImportsUsages(ABC abc, List<DottedChain> imports, List<String> uses, DottedChain ignorePackage, List<DottedChain> fullyQualifiedNames) {
for (Trait t : traits) {
t.getImportsUsages(abc, imports, uses, ignorePackage, fullyQualifiedNames);
}
}
}