Skip to content

Commit

Permalink
Allow overloads in native JsType methods.
Browse files Browse the repository at this point in the history
Change-Id: I39cc4b82949eb37f544db17abbd0788f694b18ac
  • Loading branch information
rluble committed Nov 3, 2015
1 parent 7db1ae7 commit ef18385
Show file tree
Hide file tree
Showing 11 changed files with 925 additions and 406 deletions.
3 changes: 2 additions & 1 deletion dev/core/src/com/google/gwt/dev/javac/JsInteropUtil.java
Expand Up @@ -42,6 +42,7 @@ public final class JsInteropUtil {
public static final String JSPROPERTY_CLASS = "com.google.gwt.core.client.js.JsProperty";
public static final String JSTYPE_CLASS = "com.google.gwt.core.client.js.JsType";
public static final String UNUSABLE_BY_JS = "unusable-by-js";
public static final String INVALID_JSNAME = "<invalid>";

public static void maybeSetJsInteropProperties(JDeclaredType type, Annotation... annotations) {
AnnotationBinding jsType = JdtUtil.getAnnotation(annotations, JSTYPE_CLASS);
Expand Down Expand Up @@ -172,7 +173,7 @@ private static void setJsPropertyProperties(JMethod method) {
String jsName = Introspector.decapitalize(methodName.substring(2));
method.setJsPropertyInfo(jsName, JsPropertyAccessorType.GETTER);
} else {
method.setJsPropertyInfo("<invalid>", JsPropertyAccessorType.UNDEFINED);
method.setJsPropertyInfo(INVALID_JSNAME, JsPropertyAccessorType.UNDEFINED);
}
}

Expand Down
12 changes: 8 additions & 4 deletions dev/core/src/com/google/gwt/dev/jjs/ast/JMethod.java
Expand Up @@ -16,6 +16,7 @@
package com.google.gwt.dev.jjs.ast;

import com.google.gwt.dev.common.InliningMode;
import com.google.gwt.dev.javac.JsInteropUtil;
import com.google.gwt.dev.jjs.InternalCompilerException;
import com.google.gwt.dev.jjs.SourceInfo;
import com.google.gwt.dev.jjs.SourceOrigin;
Expand Down Expand Up @@ -161,7 +162,7 @@ public String getJsName() {
continue;
}
if (jsMemberName != null && !jsMemberName.equals(jsMemberOverrideName)) {
return null;
return JsInteropUtil.INVALID_JSNAME;
}
jsMemberName = jsMemberOverrideName;
}
Expand Down Expand Up @@ -223,7 +224,7 @@ public JsPropertyAccessorType getJsPropertyAccessorType() {
return JsPropertyAccessorType.NONE;
}

public boolean isJsPropertyAccessor() {
private boolean isJsPropertyAccessor() {
return jsPropertyType != JsPropertyAccessorType.NONE;
}

Expand Down Expand Up @@ -561,15 +562,18 @@ public JType getOriginalReturnType() {
}

/**
* Returns the transitive closure of all the methods this method overrides.
* Returns the transitive closure of all the methods this method overrides; this set is ordered
* from most specific to least specific, where class methods appear before interface methods.
*/
public Set<JMethod> getOverriddenMethods() {
return overriddenMethods;
}

/**
* Returns the transitive closure of all the methods that override this method; caveat this
* list is only complete in monolithic compiles and should not be used in incremental compiles..
* list is only complete in monolithic compiles and should not be used in incremental compiles.
* The returned set is ordered in such a way that most specific overriding methods appear after
* less specific ones.
*/
public Set<JMethod> getOverridingMethods() {
return overridingMethods;
Expand Down
2 changes: 1 addition & 1 deletion dev/core/src/com/google/gwt/dev/jjs/ast/JType.java
Expand Up @@ -132,7 +132,7 @@ public String getShortName() {
* "class Name { .. }"), i.e. it is a name that does not include enclosing type names nor package.
*/
public String[] getCompoundName() {
return new String[] { shortName };
return new String[] { getShortName() };
}

/**
Expand Down
6 changes: 6 additions & 0 deletions dev/core/src/com/google/gwt/dev/jjs/ast/JTypeOracle.java
Expand Up @@ -868,6 +868,12 @@ public boolean isSubClass(JClassType type, JClassType possibleSubType) {
return subclassesByClass.containsEntry(type.getName(), possibleSubType.getName());
}

public boolean isSubType(JDeclaredType type, JDeclaredType possibleSubType) {
return subclassesByClass.containsEntry(type.getName(), possibleSubType.getName())
|| classesByImplementingInterface.containsEntry(type.getName(), possibleSubType.getName())
|| subInterfacesByInterface.containsEntry(type.getName(), possibleSubType.getName());
}

public Iterable<String> getSubTypeNames(String typeName) {
return Iterables.concat(classesByImplementingInterface.get(typeName),
subclassesByClass.get(typeName), subInterfacesByInterface.get(typeName));
Expand Down
Expand Up @@ -1472,6 +1472,7 @@ private void generateExports() {
for (JField field : type.getFields()) {
if (field.isJsInteropEntryPoint()) {
if (!field.isFinal()) {
// TODO(rluble): move waring to JsInteropRestrictionChecker.
logger.log(
TreeLogger.Type.WARN,
"Exporting effectively non-final field "
Expand Down
40 changes: 40 additions & 0 deletions dev/core/src/com/google/gwt/dev/jjs/impl/JavaAstVerifier.java
Expand Up @@ -30,9 +30,11 @@
import com.google.gwt.dev.jjs.ast.js.JsniFieldRef;
import com.google.gwt.dev.jjs.ast.js.JsniMethodRef;
import com.google.gwt.thirdparty.guava.common.collect.HashMultimap;
import com.google.gwt.thirdparty.guava.common.collect.Lists;
import com.google.gwt.thirdparty.guava.common.collect.Multimap;
import com.google.gwt.thirdparty.guava.common.collect.Sets;

import java.util.List;
import java.util.Set;

/**
Expand All @@ -48,8 +50,10 @@ public class JavaAstVerifier extends JVisitor {
private Set<String> seenTypeNames = Sets.newHashSet();
private Multimap<JDeclaredType, String> seenMethodsByType = HashMultimap.create();
private Multimap<JDeclaredType, String> seenFieldsByType = HashMultimap.create();
private JProgram program;

JavaAstVerifier(JProgram program) {
this.program = program;
for (JDeclaredType type :program.getModuleDeclaredTypes()) {
membersByType.putAll(type, type.getMethods());
membersByType.putAll(type, type.getFields());
Expand All @@ -65,6 +69,40 @@ public static void assertProgramIsConsistent(JProgram program) {
}
}

public static void assertCorrectOverriddenOrder(JProgram program, JMethod method) {
// The order of in the overriden set is most specific to least.
List<JMethod> seenMethods = Lists.newArrayList(method);
JMethod lastMethod = method;
for (JMethod overriden : method.getOverriddenMethods()) {
for (JMethod seenMethod : seenMethods) {
assert !program.typeOracle.isSubType(
seenMethod.getEnclosingType(), overriden.getEnclosingType())
: "Superclass method '" + seenMethod.getQualifiedName()
+ "' appeared before subclass method '" + overriden.getQualifiedName()
+ "' in '" + method.getQualifiedName() + "' overridden list";
}
assert overriden.getEnclosingType() instanceof JInterfaceType
|| lastMethod.getEnclosingType() instanceof JClassType
: "Class method '" + overriden.getQualifiedName()
+ "' appeared before after interface method '" + lastMethod.getQualifiedName()
+ "' in '" + method.getQualifiedName() + "' overridden list";
}
}

public static void assertCorrectOverridingOrder(JProgram program, JMethod method) {
// The order of in the overriden set is most specific to least.
List<JMethod> seenMethods = Lists.newArrayList(method);
for (JMethod overriden : method.getOverridingMethods()) {
for (JMethod seenMethod : seenMethods) {
assert !program.typeOracle.isSubType(
overriden.getEnclosingType(), seenMethod.getEnclosingType())
: "Subclass method '" + seenMethod.getQualifiedName()
+ "' appeared before superclass method '" + overriden.getQualifiedName()
+ "' in '" + method.getQualifiedName() + "' overriding list";
}
}
}

@Override
public void endVisit(JClassType x, Context ctx) {
assertNotSeenBefore(x);
Expand Down Expand Up @@ -97,6 +135,8 @@ public void endVisit(JMethod x, Context ctx) {
assert !seenMethodsByType.containsEntry(enclosingType, methodSignature) :
"Method " + x + " is duplicated.";
seenMethodsByType.put(enclosingType, methodSignature);
assertCorrectOverriddenOrder(program, x);
assertCorrectOverridingOrder(program, x);
}

@Override
Expand Down
45 changes: 45 additions & 0 deletions dev/core/src/com/google/gwt/dev/jjs/impl/JjsUtils.java
Expand Up @@ -20,6 +20,7 @@
import com.google.gwt.dev.jjs.SourceOrigin;
import com.google.gwt.dev.jjs.ast.HasName;
import com.google.gwt.dev.jjs.ast.HasType;
import com.google.gwt.dev.jjs.ast.JArrayType;
import com.google.gwt.dev.jjs.ast.JBinaryOperation;
import com.google.gwt.dev.jjs.ast.JBinaryOperator;
import com.google.gwt.dev.jjs.ast.JBlock;
Expand All @@ -30,6 +31,7 @@
import com.google.gwt.dev.jjs.ast.JDeclaredType;
import com.google.gwt.dev.jjs.ast.JDoubleLiteral;
import com.google.gwt.dev.jjs.ast.JExpression;
import com.google.gwt.dev.jjs.ast.JField;
import com.google.gwt.dev.jjs.ast.JFloatLiteral;
import com.google.gwt.dev.jjs.ast.JIntLiteral;
import com.google.gwt.dev.jjs.ast.JInterfaceType;
Expand Down Expand Up @@ -66,6 +68,7 @@
import com.google.gwt.thirdparty.guava.common.base.Joiner;
import com.google.gwt.thirdparty.guava.common.base.Predicate;
import com.google.gwt.thirdparty.guava.common.base.Predicates;
import com.google.gwt.thirdparty.guava.common.base.Strings;
import com.google.gwt.thirdparty.guava.common.collect.Collections2;
import com.google.gwt.thirdparty.guava.common.collect.FluentIterable;
import com.google.gwt.thirdparty.guava.common.collect.ImmutableMap;
Expand Down Expand Up @@ -297,6 +300,48 @@ public static JMethod createSyntheticAbstractStub(JDeclaredType type, JMethod su
return createEmptyMethodFromExample(type, superTypeMethod, true);
}

/**
* Returns a description for a type suitable for reporting errors to the users.
*/
public static String getReadableDescription(JType type) {
if (type instanceof JArrayType) {
JArrayType arrayType = (JArrayType) type;
return getReadableDescription(arrayType.getLeafType()) + Strings.repeat("[]",
arrayType.getDims());
}
return Joiner.on(".").join(type.getCompoundName());
}

/**
* Returns a description for a member suitable for reporting errors to the users.
*/
public static String getReadableDescription(JMember member) {
if (member instanceof JField) {
return String.format("%s %s.%s",
getReadableDescription(member.getType()),
getReadableDescription(member.getEnclosingType()),
member.getName());
}

JMethod method = (JMethod) member;
String printableDescription = "";
if (!method.isConstructor()) {
printableDescription += getReadableDescription(method.getType()) + " ";
}
printableDescription += String.format("%s.%s(%s)",
getReadableDescription(method.getEnclosingType()),
method.getName(),
Joiner.on(", ").join(
Iterables.transform(method.getOriginalParamTypes(), new Function<JType, String>() {
@Override
public String apply(JType type) {
return getReadableDescription(type);
}
}
)));
return printableDescription;
}

public static void replaceMethodBody(JMethod method, JExpression returnValue) {
JMethodBody body = (JMethodBody) method.getBody();
JBlock block = body.getBlock();
Expand Down

0 comments on commit ef18385

Please sign in to comment.