more fixes for prototype
Now the getDirectChildren(), getDirectChild(name) of a LocalType will
return also everything of the prototype chain.
Added various test for validation and code completion.
diff --git a/plugins/org.eclipse.dltk.javascript.core/src/org/eclipse/dltk/internal/javascript/ti/ElementValue.java b/plugins/org.eclipse.dltk.javascript.core/src/org/eclipse/dltk/internal/javascript/ti/ElementValue.java
index 4f099d3..d0d6c3c 100644
--- a/plugins/org.eclipse.dltk.javascript.core/src/org/eclipse/dltk/internal/javascript/ti/ElementValue.java
+++ b/plugins/org.eclipse.dltk.javascript.core/src/org/eclipse/dltk/internal/javascript/ti/ElementValue.java
@@ -141,7 +141,8 @@
if (!selection.isEmpty()) {
if (selection.size() == 1) {
final IRMember selected = selection.get(0);
- if ("prototype".equals(selected.getName())
+ if (IRLocalType.PROTOTYPE_PROPERTY.equals(selected
+ .getName())
&& selected instanceof IRProperty) {
if (t != null) {
return new PrototypePropertyValue(
diff --git a/plugins/org.eclipse.dltk.javascript.core/src/org/eclipse/dltk/internal/javascript/ti/TypeInferencerVisitor.java b/plugins/org.eclipse.dltk.javascript.core/src/org/eclipse/dltk/internal/javascript/ti/TypeInferencerVisitor.java
index 2585112..949ffd6 100644
--- a/plugins/org.eclipse.dltk.javascript.core/src/org/eclipse/dltk/internal/javascript/ti/TypeInferencerVisitor.java
+++ b/plugins/org.eclipse.dltk.javascript.core/src/org/eclipse/dltk/internal/javascript/ti/TypeInferencerVisitor.java
@@ -123,6 +123,7 @@
import org.eclipse.dltk.javascript.typeinfo.IRLocalType;
import org.eclipse.dltk.javascript.typeinfo.IRMapType;
import org.eclipse.dltk.javascript.typeinfo.IRMethod;
+import org.eclipse.dltk.javascript.typeinfo.IRProperty;
import org.eclipse.dltk.javascript.typeinfo.IRRecordMember;
import org.eclipse.dltk.javascript.typeinfo.IRSimpleType;
import org.eclipse.dltk.javascript.typeinfo.IRType;
@@ -448,6 +449,21 @@
&& !declaredType.isJavaScriptObject()) {
// skip assignment
return right;
+ } else {
+ // if the assignment is done on the prototype property
+ // then make sure it is not IRProperty (the one from Object itself)
+ // replace that with a AnonymousValue
+ Object attribute = leftParent
+ .getAttribute(IReferenceAttributes.ELEMENT);
+ if (attribute instanceof IRProperty
+ && ((IRProperty) attribute).getName()
+ .equals(IRLocalType.PROTOTYPE_PROPERTY)) {
+ leftParent.getParent()
+ .createChild(
+ IRLocalType.PROTOTYPE_PROPERTY)
+ .setValue(new AnonymousValue());
+ }
+
}
}
}
@@ -873,7 +889,8 @@
.getExtendsType());
thisValue.setDeclaredType(thisType);
if (thisType instanceof IRLocalType) {
- IValueReference prototype = result.createChild("prototype");
+ IValueReference prototype = result
+ .createChild(IRLocalType.PROTOTYPE_PROPERTY);
prototype.setDeclaredType(context.getType(ITypeNames.OBJECT)
.toRType(context));
Set<String> directChildren = ((IRLocalType) thisType)
diff --git a/plugins/org.eclipse.dltk.javascript.core/src/org/eclipse/dltk/javascript/typeinfo/IRLocalType.java b/plugins/org.eclipse.dltk.javascript.core/src/org/eclipse/dltk/javascript/typeinfo/IRLocalType.java
index 5137b30..5bd242d 100644
--- a/plugins/org.eclipse.dltk.javascript.core/src/org/eclipse/dltk/javascript/typeinfo/IRLocalType.java
+++ b/plugins/org.eclipse.dltk.javascript.core/src/org/eclipse/dltk/javascript/typeinfo/IRLocalType.java
@@ -21,6 +21,8 @@
* @author jcompagner
*/
public interface IRLocalType extends IRType, IRTypeExtension {
+ public static final String PROTOTYPE_PROPERTY = "prototype";
+
public IValueReference getValue();
@Nullable
diff --git a/plugins/org.eclipse.dltk.javascript.core/src/org/eclipse/dltk/javascript/typeinfo/RLocalType.java b/plugins/org.eclipse.dltk.javascript.core/src/org/eclipse/dltk/javascript/typeinfo/RLocalType.java
index bace625..c81c57e 100644
--- a/plugins/org.eclipse.dltk.javascript.core/src/org/eclipse/dltk/javascript/typeinfo/RLocalType.java
+++ b/plugins/org.eclipse.dltk.javascript.core/src/org/eclipse/dltk/javascript/typeinfo/RLocalType.java
@@ -48,15 +48,7 @@
}
public IValueReference getDirectChild(String name) {
- final IValueReference value = getValue();
- if (value.getDirectChildren(IValue.NO_LOCAL_TYPES).contains(name)) {
- return value.getChild(name);
- } else {
- JSTypeSet declaredTypes = getValue().getDeclaredTypes();
- HashSet<IRType> set = new HashSet<IRType>();
- set.add(this);
- return getChildFromDeclaredTypes(name, declaredTypes, set);
- }
+ return getChild(this, name, new HashSet<IRType>());
}
/**
@@ -67,38 +59,64 @@
private IValueReference getChildFromDeclaredTypes(String name,
JSTypeSet declaredTypes, HashSet<IRType> set) {
for (IRType irType : declaredTypes) {
- if (irType instanceof RLocalType && set.add(irType)) {
- IValueReference declaredValue = ((RLocalType) irType)
- .getValue();
- if (declaredValue.getDirectChildren(IValue.NO_LOCAL_TYPES)
- .contains(name)) {
- return declaredValue.getChild(name);
- }
- IValueReference fromChild = getChildFromDeclaredTypes(name,
- declaredValue.getDeclaredTypes(), set);
- if (fromChild != null)
- return fromChild;
+ if (irType instanceof RLocalType) {
+ IValueReference child = getChild((RLocalType) irType, name, set);
+ if (child != null)
+ return child;
}
}
return null;
}
+ private IValueReference getChild(RLocalType irType, String name,
+ HashSet<IRType> set) {
+ if (set.add(irType)) {
+ IValueReference declaredValue = irType.getValue();
+ if (declaredValue.getDirectChildren(IValue.NO_LOCAL_TYPES)
+ .contains(name)) {
+ return declaredValue.getChild(name);
+ }
+ IValueReference fromChild = getChildFromDeclaredTypes(name,
+ declaredValue.getDeclaredTypes(), set);
+ if (fromChild == null) {
+ IValueReference prototype = irType.functionValue
+ .getChild(PROTOTYPE_PROPERTY);
+ if (prototype.getDirectChildren().contains(name)) {
+ return prototype.getChild(name);
+ }
+ }
+ return fromChild;
+ }
+ return null;
+ }
+
public Set<String> getDirectChildren() {
- Set<String> children = getValue().getDirectChildren(
- IValue.NO_LOCAL_TYPES);
- JSTypeSet declaredTypes = getValue().getDeclaredTypes();
- HashSet<IRType> set = new HashSet<IRType>();
- set.add(this);
- fillDeclaredLocalTypesChildren(children, declaredTypes, set);
+ Set<String> children = new HashSet<String>();
+ fillChildren(this, children, new HashSet<IRType>());
return children;
}
+ private static void fillChildren(RLocalType rLocalType,
+ Set<String> children,
+ HashSet<IRType> set) {
+ if (set.add(rLocalType)) {
+ IValueReference value = rLocalType.getValue();
+ children.addAll(value.getDirectChildren(
+ IValue.NO_LOCAL_TYPES));
+ IValueReference prototype = rLocalType.functionValue
+ .getChild(PROTOTYPE_PROPERTY);
+ children.addAll(prototype.getDirectChildren());
+ fillDeclaredLocalTypesChildren(children, value
+ .getDeclaredTypes(), set);
+ }
+ }
+
/**
* @param children
* @param declaredTypes
* @param set
*/
- private void fillDeclaredLocalTypesChildren(Set<String> children,
+ private static void fillDeclaredLocalTypesChildren(Set<String> children,
JSTypeSet declaredTypes, HashSet<IRType> set) {
for (IRType irType : declaredTypes) {
if (irType instanceof RLocalType && set.add(irType)) {
diff --git a/tests/org.eclipse.dltk.javascript.core.tests/src/org/eclipse/dltk/javascript/core/tests/contentassist/CodeCompletion.java b/tests/org.eclipse.dltk.javascript.core.tests/src/org/eclipse/dltk/javascript/core/tests/contentassist/CodeCompletion.java
index 29bfc1e..63030a4 100644
--- a/tests/org.eclipse.dltk.javascript.core.tests/src/org/eclipse/dltk/javascript/core/tests/contentassist/CodeCompletion.java
+++ b/tests/org.eclipse.dltk.javascript.core.tests/src/org/eclipse/dltk/javascript/core/tests/contentassist/CodeCompletion.java
@@ -949,4 +949,42 @@
}
assertEquals(true, found);
}
+
+ public void testPrototypeFunctionWith2Extends() {
+ final StringList code = new StringList();
+ code.add("function A() {}");
+ code.add("A.prototype.afunction = function(){ }");
+ code.add("/**");
+ code.add(" * @extends {A}");
+ code.add(" */");
+ code.add("function B() {}");
+ code.add("B.prototype = new A();");
+ code.add("B.prototype.bfunction = function(){ }");
+ code.add("/**");
+ code.add(" * @extends {B}");
+ code.add(" */");
+ code.add("function C() {}");
+ code.add("C.prototype = new B();");
+ code.add("C.prototype.testDirectAssignment = function(){ }");
+ code.add("var x = new C();");
+ code.add("x.");
+ final IModuleSource module = new TestModule(code.toString());
+ final List<CompletionProposal> results = new ArrayList<CompletionProposal>();
+ final ICompletionEngine completionEngine = createEngine(results,
+ JSCompletionEngine.OPTION_KEYWORDS);
+ completionEngine.complete(module, lastPositionInFile(".", module), 0);
+ int found = 0;
+ for (CompletionProposal completionProposal : results) {
+ if (completionProposal.getName().equals("testDirectAssignment")) {
+ found++;
+ }
+ if (completionProposal.getName().equals("bfunction")) {
+ found++;
+ }
+ if (completionProposal.getName().equals("afunction")) {
+ found++;
+ }
+ }
+ assertEquals(3, found);
+ }
}
diff --git a/tests/org.eclipse.dltk.javascript.core.tests/src/org/eclipse/dltk/javascript/core/tests/validation/TypeInfoValidationTests.java b/tests/org.eclipse.dltk.javascript.core.tests/src/org/eclipse/dltk/javascript/core/tests/validation/TypeInfoValidationTests.java
index 1836472..329cd39 100644
--- a/tests/org.eclipse.dltk.javascript.core.tests/src/org/eclipse/dltk/javascript/core/tests/validation/TypeInfoValidationTests.java
+++ b/tests/org.eclipse.dltk.javascript.core.tests/src/org/eclipse/dltk/javascript/core/tests/validation/TypeInfoValidationTests.java
@@ -3644,5 +3644,53 @@
final List<IProblem> problems = validate(code.toString());
assertEquals(problems.toString(), 0, problems.size());
}
+
+ public void testPrototypeFunction() {
+ final StringList code = new StringList();
+ code.add("function A() {}");
+ code.add("A.prototype.testDirectAssignment = function(){ }");
+ code.add("var x = new A();");
+ code.add("x.testDirectAssignment();");
+ final List<IProblem> problems = validate(code.toString());
+ assertEquals(problems.toString(), 0, problems.size());
+ }
+ public void testPrototypeFunctionWithExtends() {
+ final StringList code = new StringList();
+ code.add("function A() {}");
+ code.add("/**");
+ code.add(" * @extends {A}");
+ code.add(" */");
+ code.add("function B() {}");
+ code.add("B.prototype = new A();");
+ code.add("B.prototype.testDirectAssignment = function(){ }");
+ code.add("var x = new B();");
+ code.add("x.testDirectAssignment();");
+ final List<IProblem> problems = validate(code.toString());
+ assertEquals(problems.toString(), 0, problems.size());
+ }
+
+ public void testPrototypeFunctionWith2Extends() {
+ final StringList code = new StringList();
+ code.add("function A() {}");
+ code.add("A.prototype.afunction = function(){ }");
+ code.add("/**");
+ code.add(" * @extends {A}");
+ code.add(" */");
+ code.add("function B() {}");
+ code.add("B.prototype = new A();");
+ code.add("B.prototype.bfunction = function(){ }");
+ code.add("/**");
+ code.add(" * @extends {B}");
+ code.add(" */");
+ code.add("function C() {}");
+ code.add("C.prototype = new B();");
+ code.add("C.prototype.testDirectAssignment = function(){ }");
+ code.add("var x = new C();");
+ code.add("x.testDirectAssignment();");
+ code.add("x.bfunction();");
+ code.add("x.afunction();");
+ final List<IProblem> problems = validate(code.toString());
+ assertEquals(problems.toString(), 0, problems.size());
+ }
}