diff --git a/CHANGELOG.md b/CHANGELOG.md index 52c18c496..ab5873537 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,7 @@ All notable changes to this project will be documented in this file. - FLA export - XML formatting with blank lines on Java9+ - [#1974] DefineBits image reading problem - [#1963] AS2 properly decompile/direct edit long classes +- [#1977] AS3 Find usages - class and function usages, various fixes ## [18.3.5] - 2023-02-12 ### Added @@ -2965,6 +2966,7 @@ All notable changes to this project will be documented in this file. [#1973]: https://www.free-decompiler.com/flash/issues/1973 [#1974]: https://www.free-decompiler.com/flash/issues/1974 [#1963]: https://www.free-decompiler.com/flash/issues/1963 +[#1977]: https://www.free-decompiler.com/flash/issues/1977 [#1959]: https://www.free-decompiler.com/flash/issues/1959 [#1960]: https://www.free-decompiler.com/flash/issues/1960 [#1964]: https://www.free-decompiler.com/flash/issues/1964 diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/ABC.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/ABC.java index 3289790a8..b8411302a 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/ABC.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/ABC.java @@ -49,8 +49,8 @@ import com.jpexs.decompiler.flash.abc.usages.ClassNameMultinameUsage; import com.jpexs.decompiler.flash.abc.usages.ConstVarNameMultinameUsage; import com.jpexs.decompiler.flash.abc.usages.ConstVarTypeMultinameUsage; import com.jpexs.decompiler.flash.abc.usages.DefinitionUsage; -import com.jpexs.decompiler.flash.abc.usages.ExtendsMultinameUsage; -import com.jpexs.decompiler.flash.abc.usages.ImplementsMultinameUsage; +import com.jpexs.decompiler.flash.abc.usages.SuperClassMultinameUsage; +import com.jpexs.decompiler.flash.abc.usages.SuperInterfaceMultinameUsage; import com.jpexs.decompiler.flash.abc.usages.MethodBodyMultinameUsage; import com.jpexs.decompiler.flash.abc.usages.MethodNameMultinameUsage; import com.jpexs.decompiler.flash.abc.usages.MethodParamsMultinameUsage; @@ -1146,21 +1146,21 @@ public class ABC implements Openable { } } - private void checkMultinameUsedInMethod(int multinameIndex, int methodInfo, List ret, int scriptIndex, int classIndex, int traitIndex, int traitsType, boolean isInitializer, Traits traits, int parentTraitIndex) { + private void checkMultinameUsedInMethod(int multinameIndex, boolean exactMatch, int methodInfo, List ret, int scriptIndex, int classIndex, int traitIndex, int traitsType, boolean isInitializer, Traits traits, int parentTraitIndex) { for (int p = 0; p < method_info.get(methodInfo).param_types.length; p++) { - if (method_info.get(methodInfo).param_types[p] == multinameIndex) { + if (isSameName(multinameIndex, method_info.get(methodInfo).param_types[p], exactMatch)) { ret.add(new MethodParamsMultinameUsage(this, multinameIndex, scriptIndex, classIndex, traitIndex, traitsType, isInitializer, traits, parentTraitIndex)); break; } } - if (method_info.get(methodInfo).ret_type == multinameIndex) { + if (isSameName(multinameIndex, method_info.get(methodInfo).ret_type, exactMatch)) { ret.add(new MethodReturnTypeMultinameUsage(this, multinameIndex, scriptIndex, classIndex, traitIndex, traitsType, isInitializer, traits, parentTraitIndex)); } MethodBody body = findBody(methodInfo); if (body != null) { - findMultinameUsageInTraits(body.traits, multinameIndex, traitsType, scriptIndex, classIndex, ret, traitIndex); + findMultinameUsageInTraits(body.traits, multinameIndex, exactMatch, traitsType, scriptIndex, classIndex, ret, traitIndex); for (ABCException e : body.exceptions) { - if ((e.name_index == multinameIndex) || (e.type_index == multinameIndex)) { + if ((isSameName(multinameIndex, e.name_index, exactMatch)) || (isSameName(multinameIndex, e.type_index, exactMatch))) { ret.add(new MethodBodyMultinameUsage(this, multinameIndex, scriptIndex, classIndex, traitIndex, traitsType, isInitializer, traits, parentTraitIndex)); return; } @@ -1168,7 +1168,7 @@ public class ABC implements Openable { for (AVM2Instruction ins : body.getCode().code) { for (int o = 0; o < ins.definition.operands.length; o++) { if (ins.definition.operands[o] == AVM2Code.DAT_MULTINAME_INDEX) { - if (ins.operands[o] == multinameIndex) { + if (isSameName(multinameIndex, ins.operands[o], exactMatch)) { ret.add(new MethodBodyMultinameUsage(this, multinameIndex, scriptIndex, classIndex, traitIndex, traitsType, isInitializer, traits, parentTraitIndex)); return; } @@ -1218,43 +1218,73 @@ public class ABC implements Openable { } } } + + private boolean isSameName(int expectedQNameIndex, int checkedNameIndex, boolean exactMatch) { + if (expectedQNameIndex == checkedNameIndex) { + return true; + } + if (exactMatch) { + return false; + } + Multiname expectedQName = constants.getMultiname(expectedQNameIndex); + Multiname checkedName = constants.getMultiname(checkedNameIndex); + if (checkedName == null) { + return false; + } + + if (expectedQName.name_index != checkedName.name_index) { + return false; + } + if (checkedName.kind == Multiname.QNAME) { + return expectedQName.namespace_index == checkedName.namespace_index; + } + if (checkedName.kind != Multiname.MULTINAME) { + return false; + } + for (int ns:constants.getNamespaceSet(checkedName.namespace_set_index).namespaces) { + if (ns == expectedQName.namespace_index) { + return true; + } + } + return false; + } - private void findMultinameUsageInTraits(Traits traits, int multinameIndex, int traitsType, int scriptIndex, int classIndex, List ret, int parentTraitIndex) { + private void findMultinameUsageInTraits(Traits traits, int multinameIndex, boolean exactMatch, int traitsType, int scriptIndex, int classIndex, List ret, int parentTraitIndex) { for (int t = 0; t < traits.traits.size(); t++) { if (traits.traits.get(t) instanceof TraitClass) { TraitClass tc = (TraitClass) traits.traits.get(t); - if (tc.name_index == multinameIndex) { + if (isSameName(multinameIndex, tc.name_index, exactMatch)) { ret.add(new ClassNameMultinameUsage(this, multinameIndex, tc.class_info, scriptIndex)); } int c = tc.class_info; - if (instance_info.get(c).super_index == multinameIndex) { - ret.add(new ExtendsMultinameUsage(this, multinameIndex, c, scriptIndex)); + if (isSameName(multinameIndex, instance_info.get(c).super_index, exactMatch)) { + ret.add(new SuperClassMultinameUsage(this, multinameIndex, c, scriptIndex)); } for (int i = 0; i < instance_info.get(c).interfaces.length; i++) { - if (instance_info.get(c).interfaces[i] == multinameIndex) { - ret.add(new ImplementsMultinameUsage(this, multinameIndex, c, scriptIndex)); + if (isSameName(multinameIndex, instance_info.get(c).interfaces[i], exactMatch)) { + ret.add(new SuperInterfaceMultinameUsage(this, multinameIndex, c, scriptIndex)); } } - checkMultinameUsedInMethod(multinameIndex, instance_info.get(c).iinit_index, ret, -1/*FIXME*/, c, 0, TraitMultinameUsage.TRAITS_TYPE_INSTANCE, true, null, -1); - checkMultinameUsedInMethod(multinameIndex, class_info.get(c).cinit_index, ret, -1/*FIXME*/, c, 0, TraitMultinameUsage.TRAITS_TYPE_CLASS, true, null, -1); - findMultinameUsageInTraits(instance_info.get(c).instance_traits, multinameIndex, TraitMultinameUsage.TRAITS_TYPE_INSTANCE, -1/*FIXME*/, c, ret, -1); - findMultinameUsageInTraits(class_info.get(c).static_traits, multinameIndex, TraitMultinameUsage.TRAITS_TYPE_CLASS, -1/*FIXME*/, c, ret, -1); + checkMultinameUsedInMethod(multinameIndex, exactMatch, instance_info.get(c).iinit_index, ret, -1/*FIXME*/, c, 0, TraitMultinameUsage.TRAITS_TYPE_INSTANCE, true, null, -1); + checkMultinameUsedInMethod(multinameIndex, exactMatch, class_info.get(c).cinit_index, ret, -1/*FIXME*/, c, 0, TraitMultinameUsage.TRAITS_TYPE_CLASS, true, null, -1); + findMultinameUsageInTraits(instance_info.get(c).instance_traits, multinameIndex, exactMatch, TraitMultinameUsage.TRAITS_TYPE_INSTANCE, -1/*FIXME*/, c, ret, -1); + findMultinameUsageInTraits(class_info.get(c).static_traits, multinameIndex, exactMatch, TraitMultinameUsage.TRAITS_TYPE_CLASS, -1/*FIXME*/, c, ret, -1); } if (traits.traits.get(t) instanceof TraitSlotConst) { TraitSlotConst tsc = (TraitSlotConst) traits.traits.get(t); - if (tsc.name_index == multinameIndex) { + if (isSameName(multinameIndex, tsc.name_index, exactMatch)) { ret.add(new ConstVarNameMultinameUsage(this, multinameIndex, scriptIndex, classIndex, t, traitsType, traits, parentTraitIndex)); } - if (tsc.type_index == multinameIndex) { + if (isSameName(multinameIndex, tsc.type_index, exactMatch)) { ret.add(new ConstVarTypeMultinameUsage(this, multinameIndex, scriptIndex, classIndex, t, traitsType, traits, parentTraitIndex)); } } if (traits.traits.get(t) instanceof TraitMethodGetterSetter) { TraitMethodGetterSetter tmgs = (TraitMethodGetterSetter) traits.traits.get(t); - if (tmgs.name_index == multinameIndex) { + if (isSameName(multinameIndex, tmgs.name_index, exactMatch)) { ret.add(new MethodNameMultinameUsage(this, multinameIndex, scriptIndex, classIndex, t, traitsType, false, traits, parentTraitIndex)); } - checkMultinameUsedInMethod(multinameIndex, tmgs.method_info, ret, scriptIndex, classIndex, t, traitsType, false, traits, parentTraitIndex); + checkMultinameUsedInMethod(multinameIndex, exactMatch, tmgs.method_info, ret, scriptIndex, classIndex, t, traitsType, false, traits, parentTraitIndex); } } } @@ -1270,10 +1300,10 @@ public class ABC implements Openable { int classNameMultinameIndex = instance_info.get(c).name_index; ret.get(classNameMultinameIndex).add(new ClassNameMultinameUsage(this, classNameMultinameIndex, c, scriptIndex)); int extendsMultinameIndex = instance_info.get(c).super_index; - ret.get(extendsMultinameIndex).add(new ExtendsMultinameUsage(this, extendsMultinameIndex, c, scriptIndex)); + ret.get(extendsMultinameIndex).add(new SuperClassMultinameUsage(this, extendsMultinameIndex, c, scriptIndex)); for (int i = 0; i < instance_info.get(c).interfaces.length; i++) { int implementsMultinameIndex = instance_info.get(c).interfaces[i]; - ret.get(implementsMultinameIndex).add(new ImplementsMultinameUsage(this, implementsMultinameIndex, c, scriptIndex)); + ret.get(implementsMultinameIndex).add(new SuperInterfaceMultinameUsage(this, implementsMultinameIndex, c, scriptIndex)); } checkAllMultinameUsedInMethod(instance_info.get(c).iinit_index, ret, -1/*FIXME*/, c, 0, TraitMultinameUsage.TRAITS_TYPE_INSTANCE, true, null, -1); checkAllMultinameUsedInMethod(class_info.get(c).cinit_index, ret, -1/*FIXME*/, c, 0, TraitMultinameUsage.TRAITS_TYPE_CLASS, true, null, -1); @@ -1294,7 +1324,7 @@ public class ABC implements Openable { } public List findMultinameDefinition(int multinameIndex) { - List usages = findMultinameUsage(multinameIndex); + List usages = findMultinameUsage(multinameIndex, false); List ret = new ArrayList<>(); for (MultinameUsage u : usages) { if (u instanceof DefinitionUsage) { @@ -1308,7 +1338,7 @@ public class ABC implements Openable { List ret = new ArrayList<>(); for (int multinameIndex = 1; multinameIndex < constants.getMultinameCount(); multinameIndex++) { if (constants.getMultiname(multinameIndex).namespace_index == namespaceIndex) { - ret.addAll(findMultinameUsage(multinameIndex)); + ret.addAll(findMultinameUsage(multinameIndex, false)); } } return ret; @@ -1386,13 +1416,14 @@ public class ABC implements Openable { } } - public List findMultinameUsage(int multinameIndex) { + public List findMultinameUsage(int multinameIndex, boolean exactMatch) { List ret = new ArrayList<>(); if (multinameIndex == 0) { return ret; } for (int s = 0; s < script_info.size(); s++) { - findMultinameUsageInTraits(script_info.get(s).traits, multinameIndex, TraitMultinameUsage.TRAITS_TYPE_SCRIPT, s, -1, ret, -1); + checkMultinameUsedInMethod(multinameIndex, exactMatch, script_info.get(s).init_index, ret, s, -1, 0, TraitMultinameUsage.TRAITS_TYPE_SCRIPT, true, null, -1); + findMultinameUsageInTraits(script_info.get(s).traits, multinameIndex, exactMatch, TraitMultinameUsage.TRAITS_TYPE_SCRIPT, s, -1, ret, -1); } loopm: for (int t = 1; t < constants.getMultinameCount(); t++) { @@ -1420,6 +1451,7 @@ public class ABC implements Openable { } for (int s = 0; s < script_info.size(); s++) { + checkAllMultinameUsedInMethod(script_info.get(s).init_index, ret, s, -1, 0, TraitMultinameUsage.TRAITS_TYPE_SCRIPT, true, null, -1); findAllMultinameUsageInTraits(script_info.get(s).traits, TraitMultinameUsage.TRAITS_TYPE_SCRIPT, s, -1, ret, -1); } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/types/InstanceInfo.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/types/InstanceInfo.java index de5dc791b..67d91c9a3 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/types/InstanceInfo.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/types/InstanceInfo.java @@ -103,7 +103,9 @@ public class InstanceInfo { } writer.appendNoHilight(modifiers + objType); - writer.hilightSpecial(abc.constants.getMultiname(name_index).getName(abc.constants, null/* No full names here*/, false, true), HighlightSpecialType.CLASS_NAME); + String classTypeName = abc.constants.getMultiname(name_index).getNameWithNamespace(abc.constants, true).toRawString(); + + writer.hilightSpecial(abc.constants.getMultiname(name_index).getName(abc.constants, null/* No full names here*/, false, true), HighlightSpecialType.CLASS_NAME, classTypeName); if (super_index > 0) { String typeName = abc.constants.getMultiname(super_index).getNameWithNamespace(abc.constants, true).toRawString(); diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/types/ScriptInfo.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/types/ScriptInfo.java index 891ef9239..848f1082e 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/types/ScriptInfo.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/types/ScriptInfo.java @@ -63,6 +63,29 @@ public class ScriptInfo { public void clearPacksCache() { cachedPacks = null; } + + /** + * + * @param abc + * @return Simple pack name - Can be null! + */ + public DottedChain getSimplePackName(ABC abc) { + List packageTraits = new ArrayList<>(); + + for (int j = 0; j < traits.traits.size(); j++) { + Trait t = traits.traits.get(j); + Multiname name = t.getName(abc); + Namespace ns = name.getNamespace(abc.constants); + if ((ns.kind == Namespace.KIND_PACKAGE_INTERNAL) + || (ns.kind == Namespace.KIND_PACKAGE)) { + packageTraits.add(j); + } + } + if (packageTraits.isEmpty() || packageTraits.size() > 1) { + return null; + } + return traits.traits.get(packageTraits.get(0)).getName(abc).getNameWithNamespace(abc.constants, true); + } public List getPacks(ABC abc, int scriptIndex, String packagePrefix, List allAbcs) { if (packagePrefix == null && cachedPacks != null) { diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/usages/ClassNameMultinameUsage.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/usages/ClassNameMultinameUsage.java index e47108807..389a06213 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/usages/ClassNameMultinameUsage.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/usages/ClassNameMultinameUsage.java @@ -17,6 +17,7 @@ package com.jpexs.decompiler.flash.abc.usages; import com.jpexs.decompiler.flash.abc.ABC; +import com.jpexs.decompiler.flash.abc.types.InstanceInfo; /** * @@ -38,7 +39,9 @@ public class ClassNameMultinameUsage extends MultinameUsage implements Definitio @Override public String toString() { - return "class " + abc.constants.getMultiname(abc.instance_info.get(classIndex).name_index).getNameWithNamespace(abc.constants, true).toPrintableString(true) + " trait name"; + InstanceInfo ii = abc.instance_info.get(classIndex); + String kind = ii.isInterface() ? "interface" : "class"; + return kind + " " + ii.getName(abc.constants).getNameWithNamespace(abc.constants, true).toPrintableString(true) + " name"; } @Override @@ -81,4 +84,9 @@ public class ClassNameMultinameUsage extends MultinameUsage implements Definitio } return false; } + + @Override + public int getScriptIndex() { + return scriptIndex; + } } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/usages/InsideClassMultinameUsageInterface.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/usages/InsideClassMultinameUsageInterface.java index 7deee0011..5a9b313c8 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/usages/InsideClassMultinameUsageInterface.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/usages/InsideClassMultinameUsageInterface.java @@ -24,6 +24,8 @@ import com.jpexs.decompiler.flash.abc.ABC; */ public interface InsideClassMultinameUsageInterface { + public int getScriptIndex(); + public int getClassIndex(); public ABC getAbc(); diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/usages/ImplementsMultinameUsage.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/usages/SuperClassMultinameUsage.java similarity index 74% rename from libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/usages/ImplementsMultinameUsage.java rename to libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/usages/SuperClassMultinameUsage.java index 2dfd2c5d9..70b9f6cf9 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/usages/ImplementsMultinameUsage.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/usages/SuperClassMultinameUsage.java @@ -17,16 +17,17 @@ package com.jpexs.decompiler.flash.abc.usages; import com.jpexs.decompiler.flash.abc.ABC; +import com.jpexs.decompiler.flash.abc.types.InstanceInfo; /** * * @author JPEXS */ -public class ImplementsMultinameUsage extends MultinameUsage implements InsideClassMultinameUsageInterface { +public class SuperClassMultinameUsage extends MultinameUsage implements InsideClassMultinameUsageInterface { private final int classIndex; - public ImplementsMultinameUsage(ABC abc, int multinameIndex, int classIndex, int scriptIndex) { + public SuperClassMultinameUsage(ABC abc, int multinameIndex, int classIndex, int scriptIndex) { super(abc, multinameIndex, scriptIndex); this.classIndex = classIndex; } @@ -38,13 +39,15 @@ public class ImplementsMultinameUsage extends MultinameUsage implements InsideCl @Override public String toString() { - return super.toString() + " implements"; + InstanceInfo ii = abc.instance_info.get(classIndex); + String kind = ii.isInterface() ? "interface" : "class"; + return kind + " " + ii.getName(abc.constants).getNameWithNamespace(abc.constants, true) + " extends"; } @Override public int hashCode() { int hash = super.hashCode(); - hash = 59 * hash + this.classIndex; + hash = 17 * hash + this.classIndex; return hash; } @@ -62,7 +65,7 @@ public class ImplementsMultinameUsage extends MultinameUsage implements InsideCl if (!super.equals(obj)) { return false; } - final ImplementsMultinameUsage other = (ImplementsMultinameUsage) obj; + final SuperClassMultinameUsage other = (SuperClassMultinameUsage) obj; if (this.classIndex != other.classIndex) { return false; } @@ -73,4 +76,9 @@ public class ImplementsMultinameUsage extends MultinameUsage implements InsideCl public boolean collides(MultinameUsage other) { return false; } + + @Override + public int getScriptIndex() { + return scriptIndex; + } } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/usages/ExtendsMultinameUsage.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/usages/SuperInterfaceMultinameUsage.java similarity index 69% rename from libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/usages/ExtendsMultinameUsage.java rename to libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/usages/SuperInterfaceMultinameUsage.java index 06c11b490..9a515d0d9 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/usages/ExtendsMultinameUsage.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/usages/SuperInterfaceMultinameUsage.java @@ -17,16 +17,17 @@ package com.jpexs.decompiler.flash.abc.usages; import com.jpexs.decompiler.flash.abc.ABC; +import com.jpexs.decompiler.flash.abc.types.InstanceInfo; /** * * @author JPEXS */ -public class ExtendsMultinameUsage extends MultinameUsage implements InsideClassMultinameUsageInterface { +public class SuperInterfaceMultinameUsage extends MultinameUsage implements InsideClassMultinameUsageInterface { private final int classIndex; - public ExtendsMultinameUsage(ABC abc, int multinameIndex, int classIndex, int scriptIndex) { + public SuperInterfaceMultinameUsage(ABC abc, int multinameIndex, int classIndex, int scriptIndex) { super(abc, multinameIndex, scriptIndex); this.classIndex = classIndex; } @@ -38,13 +39,15 @@ public class ExtendsMultinameUsage extends MultinameUsage implements InsideClass @Override public String toString() { - return super.toString() + " extends"; + InstanceInfo ii = abc.instance_info.get(classIndex); + String kind = ii.isInterface() ? "interface" : "class"; + return kind + " " + ii.getName(abc.constants).getNameWithNamespace(abc.constants, true) + " " + (ii.isInterface() ? "extends" : "implements"); } @Override public int hashCode() { int hash = super.hashCode(); - hash = 17 * hash + this.classIndex; + hash = 59 * hash + this.classIndex; return hash; } @@ -62,7 +65,7 @@ public class ExtendsMultinameUsage extends MultinameUsage implements InsideClass if (!super.equals(obj)) { return false; } - final ExtendsMultinameUsage other = (ExtendsMultinameUsage) obj; + final SuperInterfaceMultinameUsage other = (SuperInterfaceMultinameUsage) obj; if (this.classIndex != other.classIndex) { return false; } @@ -73,4 +76,9 @@ public class ExtendsMultinameUsage extends MultinameUsage implements InsideClass public boolean collides(MultinameUsage other) { return false; } + + @Override + public int getScriptIndex() { + return scriptIndex; + } } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/usages/TraitMultinameUsage.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/usages/TraitMultinameUsage.java index d43f06980..72e418df1 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/usages/TraitMultinameUsage.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/usages/TraitMultinameUsage.java @@ -17,7 +17,9 @@ package com.jpexs.decompiler.flash.abc.usages; import com.jpexs.decompiler.flash.abc.ABC; +import com.jpexs.decompiler.flash.abc.types.InstanceInfo; import com.jpexs.decompiler.flash.abc.types.traits.Traits; +import com.jpexs.decompiler.graph.DottedChain; import java.util.Objects; /** @@ -56,7 +58,13 @@ public abstract class TraitMultinameUsage extends MultinameUsage implements Insi @Override public String toString() { - return "class " + abc.constants.getMultiname(abc.instance_info.get(classIndex).name_index).getNameWithNamespace(abc.constants, true).toPrintableString(true); + if (classIndex != -1) { + InstanceInfo ii = abc.instance_info.get(classIndex); + String kind = ii.isInterface() ? "interface" : "class"; + return kind + " " + ii.getName(abc.constants).getNameWithNamespace(abc.constants, true).toPrintableString(true); + } + DottedChain scriptSimpleName = abc.script_info.get(scriptIndex).getSimplePackName(abc); + return "script " + (scriptSimpleName == null ? "" + scriptIndex:scriptSimpleName.toPrintableString(true)); } @Override diff --git a/libsrc/ffdec_lib/testdata/as3_new/bin/as3_new.air.swf b/libsrc/ffdec_lib/testdata/as3_new/bin/as3_new.air.swf index d578e4ee2..3b0ad9933 100644 Binary files a/libsrc/ffdec_lib/testdata/as3_new/bin/as3_new.air.swf and b/libsrc/ffdec_lib/testdata/as3_new/bin/as3_new.air.swf differ diff --git a/libsrc/ffdec_lib/testdata/as3_new/bin/as3_new.flex.swf b/libsrc/ffdec_lib/testdata/as3_new/bin/as3_new.flex.swf index 9e90328ea..07e29c542 100644 Binary files a/libsrc/ffdec_lib/testdata/as3_new/bin/as3_new.flex.swf and b/libsrc/ffdec_lib/testdata/as3_new/bin/as3_new.flex.swf differ diff --git a/libsrc/ffdec_lib/testdata/as3_new/src/Main.as b/libsrc/ffdec_lib/testdata/as3_new/src/Main.as index 1f8208a4f..3ad310fd9 100644 --- a/libsrc/ffdec_lib/testdata/as3_new/src/Main.as +++ b/libsrc/ffdec_lib/testdata/as3_new/src/Main.as @@ -8,6 +8,7 @@ package import tests_classes.mypackage3.SetupMyPackage3; import tests_classes.*; import tests_edit.*; + import tests_uses.TestOtherClass; /** * ... @@ -138,6 +139,8 @@ package TestModifiers; + TestOtherClass; + public function Main() { if (stage) init(); diff --git a/libsrc/ffdec_lib/testdata/as3_new/src/tests_uses/TestClass.as b/libsrc/ffdec_lib/testdata/as3_new/src/tests_uses/TestClass.as new file mode 100644 index 000000000..2d413aac7 --- /dev/null +++ b/libsrc/ffdec_lib/testdata/as3_new/src/tests_uses/TestClass.as @@ -0,0 +1,20 @@ +package tests_uses +{ + + public class TestClass extends TestParentClass implements TestInterface + { + public var classVar:int = 2; + + public function interfaceMethod(): void { + trace("interfaceMethod"); + } + + public function parentInterfaceMethod(): void { + trace("parentInterfaceMethod"); + } + + public function classMethod(): void { + trace("classMethod"); + } + } +} diff --git a/libsrc/ffdec_lib/testdata/as3_new/src/tests_uses/TestClass2.as b/libsrc/ffdec_lib/testdata/as3_new/src/tests_uses/TestClass2.as new file mode 100644 index 000000000..3f7b5cc0f --- /dev/null +++ b/libsrc/ffdec_lib/testdata/as3_new/src/tests_uses/TestClass2.as @@ -0,0 +1,10 @@ +package tests_uses +{ + + public class TestClass2 + { + public function classMethod(): void { + trace("class2Method"); + } + } +} diff --git a/libsrc/ffdec_lib/testdata/as3_new/src/tests_uses/TestInterface.as b/libsrc/ffdec_lib/testdata/as3_new/src/tests_uses/TestInterface.as new file mode 100644 index 000000000..a2f610e21 --- /dev/null +++ b/libsrc/ffdec_lib/testdata/as3_new/src/tests_uses/TestInterface.as @@ -0,0 +1,8 @@ +package tests_uses +{ + + public interface TestInterface extends TestParentInterface + { + function interfaceMethod(): void; + } +} diff --git a/libsrc/ffdec_lib/testdata/as3_new/src/tests_uses/TestOtherClass.as b/libsrc/ffdec_lib/testdata/as3_new/src/tests_uses/TestOtherClass.as new file mode 100644 index 000000000..64ab671d2 --- /dev/null +++ b/libsrc/ffdec_lib/testdata/as3_new/src/tests_uses/TestOtherClass.as @@ -0,0 +1,37 @@ +package tests_uses +{ + + public class TestOtherClass + { + public function methodBody(): void { + var tc:TestClass = new TestClass(); + trace("method"); + } + + public function argsMethod(tc:TestClass): void { + trace("argsMethod"); + } + + public function returnTypeMethod(): TestClass { + trace("returnTypeMethod"); + return null; + } + + public function methodCall(): void { + var tc:TestClass = new TestClass(); + tc.classMethod(); + } + + public function methodCall2(): void { + var tc2:TestClass2 = new TestClass2(); + tc2.classMethod(); + } + + public function varUse(): void { + var tc:TestClass = new TestClass(); + trace(tc.parentVar); + trace(tc.classVar); + + } + } +} diff --git a/libsrc/ffdec_lib/testdata/as3_new/src/tests_uses/TestParentClass.as b/libsrc/ffdec_lib/testdata/as3_new/src/tests_uses/TestParentClass.as new file mode 100644 index 000000000..1fe590b5a --- /dev/null +++ b/libsrc/ffdec_lib/testdata/as3_new/src/tests_uses/TestParentClass.as @@ -0,0 +1,12 @@ +package tests_uses +{ + + public class TestParentClass + { + public var parentVar:int = 1; + + public function parentClassMethod(): void { + + } + } +} diff --git a/libsrc/ffdec_lib/testdata/as3_new/src/tests_uses/TestParentInterface.as b/libsrc/ffdec_lib/testdata/as3_new/src/tests_uses/TestParentInterface.as new file mode 100644 index 000000000..c2ea6d339 --- /dev/null +++ b/libsrc/ffdec_lib/testdata/as3_new/src/tests_uses/TestParentInterface.as @@ -0,0 +1,8 @@ +package tests_uses +{ + + public interface TestParentInterface + { + function parentInterfaceMethod(): void; + } +} diff --git a/src/com/jpexs/decompiler/flash/gui/abc/ABCPanel.java b/src/com/jpexs/decompiler/flash/gui/abc/ABCPanel.java index 413c52736..cb879d8d9 100644 --- a/src/com/jpexs/decompiler/flash/gui/abc/ABCPanel.java +++ b/src/com/jpexs/decompiler/flash/gui/abc/ABCPanel.java @@ -1104,7 +1104,7 @@ public class ABCPanel extends JPanel implements ItemListener, SearchListener usedAbc = new Reference<>(null); int multinameIndex = decompiledTextArea.getMultinameUnderCaret(usedAbc); if (multinameIndex > -1) { - UsageFrame usageFrame = new UsageFrame(usedAbc.getVal(), multinameIndex, ABCPanel.this, false); + UsageFrame usageFrame = new UsageFrame(usedAbc.getVal(), multinameIndex, false, ABCPanel.this, false); usageFrame.setVisible(true); } } @@ -1166,7 +1166,7 @@ public class ABCPanel extends JPanel implements ItemListener, SearchListener 0) { - UsageFrame usageFrame = new UsageFrame(abc, multinameIndex, t, false); + UsageFrame usageFrame = new UsageFrame(abc, multinameIndex, true, t, false); usageFrame.setVisible(true); } } @@ -1297,7 +1297,7 @@ public class ABCPanel extends JPanel implements ItemListener, SearchListener 1) { - UsageFrame usageFrame = new UsageFrame(usedAbc, multinameIndex, ABCPanel.this, true); + UsageFrame usageFrame = new UsageFrame(usedAbc, multinameIndex, false, ABCPanel.this, true); usageFrame.setVisible(true); return; } else if (!usages.isEmpty()) { //one diff --git a/src/com/jpexs/decompiler/flash/gui/abc/DecompiledEditorPane.java b/src/com/jpexs/decompiler/flash/gui/abc/DecompiledEditorPane.java index 4510f65be..748f55327 100644 --- a/src/com/jpexs/decompiler/flash/gui/abc/DecompiledEditorPane.java +++ b/src/com/jpexs/decompiler/flash/gui/abc/DecompiledEditorPane.java @@ -576,6 +576,7 @@ public class DecompiledEditorPane extends DebuggableEditorPane implements CaretL Highlighting sh = Highlighting.searchPos(highlightedText.getSpecialHighlights(), pos); if (sh != null) { switch (sh.getProperties().subtype) { + case CLASS_NAME: case TYPE_NAME: String typeName = sh.getProperties().specialValue; for (int i = 1; i < abc.constants.getMultinameCount(); i++) { @@ -594,7 +595,8 @@ public class DecompiledEditorPane extends DebuggableEditorPane implements CaretL break; case TRAIT_NAME: if (currentTrait != null) { - //return currentTrait.name_index; + //TODO: this should be handled better = to match method usages on the same class, not all matching classes. But that requires decompiling target usages. + return currentTrait.name_index; } break; case RETURNS: @@ -735,6 +737,24 @@ public class DecompiledEditorPane extends DebuggableEditorPane implements CaretL } } + /** + * WARNING: This won't change script. This only hilights class in current script + */ + public void gotoClassHeader() { + Highlighting tc = Highlighting.searchIndex(highlightedText.getClassHighlights(), classIndex); + if (tc != null) { + final int fpos = tc.startPos; + new Timer().schedule(new TimerTask() { + @Override + public void run() { + if (fpos <= getDocument().getLength()) { + setCaretPosition(fpos); + } + } + }, 100); + } + } + public void gotoTrait(int traitId) { boolean isScriptInit = traitId == GraphTextWriter.TRAIT_SCRIPT_INITIALIZER; diff --git a/src/com/jpexs/decompiler/flash/gui/abc/UsageFrame.java b/src/com/jpexs/decompiler/flash/gui/abc/UsageFrame.java index 34c4fb3b4..d63a10912 100644 --- a/src/com/jpexs/decompiler/flash/gui/abc/UsageFrame.java +++ b/src/com/jpexs/decompiler/flash/gui/abc/UsageFrame.java @@ -19,6 +19,7 @@ package com.jpexs.decompiler.flash.gui.abc; import com.jpexs.decompiler.flash.abc.ABC; import com.jpexs.decompiler.flash.abc.types.Multiname; import com.jpexs.decompiler.flash.abc.types.Namespace; +import com.jpexs.decompiler.flash.abc.types.traits.TraitType; import com.jpexs.decompiler.flash.abc.usages.InsideClassMultinameUsageInterface; import com.jpexs.decompiler.flash.abc.usages.MethodMultinameUsage; import com.jpexs.decompiler.flash.abc.usages.MultinameUsage; @@ -55,10 +56,18 @@ public class UsageFrame extends AppDialog implements MouseListener { private final ABCPanel abcPanel; - public UsageFrame(ABC abc, int multinameIndex, ABCPanel abcPanel, boolean definitions) { + /** + * + * @param abc + * @param multinameIndex + * @param exactMatch False = also consider Multiname.MULTINAME kind equal to QNAME with same name+namespace in the list. This is used in some of "extends/implements" cause. + * @param abcPanel + * @param definitions + */ + public UsageFrame(ABC abc, int multinameIndex, boolean exactMatch, ABCPanel abcPanel, boolean definitions) { super(abcPanel.getMainPanel().getMainFrame().getWindow()); - this.abcPanel = abcPanel; - List usages = definitions ? abc.findMultinameDefinition(multinameIndex) : abc.findMultinameUsage(multinameIndex); + this.abcPanel = abcPanel; + List usages = definitions ? abc.findMultinameDefinition(multinameIndex) : abc.findMultinameUsage(multinameIndex, exactMatch); Multiname m = abc.constants.getMultiname(multinameIndex); if (m.namespace_index > 0 && abc.constants.getNamespace(m.namespace_index).kind != Namespace.KIND_PRIVATE) { for (ABCContainerTag at : abc.getAbcTags()) { @@ -68,7 +77,7 @@ public class UsageFrame extends AppDialog implements MouseListener { } List mids = a.constants.getMultinameIds(m, abc.constants); for (int mid : mids) { - usages.addAll(definitions ? a.findMultinameDefinition(mid) : a.findMultinameUsage(mid)); + usages.addAll(definitions ? a.findMultinameDefinition(mid) : a.findMultinameUsage(mid, exactMatch)); } } } @@ -126,10 +135,12 @@ public class UsageFrame extends AppDialog implements MouseListener { if (tmu instanceof MethodMultinameUsage) { MethodMultinameUsage mmu = (MethodMultinameUsage) usage; if (mmu.isInitializer() == true) { - traitIndex = newAbc.class_info.get(mmu.getClassIndex()).static_traits.traits.size() + newAbc.instance_info.get(mmu.getClassIndex()).instance_traits.traits.size() + (mmu.getTraitsType() == TraitMultinameUsage.TRAITS_TYPE_CLASS ? 1 : 0); + traitIndex = mmu.getAbc().getGlobalTraitId(mmu.getClassIndex() == -1 ? TraitType.SCRIPT_INITIALIZER : TraitType.INITIALIZER, mmu.getTraitsType() == TraitMultinameUsage.TRAITS_TYPE_CLASS, -1, -1); } } decompiledTextArea.gotoTrait(traitIndex); + } else { + decompiledTextArea.gotoClassHeader(); } } }; @@ -138,7 +149,15 @@ public class UsageFrame extends AppDialog implements MouseListener { setTrait.run(); } else { decompiledTextArea.addScriptListener(setTrait); - abcPanel.hilightScript(abcPanel.getOpenable(), icu.getAbc().instance_info.get(icu.getClassIndex()).getName(icu.getAbc().constants).getNameWithNamespace(icu.getAbc().constants, true).toRawString()); + String scriptName; + if (icu.getClassIndex() > -1) { + scriptName = icu.getAbc().instance_info.get(icu.getClassIndex()).getName(icu.getAbc().constants).getNameWithNamespace(icu.getAbc().constants, true).toRawString(); + } else if (icu.getScriptIndex() > -1) { + scriptName = icu.getAbc().script_info.get(icu.getScriptIndex()).getSimplePackName(icu.getAbc()).toRawString(); + } else { + scriptName = ""; + } + abcPanel.hilightScript(abcPanel.getOpenable(), scriptName); } } }