Added: AS3 Direct editation - Error when accessing inaccessible namespace

Fixed: AS3 goto definition missing some namespaces
AS3 debug game testdata with debug info
This commit is contained in:
Jindra Petřík
2026-02-28 15:33:32 +01:00
parent 4a9e7a4688
commit 92e43cb615
15 changed files with 121 additions and 68 deletions

View File

@@ -2508,10 +2508,13 @@ public class AVM2SourceGenerator implements SourceGenerator {
*/
public static boolean searchPrototypeChain(String nsKeyword, Integer namespaceSuffix, List<Integer> otherNs, int privateNs, int protectedNs, int staticProtectedNs, int internalNs, boolean instanceOnly, AbcIndexing abc, DottedChain pkg, String obj, String propertyName, Reference<String> outName, Reference<DottedChain> outNs, Reference<DottedChain> outPropNs, Reference<Integer> outPropNsKind, Reference<Integer> outPropNsIndex, Reference<GraphTargetItem> outPropType, Reference<ValueKind> outPropValue, Reference<ABC> outPropValueAbc, Reference<Boolean> isType, Reference<Trait> outPropTrait) {
AVM2ConstantPool constants = abc.getSelectedAbc().constants;
int publicNs = constants.getNamespaceId(Namespace.KIND_PACKAGE, "", 0, false);
if (nsKeyword != null) {
switch (nsKeyword) {
case "public":
return searchPrototypeChain(0, instanceOnly, abc, pkg, obj, propertyName, outName, outNs, outPropNs, outPropNsKind, outPropNsIndex, outPropType, outPropValue, outPropValueAbc, isType, outPropTrait);
return searchPrototypeChain(publicNs, instanceOnly, abc, pkg, obj, propertyName, outName, outNs, outPropNs, outPropNsKind, outPropNsIndex, outPropType, outPropValue, outPropValueAbc, isType, outPropTrait);
case "protected":
if (searchPrototypeChain(staticProtectedNs, instanceOnly, abc, pkg, obj, propertyName, outName, outNs, outPropNs, outPropNsKind, outPropNsIndex, outPropType, outPropValue, outPropValueAbc, isType, outPropTrait)) {
return true;
@@ -2542,14 +2545,14 @@ public class AVM2SourceGenerator implements SourceGenerator {
}
}
return searchPrototypeChain(0, instanceOnly, abc, pkg, obj, propertyName, outName, outNs, outPropNs, outPropNsKind, outPropNsIndex, outPropType, outPropValue, outPropValueAbc, isType, outPropTrait);
return searchPrototypeChain(publicNs, instanceOnly, abc, pkg, obj, propertyName, outName, outNs, outPropNs, outPropNsKind, outPropNsIndex, outPropType, outPropValue, outPropValueAbc, isType, outPropTrait);
}
private static boolean searchPrototypeChain(int selectedNs, boolean instanceOnly, AbcIndexing abc, DottedChain pkg, String obj, String propertyName, Reference<String> outName, Reference<DottedChain> outNs, Reference<DottedChain> outPropNs, Reference<Integer> outPropNsKind, Reference<Integer> outPropNsIndex, Reference<GraphTargetItem> outPropType, Reference<ValueKind> outPropValue, Reference<ABC> outPropValueAbc, Reference<Boolean> isType, Reference<Trait> outPropTrait) {
isType.setVal(false);
AbcIndexing.TraitIndex sp = abc.findScriptProperty(pkg.addWithSuffix(propertyName));
if (sp == null) {
Reference<Boolean> foundStatic = new Reference<>(null);
Reference<Boolean> foundStatic = new Reference<>(null);
sp = abc.findProperty(new AbcIndexing.PropertyDef(propertyName, new TypeItem(pkg.addWithSuffix(obj)), abc.getSelectedAbc(), selectedNs), !instanceOnly, true, true, foundStatic);
}
if (sp != null) {
@@ -3086,7 +3089,7 @@ public class AVM2SourceGenerator implements SourceGenerator {
ret.add(ins(AVM2Instructions.NewObject, 0));
ret.add(ins(AVM2Instructions.PushWith));
scope = localData.scopeStack.size();
localData.scopeStack.add(new PropertyAVM2Item(null, false, item.functionName, "" /*??*/, abcIndex, new ArrayList<>(), localData.callStack, false, null));
localData.scopeStack.add(new PropertyAVM2Item(null, false, item.functionName, "" /*??*/, abcIndex, new ArrayList<>(), localData.callStack, false, null, -1));
}
AVM2ConstantPool constants = abcIndex.getSelectedAbc().constants;
ret.add(ins(AVM2Instructions.NewFunction, method(null, false, constants.getStringId(item.functionName, true), true, false, false, localData.callStack, localData.pkg, item.needsActivation, item.subvariables, 0 /*Set later*/, item.hasRest, item.line, localData.currentClassBaseName, null, false, localData, item.paramTypes, item.paramNames, item.paramValues, item.body, item.retType)));

View File

@@ -162,13 +162,16 @@ public final class AbcIndexing {
return;
}
Namespace ns = abc.constants.getNamespace(propNsIndex);
this.propNsKind = ns.kind;
//this.propNsKind = ns.kind;
switch (ns.kind) {
case Namespace.KIND_PACKAGE:
case Namespace.KIND_NAMESPACE:
case Namespace.KIND_PACKAGE:
case Namespace.KIND_PACKAGE_INTERNAL:
case Namespace.KIND_PROTECTED:
case Namespace.KIND_STATIC_PROTECTED:
this.abc = null;
//this.abc = null;
//this.propNsString = abc.constants.getNamespace(propNsIndex).getRawName(abc.constants);
break;
case Namespace.KIND_NAMESPACE:
this.propNsString = abc.constants.getNamespace(propNsIndex).getRawName(abc.constants);
break;
default:
@@ -187,8 +190,11 @@ public final class AbcIndexing {
this.propName = propName;
this.parent = parent;
this.abc = null;
this.propNsKind = nsKind;
this.propNsString = propNsString;
if (nsKind == Namespace.KIND_NAMESPACE) {
this.propNsString = propNsString;
}
//this.propNsKind = nsKind;
//this.propNsString = propNsString;
}
@Override
@@ -242,12 +248,7 @@ public final class AbcIndexing {
private int propNsIndex = 0;
private ABC abc = null;
private void setPrivate(ABC abc, int propNsIndex) {
this.propNsIndex = propNsIndex;
this.abc = abc;
}
private ABC abc = null;
/**
* Gets property name
@@ -280,9 +281,12 @@ public final class AbcIndexing {
return;
}
int k = abc.constants.getNamespace(nsIndex).kind;
if (k != Namespace.KIND_PACKAGE) {
/*if (k != Namespace.KIND_PACKAGE) {
setPrivate(abc, nsIndex);
}
}*/
this.propNsIndex = nsIndex;
this.abc = abc;
}
/**
@@ -840,33 +844,26 @@ public final class AbcIndexing {
* @param prop Property to find
* @param findStatic Find static properties
* @param findInstance Find instance properties
* @param foundStatic Whether result is static
* @return Trait index or null
*/
public TraitIndex findNsProperty(PropertyNsDef prop, boolean findStatic, boolean findInstance) {
if (findStatic && classNsProperties.containsKey(prop)) {
if (!classNsProperties.containsKey(prop)) {
if (parent != null) {
TraitIndex ret = parent.findNsProperty(prop, findStatic, findInstance);
if (ret != null) {
return ret;
}
}
} else {
public TraitIndex findNsProperty(PropertyNsDef prop, boolean findStatic, boolean findInstance, Reference<Boolean> foundStatic) {
if (findStatic) {
if (classNsProperties.containsKey(prop)) {
foundStatic.setVal(true);
return classNsProperties.get(prop);
}
}
}
if (findInstance && instanceNsProperties.containsKey(prop)) {
if (!instanceNsProperties.containsKey(prop)) {
if (parent != null) {
TraitIndex ret = parent.findNsProperty(prop, findStatic, findInstance);
if (ret != null) {
return ret;
}
}
} else {
return instanceNsProperties.get(prop);
}
foundStatic.setVal(false);
return instanceNsProperties.get(prop);
}
if (parent != null) {
TraitIndex ret = parent.findProperty(new PropertyDef(prop.propName, new TypeItem(prop.ns), prop.abc, prop.propNsIndex), findStatic, findInstance, true, foundStatic);
if (ret != null) {
return ret;
}
}
return null;
}

View File

@@ -358,7 +358,7 @@ public class ActionScript3Parser {
if (ns != null) {
ret = new NamespacedAVM2Item(ns, propName, propItem, ret, attr, openedNamespaces, null);
} else {
ret = new PropertyAVM2Item(ret, attr, propName, nsSuffix, abcIndex, openedNamespaces, new ArrayList<>(), nullDot, nsKeyword);
ret = new PropertyAVM2Item(ret, attr, propName, nsSuffix, abcIndex, openedNamespaces, new ArrayList<>(), nullDot, nsKeyword, lexer.yyline());
}
s = lex();
}
@@ -472,7 +472,7 @@ public class ActionScript3Parser {
}
if (nsname != null) {
if (nsKeyword != null && nspropItem == null) {
ret = new PropertyAVM2Item(ret, nsAtribute, nsprop, nsSuffix, abcIndex, openedNamespaces, new ArrayList<MethodBody>(), false, nsKeyword);
ret = new PropertyAVM2Item(ret, nsAtribute, nsprop, nsSuffix, abcIndex, openedNamespaces, new ArrayList<MethodBody>(), false, nsKeyword, lexer.yyline());
} else {
UnresolvedAVM2Item ns = new UnresolvedAVM2Item(new ArrayList<>(), importedClasses, typeOnly, null, lexer.yyline(), new DottedChain(new String[]{nsname}), null, openedNamespaces, abcIndex);
variables.add(ns);

View File

@@ -16,6 +16,7 @@
*/
package com.jpexs.decompiler.flash.abc.avm2.parser.script;
import com.jpexs.decompiler.flash.SWF;
import com.jpexs.decompiler.flash.abc.ABC;
import com.jpexs.decompiler.flash.abc.avm2.parser.AVM2ParseException;
import com.jpexs.decompiler.flash.simpleparser.CatchScope;
@@ -2371,7 +2372,11 @@ public class ActionScript3SimpleParser implements SimpleParser {
List<VariableOrScope> vars = new ArrayList<>();
List<DottedChain> importedClasses = new ArrayList<>();
List<NamespaceItem> openedNamespaces = new ArrayList<>();
for (String name : abc.getSwf().getAbcIndex().getPackageObjects(DottedChain.TOPLEVEL)) {
SWF swf = abc.getSwf();
if (swf == null) {
return;
}
for (String name : swf.getAbcIndex().getPackageObjects(DottedChain.TOPLEVEL)) {
externalTypes.add(new Path(name));
}
externalTypes.add(new Path("__AS3__", "vec", "Vector"));

View File

@@ -136,7 +136,7 @@ public class CallAVM2Item extends AVM2Item {
nobj.setRegNumber(0);
obj = nobj;
}*/
PropertyAVM2Item p = new PropertyAVM2Item(obj, n.isAttribute(), n.getVariableName(), n.getNamespaceSuffix(), g.abcIndex, n.openedNamespaces, new ArrayList<>(), false, null);
PropertyAVM2Item p = new PropertyAVM2Item(obj, n.isAttribute(), n.getVariableName(), n.getNamespaceSuffix(), g.abcIndex, n.openedNamespaces, new ArrayList<>(), false, null, line);
p.setAssignedValue(n.getAssignedValue());
callable = p;
}

View File

@@ -136,7 +136,7 @@ public class NamespaceItem {
}
if (kind == KIND_NAMESPACE_CUSTOM) {
String custom = name.toRawString();
PropertyAVM2Item prop = new PropertyAVM2Item(null, false, custom, "", abcIndex, openedNamespaces, new ArrayList<>(), false, null);
PropertyAVM2Item prop = new PropertyAVM2Item(null, false, custom, "", abcIndex, openedNamespaces, new ArrayList<>(), false, null, -1);
Reference<ValueKind> value = new Reference<>(null);
Reference<ABC> outAbc = new Reference<>(null);
Reference<Boolean> isType = new Reference<>(false);

View File

@@ -45,8 +45,10 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Objects;
import java.util.logging.Level;
import java.util.logging.Logger;
@@ -98,10 +100,12 @@ public class PropertyAVM2Item extends AssignableAVM2Item {
public List<GraphTargetItem> scopeStack = new ArrayList<>();
private final boolean nullish;
private final String nsKeyword;
private int line;
@Override
public AssignableAVM2Item copy() {
PropertyAVM2Item p = new PropertyAVM2Item(object, attribute, propertyName, namespaceSuffix, abcIndex, openedNamespaces, callStack, nullish, nsKeyword);
PropertyAVM2Item p = new PropertyAVM2Item(object, attribute, propertyName, namespaceSuffix, abcIndex, openedNamespaces, callStack, nullish, nsKeyword, line);
return p;
}
@@ -117,8 +121,9 @@ public class PropertyAVM2Item extends AssignableAVM2Item {
* @param callStack Call stack
* @param nullish Nullish
* @param nsKeyword Namespace keyword (public,protected,private,internal)
* @param line Source code line
*/
public PropertyAVM2Item(GraphTargetItem object, boolean attribute, String propertyName, String namespaceSuffix, AbcIndexing abcIndex, List<NamespaceItem> openedNamespaces, List<MethodBody> callStack, boolean nullish, String nsKeyword) {
public PropertyAVM2Item(GraphTargetItem object, boolean attribute, String propertyName, String namespaceSuffix, AbcIndexing abcIndex, List<NamespaceItem> openedNamespaces, List<MethodBody> callStack, boolean nullish, String nsKeyword, int line) {
this.attribute = attribute;
this.propertyName = propertyName;
this.namespaceSuffix = namespaceSuffix;
@@ -128,6 +133,7 @@ public class PropertyAVM2Item extends AssignableAVM2Item {
this.callStack = callStack;
this.nullish = nullish;
this.nsKeyword = nsKeyword;
this.line = line;
}
@Override
@@ -302,7 +308,7 @@ public class PropertyAVM2Item extends AssignableAVM2Item {
propValueAbc = sp.abc;
propTrait = sp.trait;
}
}
}
if (propType == null && AVM2SourceGenerator.searchPrototypeChain(nsKeyword, namespaceSuffixInt, otherNs, localData.privateNs, localData.protectedNs, localData.staticProtectedNs, localData.internalNs, false, abcIndex, ftn.getWithoutLast(), ftn.getLast(), propertyName, outName, outNs, outPropNs, outPropNsKind, outPropNsIndex, outPropType, outPropValue, outPropValueAbc, isType, outPropTrait)) {
objType = new TypeItem(outNs.getVal().addWithSuffix(outName.getVal()));
propType = outPropType.getVal();
@@ -313,6 +319,39 @@ public class PropertyAVM2Item extends AssignableAVM2Item {
propValue = outPropValue.getVal();
propValueAbc = outPropValueAbc.getVal();
propTrait = outPropTrait.getVal();
int nsIndex = propTrait.getName(propValueAbc).namespace_index;
Namespace ns = propValueAbc.constants.getNamespace(nsIndex);
String pkg = ftn.getWithoutLast().toRawString();
switch (ns.kind) {
case Namespace.KIND_PRIVATE:
if (!(otherNs.contains(nsIndex) && propValueAbc == abc)) {
throw new CompilationException("Property " + propertyName + " has private access in " + objType.toString(), line);
}
break;
case Namespace.KIND_PACKAGE_INTERNAL:
if (!pkg.equals(localData.pkg.toRawString())) {
throw new CompilationException("Property " + propertyName + " has package internal access in " + objType.toString(), line);
}
break;
case Namespace.KIND_PROTECTED:
case Namespace.KIND_STATIC_PROTECTED:
AbcIndexing.ClassIndex ci = abcIndex.findClass(thisType, abc, localData.scriptIndex);
boolean found = false;
String nsName = ns.getName(propValueAbc.constants).toRawString();
while (ci != null) {
DottedChain clsName = ci.abc.instance_info.get(ci.index).getName(ci.abc.constants).getNameWithNamespace(new HashSet<>(), ci.abc, ci.abc.constants, false);
String clsNsName = clsName.isTopLevel() ? clsName.getLast() : clsName.getWithoutLast().toRawString() + ":" + clsName.getLast();
if (Objects.equals(nsName, clsNsName)) {
found = true;
break;
}
ci = ci.parent;
}
if (!found) {
throw new CompilationException("Property " + propertyName + " has protected access in " + objType.toString(), line);
}
break;
}
}
}
}
@@ -364,7 +403,8 @@ public class PropertyAVM2Item extends AssignableAVM2Item {
}
}
if (nsKind == Namespace.KIND_PACKAGE && propertyName != null) {
AbcIndexing.TraitIndex p = abcIndex.findNsProperty(new AbcIndexing.PropertyNsDef(propertyName, nsname, abc, nsindex), true, true);
Reference<Boolean> foundStatic = new Reference<>(null);
AbcIndexing.TraitIndex p = abcIndex.findNsProperty(new AbcIndexing.PropertyNsDef(propertyName, nsname, abc, nsindex), true, true, foundStatic);
Reference<String> outName = new Reference<>("");
Reference<DottedChain> outNs = new Reference<>(DottedChain.EMPTY);

View File

@@ -420,7 +420,7 @@ public class UnresolvedAVM2Item extends AssignableAVM2Item {
ret.setRegNumber(n.getRegNumber());
resolved = ret;
for (int i = 1; i < name.size(); i++) {
resolved = new PropertyAVM2Item(resolved, name.isAttribute(i), name.get(i), name.getNamespaceSuffix(i), abc, openedNamespaces, new ArrayList<>(), false, null);
resolved = new PropertyAVM2Item(resolved, name.isAttribute(i), name.get(i), name.getNamespaceSuffix(i), abc, openedNamespaces, new ArrayList<>(), false, null, line);
if (i == name.size() - 1) {
((PropertyAVM2Item) resolved).assignedValue = assignedValue;
}
@@ -447,7 +447,7 @@ public class UnresolvedAVM2Item extends AssignableAVM2Item {
GraphTargetItem ret = new NameAVM2Item(t, line, name.isAttribute(0), name.get(0), name.getNamespaceSuffix(0), null, false, openedNamespaces, abcIndex, false);
resolved = ret;
for (int i = 1; i < name.size(); i++) {
resolved = new PropertyAVM2Item(resolved, name.isAttribute(i), name.get(i), name.getNamespaceSuffix(i), abc, openedNamespaces, new ArrayList<>(), false, null);
resolved = new PropertyAVM2Item(resolved, name.isAttribute(i), name.get(i), name.getNamespaceSuffix(i), abc, openedNamespaces, new ArrayList<>(), false, null, line);
if (i == name.size() - 1) {
((PropertyAVM2Item) resolved).assignedValue = assignedValue;
}
@@ -460,7 +460,7 @@ public class UnresolvedAVM2Item extends AssignableAVM2Item {
boolean isProperty = false;
if (localData != null) { //resolve can be called without localData
PropertyAVM2Item resolvedx = new PropertyAVM2Item(null, name.isAttribute(0), name.get(0), name.getNamespaceSuffix(0), abc, openedNamespaces, callStack, false, null);
PropertyAVM2Item resolvedx = new PropertyAVM2Item(null, name.isAttribute(0), name.get(0), name.getNamespaceSuffix(0), abc, openedNamespaces, callStack, false, null, line);
((PropertyAVM2Item) resolvedx).scopeStack = scopeStack;
((PropertyAVM2Item) resolvedx).setAssignedValue(assignedValue);
Reference<GraphTargetItem> objectType = new Reference<>(null);
@@ -490,7 +490,7 @@ public class UnresolvedAVM2Item extends AssignableAVM2Item {
if (ci != null) {
resolved = ti;
for (int i = 1; i < name.size(); i++) {
resolved = new PropertyAVM2Item(resolved, name.isAttribute(i), name.get(i), name.getNamespaceSuffix(i), abc, openedNamespaces, new ArrayList<>(), false, null);
resolved = new PropertyAVM2Item(resolved, name.isAttribute(i), name.get(i), name.getNamespaceSuffix(i), abc, openedNamespaces, new ArrayList<>(), false, null, line);
if (i == name.size() - 1) {
((PropertyAVM2Item) resolved).assignedValue = assignedValue;
}
@@ -517,7 +517,7 @@ public class UnresolvedAVM2Item extends AssignableAVM2Item {
}
resolved = ti;
for (int i = 1; i < name.size(); i++) {
resolved = new PropertyAVM2Item(resolved, name.isAttribute(i), name.get(i), name.getNamespaceSuffix(i), abc, openedNamespaces, new ArrayList<>(), false, null);
resolved = new PropertyAVM2Item(resolved, name.isAttribute(i), name.get(i), name.getNamespaceSuffix(i), abc, openedNamespaces, new ArrayList<>(), false, null, line);
if (i == name.size() - 1) {
((PropertyAVM2Item) resolved).assignedValue = assignedValue;
}
@@ -536,7 +536,7 @@ public class UnresolvedAVM2Item extends AssignableAVM2Item {
resolved = ret;
for (int i = 1; i < name.size(); i++) {
resolved = new PropertyAVM2Item(resolved, name.isAttribute(i), name.get(i), name.getNamespaceSuffix(i), abc, openedNamespaces, new ArrayList<>(), false, null);
resolved = new PropertyAVM2Item(resolved, name.isAttribute(i), name.get(i), name.getNamespaceSuffix(i), abc, openedNamespaces, new ArrayList<>(), false, null, line);
if (i == name.size() - 1) {
((PropertyAVM2Item) resolved).assignedValue = assignedValue;
}
@@ -573,7 +573,7 @@ public class UnresolvedAVM2Item extends AssignableAVM2Item {
TypeItem ret = new TypeItem(fname);
resolved = ret;
for (int j = i + 1; j < name.size(); j++) {
resolved = new PropertyAVM2Item(resolved, name.isAttribute(j), name.get(j), name.getNamespaceSuffix(j), abc, openedNamespaces, new ArrayList<>(), false, null);
resolved = new PropertyAVM2Item(resolved, name.isAttribute(j), name.get(j), name.getNamespaceSuffix(j), abc, openedNamespaces, new ArrayList<>(), false, null, line);
if (j == name.size() - 1) {
((PropertyAVM2Item) resolved).assignedValue = assignedValue;
}
@@ -602,7 +602,7 @@ public class UnresolvedAVM2Item extends AssignableAVM2Item {
TypeItem ret = ti;
resolved = ret;
for (int i = 1; i < name.size(); i++) {
resolved = new PropertyAVM2Item(resolved, name.isAttribute(i), name.get(i), name.getNamespaceSuffix(i), abc, openedNamespaces, new ArrayList<>(), false, null);
resolved = new PropertyAVM2Item(resolved, name.isAttribute(i), name.get(i), name.getNamespaceSuffix(i), abc, openedNamespaces, new ArrayList<>(), false, null, line);
if (i == name.size() - 1) {
((PropertyAVM2Item) resolved).assignedValue = assignedValue;
}
@@ -639,7 +639,7 @@ public class UnresolvedAVM2Item extends AssignableAVM2Item {
NameAVM2Item ret = new NameAVM2Item(ntype, line, name.isAttribute(0), name.get(0), name.getNamespaceSuffix(0), null, false, openedNamespaces, abcIndex, false);
resolved = ret;
for (int i = 1; i < name.size(); i++) {
resolved = new PropertyAVM2Item(resolved, name.isAttribute(i), name.get(i), name.getNamespaceSuffix(i), abc, openedNamespaces, new ArrayList<>(), false, null);
resolved = new PropertyAVM2Item(resolved, name.isAttribute(i), name.get(i), name.getNamespaceSuffix(i), abc, openedNamespaces, new ArrayList<>(), false, null, line);
if (i == name.size() - 1) {
((PropertyAVM2Item) resolved).assignedValue = assignedValue;
}
@@ -662,7 +662,7 @@ public class UnresolvedAVM2Item extends AssignableAVM2Item {
resolved = null;
GraphTargetItem ret = null;
for (int i = 0; i < name.size(); i++) {
resolved = new PropertyAVM2Item(resolved, name.isAttribute(i), name.get(i), name.getNamespaceSuffix(i), abc, openedNamespaces, callStack, false, null);
resolved = new PropertyAVM2Item(resolved, name.isAttribute(i), name.get(i), name.getNamespaceSuffix(i), abc, openedNamespaces, callStack, false, null, line);
if (ret == null) {
((PropertyAVM2Item) resolved).scopeStack = scopeStack;
ret = resolved;