Skip to content

Commit 40d7c38

Browse files
committed
Merge remote-tracking branch 'anba/DefineClassMapInheritanceBug'
2 parents 2c6d66d + fa7e69f commit 40d7c38

File tree

2 files changed

+60
-0
lines changed

2 files changed

+60
-0
lines changed

src/org/mozilla/javascript/ScriptableObject.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1255,6 +1255,15 @@ static <T extends Scriptable> BaseFunction buildClassCtor(
12551255
Scriptable proto = (Scriptable) protoCtor.newInstance(ScriptRuntime.emptyArgs);
12561256
String className = proto.getClassName();
12571257

1258+
// check for possible redefinition
1259+
Object existing = getProperty(getTopLevelScope(scope), className);
1260+
if (existing instanceof BaseFunction) {
1261+
Object existingProto = ((BaseFunction)existing).getPrototypeProperty();
1262+
if (clazz.equals(existingProto.getClass())) {
1263+
return (BaseFunction)existing;
1264+
}
1265+
}
1266+
12581267
// Set the prototype's prototype, trying to map Java inheritance to JS
12591268
// prototype-based inheritance if requested to do so.
12601269
Scriptable superProto = null;
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
package org.mozilla.javascript.tests;
2+
3+
import static org.junit.Assert.*;
4+
5+
import java.lang.reflect.InvocationTargetException;
6+
7+
import org.junit.Test;
8+
import org.mozilla.javascript.Context;
9+
import org.mozilla.javascript.ScriptableObject;
10+
11+
@SuppressWarnings("serial")
12+
public class DefineClassMapInheritance {
13+
14+
public static class Food extends ScriptableObject {
15+
@Override
16+
public String getClassName() {
17+
return getClass().getSimpleName();
18+
}
19+
}
20+
21+
public static class Fruit extends Food {
22+
}
23+
24+
public static class Vegetable extends Food {
25+
}
26+
27+
@Test
28+
public void test() throws IllegalAccessException, InstantiationException,
29+
InvocationTargetException {
30+
Context cx = Context.enter();
31+
try {
32+
ScriptableObject scope = cx.initStandardObjects();
33+
34+
// define two classes that share a parent prototype
35+
ScriptableObject.defineClass(scope, Fruit.class, false, true);
36+
ScriptableObject.defineClass(scope, Vegetable.class, false, true);
37+
38+
assertEquals(Boolean.TRUE,
39+
evaluate(cx, scope, "(new Fruit instanceof Food)"));
40+
assertEquals(Boolean.TRUE,
41+
evaluate(cx, scope, "(new Vegetable instanceof Food)"));
42+
} finally {
43+
Context.exit();
44+
}
45+
}
46+
47+
private static Object evaluate(Context cx, ScriptableObject scope,
48+
String source) {
49+
return cx.evaluateString(scope, source, "<eval>", 1, null);
50+
}
51+
}

0 commit comments

Comments
 (0)