Changes long warnings to errors. A new annotation is now required to compile without errors.
- LongFromJSNIChecker is now implemented totally in terms of JDT.
- The trick was to do lookup via Scope.getType(), not scope.environment.askForType(). The former has all kinds of smarts for resolving graphs of type references in a dependency-driven manner. The latter bypasses all the smarts and just asks the source oracle, which won't know.
Patch by: spoon
Review by: me
git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@2339 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/dev/core/src/com/google/gwt/dev/jdt/AstCompiler.java b/dev/core/src/com/google/gwt/dev/jdt/AstCompiler.java
index f7fe488..8def4ac 100644
--- a/dev/core/src/com/google/gwt/dev/jdt/AstCompiler.java
+++ b/dev/core/src/com/google/gwt/dev/jdt/AstCompiler.java
@@ -122,6 +122,7 @@
protected void doCompilationUnitDeclarationValidation(
CompilationUnitDeclaration cud, TreeLogger logger) {
JSORestrictionsChecker.check(cud);
+ LongFromJSNIChecker.check(cud);
BinaryTypeReferenceRestrictionsChecker.check(cud);
}
}
diff --git a/dev/core/src/com/google/gwt/dev/jdt/LongFromJSNIChecker.java b/dev/core/src/com/google/gwt/dev/jdt/LongFromJSNIChecker.java
index edffb59..ff53b63 100644
--- a/dev/core/src/com/google/gwt/dev/jdt/LongFromJSNIChecker.java
+++ b/dev/core/src/com/google/gwt/dev/jdt/LongFromJSNIChecker.java
@@ -15,35 +15,27 @@
*/
package com.google.gwt.dev.jdt;
-import com.google.gwt.core.ext.TreeLogger;
-import com.google.gwt.core.ext.typeinfo.JClassType;
-import com.google.gwt.core.ext.typeinfo.JField;
-import com.google.gwt.core.ext.typeinfo.JMethod;
-import com.google.gwt.core.ext.typeinfo.JParameter;
-import com.google.gwt.core.ext.typeinfo.JPrimitiveType;
-import com.google.gwt.core.ext.typeinfo.JType;
-import com.google.gwt.core.ext.typeinfo.TypeOracle;
-import com.google.gwt.dev.jjs.InternalCompilerException;
-import com.google.gwt.dev.util.Jsni;
+import com.google.gwt.core.client.UnsafeNativeLong;
import com.google.gwt.dev.util.JsniRef;
+import org.eclipse.jdt.core.compiler.CharOperation;
import org.eclipse.jdt.internal.compiler.ASTVisitor;
-import org.eclipse.jdt.internal.compiler.CompilationResult;
import org.eclipse.jdt.internal.compiler.ast.ASTNode;
+import org.eclipse.jdt.internal.compiler.ast.Annotation;
import org.eclipse.jdt.internal.compiler.ast.Argument;
import org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration;
import org.eclipse.jdt.internal.compiler.ast.MethodDeclaration;
import org.eclipse.jdt.internal.compiler.ast.TypeReference;
import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
-import org.eclipse.jdt.internal.compiler.impl.CompilerOptions;
import org.eclipse.jdt.internal.compiler.lookup.ArrayBinding;
import org.eclipse.jdt.internal.compiler.lookup.BaseTypeBinding;
import org.eclipse.jdt.internal.compiler.lookup.ClassScope;
+import org.eclipse.jdt.internal.compiler.lookup.FieldBinding;
+import org.eclipse.jdt.internal.compiler.lookup.MethodBinding;
+import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding;
import org.eclipse.jdt.internal.compiler.lookup.TypeBinding;
import org.eclipse.jdt.internal.compiler.lookup.TypeIds;
-import org.eclipse.jdt.internal.compiler.util.Util;
-import java.lang.reflect.Field;
import java.util.Set;
/**
@@ -60,7 +52,7 @@
ClassFileConstants {
@Override
public void endVisit(MethodDeclaration meth, ClassScope scope) {
- if (meth.isNative() && !suppressingWarnings(meth, scope)) {
+ if (meth.isNative() && !hasUnsafeLongsAnnotation(meth, scope)) {
checkDecl(meth, scope);
checkRefs(meth, scope);
}
@@ -69,15 +61,16 @@
private void checkDecl(MethodDeclaration meth, ClassScope scope) {
TypeReference returnType = meth.returnType;
if (containsLong(returnType, scope)) {
- warn(meth, "Return value of type '" + returnType
- + "' is an opaque, non-numeric value in JS code");
+ longAccessError(meth, "Type '" + typeString(returnType)
+ + "' may not be returned from a JSNI method");
}
if (meth.arguments != null) {
for (Argument arg : meth.arguments) {
if (containsLong(arg.type, scope)) {
- warn(arg, "Parameter '" + String.valueOf(arg.name) + "': '"
- + arg.type + "' is an opaque, non-numeric value in JS code");
+ longAccessError(arg, "Parameter '" + String.valueOf(arg.name)
+ + "': type '" + typeString(arg.type)
+ + "' is not safe to access in JSNI code");
}
}
}
@@ -85,38 +78,41 @@
private void checkFieldRef(MethodDeclaration meth, JsniRef jsniRef) {
assert jsniRef.isField();
- JField target = getField(jsniRef);
+ FieldBinding target = getField(jsniRef);
if (target == null) {
return;
}
- if (containsLong(target.getType())) {
- warn(meth, "Referencing field '"
- + target.getEnclosingType().getSimpleSourceName() + "."
- + target.getName() + "': '" + target.getType()
- + "' is an opaque, non-numeric value in JS code");
+ if (containsLong(target.type)) {
+ longAccessError(meth, "Referencing field '" + jsniRef.className() + "."
+ + jsniRef.memberName() + "': type '" + typeString(target.type)
+ + "' is not safe to access in JSNI code");
}
}
private void checkMethodRef(MethodDeclaration meth, JsniRef jsniRef) {
assert jsniRef.isMethod();
- JMethod target = getMethod(jsniRef);
+ MethodBinding target = getMethod(jsniRef);
if (target == null) {
return;
}
- if (containsLong(target.getReturnType())) {
- warn(meth, "Referencing method '"
- + target.getEnclosingType().getSimpleSourceName() + "."
- + target.getName() + "': return type '" + target.getReturnType()
- + "' is an opaque, non-numeric value in JS code");
+ if (containsLong(target.returnType)) {
+ longAccessError(meth, "Referencing method '" + jsniRef.className()
+ + "." + jsniRef.memberName() + "': return type '"
+ + typeString(target.returnType)
+ + "' is not safe to access in JSNI code");
}
- for (JParameter param : target.getParameters()) {
- if (containsLong(param.getType())) {
- warn(meth, "Referencing method '"
- + target.getEnclosingType().getSimpleSourceName() + "."
- + target.getName() + "': parameter '" + param.getName() + "': '"
- + param.getType()
- + "' is an opaque, non-numeric value in JS code");
+ if (target.parameters != null) {
+ int i = 0;
+ for (TypeBinding paramType : target.parameters) {
+ ++i;
+ if (containsLong(paramType)) {
+ // It would be nice to print the parameter name, but how to find it?
+ longAccessError(meth, "Parameter " + i + " of method '"
+ + jsniRef.className() + "." + jsniRef.memberName()
+ + "': type '" + typeString(paramType)
+ + "' may not be passed out of JSNI code");
+ }
}
}
}
@@ -138,13 +134,6 @@
}
}
- private boolean containsLong(JType type) {
- if (type != null && type.isArray() != null) {
- return containsLong(type.isArray().getLeafType());
- }
- return type == JPrimitiveType.LONG;
- }
-
/**
* Check whether the argument type is long or an array of (arrays of...)
* long. If the argument is <code>null</code>, returns <code>false</code>.
@@ -172,46 +161,33 @@
return returnType != null && containsLong(returnType.resolveType(scope));
}
- private JClassType findType(JsniRef jsniRef) {
- // Use source name.
- String className = jsniRef.className();
- className = className.replace('$', '.');
- JClassType type = typeOracle.findType(className);
- return type;
- }
-
- /**
- * Returns either the type returned if this reference is "read". For a
- * field, returns the field's type. For a method, returns the method's
- * return type. If the reference cannot be resolved, returns null.
- */
- private JField getField(JsniRef jsniRef) {
- assert jsniRef.isField();
- JClassType type = findType(jsniRef);
- if (type == null) {
- return null;
- }
-
- JField field = type.findField(jsniRef.memberName());
- if (field != null) {
- return field;
+ private ReferenceBinding findClass(JsniRef jsniRef) {
+ String className = jsniRef.className().replace('$', '.');
+ char[][] compoundName = CharOperation.splitOn('.',
+ className.toCharArray());
+ TypeBinding binding = cud.scope.getType(compoundName, compoundName.length);
+ if (binding instanceof ReferenceBinding) {
+ return (ReferenceBinding) binding;
}
return null;
}
- /**
- * Returns either the type returned if this reference is "read". For a
- * field, returns the field's type. For a method, returns the method's
- * return type. If the reference cannot be resolved, returns null.
- */
- private JMethod getMethod(JsniRef jsniRef) {
- assert jsniRef.isMethod();
- JClassType type = findType(jsniRef);
+ private FieldBinding getField(JsniRef jsniRef) {
+ assert jsniRef.isField();
+ ReferenceBinding type = findClass(jsniRef);
if (type == null) {
return null;
}
+ return type.getField(jsniRef.memberName().toCharArray(), false);
+ }
- for (JMethod method : type.getMethods()) {
+ private MethodBinding getMethod(JsniRef jsniRef) {
+ assert jsniRef.isMethod();
+ ReferenceBinding type = findClass(jsniRef);
+ if (type == null) {
+ return null;
+ }
+ for (MethodBinding method : type.getMethods(jsniRef.memberName().toCharArray())) {
if (paramTypesMatch(method, jsniRef)) {
return method;
}
@@ -219,86 +195,74 @@
return null;
}
- private boolean paramTypesMatch(JMethod method, JsniRef jsniRef) {
- String methodSig = Jsni.getMemberSignature(method);
- return methodSig.equals(jsniRef.memberSignature());
- }
-
- private boolean suppressingWarnings(MethodDeclaration meth, ClassScope scope) {
- CompilationResult result = scope.referenceCompilationUnit().compilationResult;
- long[] suppressWarningIrritants;
- long[] suppressWarningScopePositions; // (start << 32) + end
- int suppressWarningsCount;
-
- try {
- {
- Field field = CompilationResult.class.getDeclaredField("suppressWarningIrritants");
- field.setAccessible(true);
- suppressWarningIrritants = (long[]) field.get(result);
- }
- {
- Field field = CompilationResult.class.getDeclaredField("suppressWarningScopePositions");
- field.setAccessible(true);
- suppressWarningScopePositions = (long[]) field.get(result);
- }
- {
- Field field = CompilationResult.class.getDeclaredField("suppressWarningsCount");
- field.setAccessible(true);
- suppressWarningsCount = (Integer) field.get(result);
- }
- } catch (NoSuchFieldException e) {
- throw new InternalCompilerException(
- "Failed to read suppress warnings data from JDT", e);
- } catch (IllegalAccessException e) {
- throw new InternalCompilerException(
- "Failed to read suppress warnings data from JDT", e);
- }
-
- for (int i = 0; i < suppressWarningsCount; i++) {
- if ((suppressWarningIrritants[i] & CompilerOptions.DiscouragedReference) != 0) {
- long start = suppressWarningScopePositions[i] >> 32;
- long end = suppressWarningScopePositions[i] & 0xFFFFFFFF;
- if (meth.bodyStart >= start && meth.bodyStart <= end) {
+ private boolean hasUnsafeLongsAnnotation(MethodDeclaration meth,
+ ClassScope scope) {
+ if (meth.annotations != null) {
+ for (Annotation annot : meth.annotations) {
+ if (isUnsafeLongAnnotation(annot, scope)) {
return true;
}
}
}
-
return false;
}
- private void warn(ASTNode node, String message) {
- CompilationResult compResult = cud.compilationResult();
- int[] lineEnds = compResult.getLineSeparatorPositions();
- int startLine = Util.getLineNumber(node.sourceStart(), lineEnds, 0,
- lineEnds.length - 1);
- String fileName = String.valueOf(cud.getFileName());
- logger.log(TreeLogger.WARN, fileName + "(" + startLine + "): " + message,
- null);
+ private boolean isUnsafeLongAnnotation(Annotation annot, ClassScope scope) {
+ if (annot.type != null) {
+ TypeBinding resolved = annot.type.resolveType(scope);
+ if (resolved != null) {
+ if (resolved instanceof ReferenceBinding) {
+ ReferenceBinding rb = (ReferenceBinding) resolved;
+ if (CharOperation.equals(rb.compoundName,
+ UNSAFE_LONG_ANNOTATION_CHARS)) {
+ return true;
+ }
+ }
+ }
+ }
+ return false;
+ }
+
+ private void longAccessError(ASTNode node, String message) {
+ GWTProblem.recordInCud(node, cud, message);
+ }
+
+ private boolean paramTypesMatch(MethodBinding method, JsniRef jsniRef) {
+ StringBuilder methodSig = new StringBuilder();
+ if (method.parameters != null) {
+ for (TypeBinding binding : method.parameters) {
+ methodSig.append(binding.signature());
+ }
+ }
+ return methodSig.toString().equals(jsniRef.paramTypesString());
+ }
+
+ private String typeString(TypeBinding type) {
+ return String.valueOf(type.shortReadableName());
+ }
+
+ private String typeString(TypeReference type) {
+ return type.toString();
}
}
+ private static final char[][] UNSAFE_LONG_ANNOTATION_CHARS = CharOperation.splitOn(
+ '.', UnsafeNativeLong.class.getName().toCharArray());
+
/**
* Checks an entire
* {@link org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration}.
*
*/
- public static void check(TypeOracle typeOracle,
- CompilationUnitDeclaration cud, TreeLogger logger) {
- LongFromJSNIChecker checker = new LongFromJSNIChecker(typeOracle, cud,
- logger);
+ public static void check(CompilationUnitDeclaration cud) {
+ LongFromJSNIChecker checker = new LongFromJSNIChecker(cud);
checker.check();
}
private final CompilationUnitDeclaration cud;
- private final TreeLogger logger;
- private final TypeOracle typeOracle;
- private LongFromJSNIChecker(TypeOracle typeOracle,
- CompilationUnitDeclaration cud, TreeLogger logger) {
- this.typeOracle = typeOracle;
+ private LongFromJSNIChecker(CompilationUnitDeclaration cud) {
this.cud = cud;
- this.logger = logger;
}
private void check() {
diff --git a/dev/core/src/com/google/gwt/dev/jdt/TypeOracleBuilder.java b/dev/core/src/com/google/gwt/dev/jdt/TypeOracleBuilder.java
index 59d63c9..01b2a21 100644
--- a/dev/core/src/com/google/gwt/dev/jdt/TypeOracleBuilder.java
+++ b/dev/core/src/com/google/gwt/dev/jdt/TypeOracleBuilder.java
@@ -617,10 +617,6 @@
Util.invokeInaccessableMethod(TypeOracle.class, "refresh",
new Class[] {TreeLogger.class}, oracle, new Object[] {logger});
- for (CompilationUnitDeclaration cud : cudsByFileName.values()) {
- LongFromJSNIChecker.check(oracle, cud, logger);
- }
-
PerfLogger.end();
return oracle;
diff --git a/dev/core/super/com/google/gwt/core/client/UnsafeNativeLong.java b/dev/core/super/com/google/gwt/core/client/UnsafeNativeLong.java
new file mode 100644
index 0000000..ceaa8de
--- /dev/null
+++ b/dev/core/super/com/google/gwt/core/client/UnsafeNativeLong.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2008 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.core.client;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * This annotation can be placed on a native method to allow it to directly
+ * access Java <code>long</code> values. Without this annotation present,
+ * accessing a <code>long</code> in any way from a JSNI method is an error.
+ * This includes declaring a parameter or return type of <code>long</code>,
+ * calling a method that takes or returns a <code>long</code>, or accessing a
+ * <code>long</code> field.
+ *
+ * <p>
+ * The reason for the restriction is that Java long values are not represented
+ * as numeric values in compiled code, but as opaque Objects. Attempting to
+ * perform math operations on them would produce undesirable results.
+ * </p>
+ * <p>
+ * Use this annotation with care; the only safe thing to do with
+ * <code>long</code> values in JSNI code is to pass them back into Java
+ * unaltered.
+ * </p>
+ */
+@Target(ElementType.METHOD)
+@Retention(RetentionPolicy.SOURCE)
+public @interface UnsafeNativeLong {
+}
diff --git a/dev/core/super/com/google/gwt/lang/LongLib.java b/dev/core/super/com/google/gwt/lang/LongLib.java
index ec03903..ddfacc0 100644
--- a/dev/core/super/com/google/gwt/lang/LongLib.java
+++ b/dev/core/super/com/google/gwt/lang/LongLib.java
@@ -24,6 +24,8 @@
import static com.google.gwt.lang.LongLib.Const.TWO_PWR_24;
import static com.google.gwt.lang.LongLib.Const.ZERO;
+import com.google.gwt.core.client.UnsafeNativeLong;
+
/**
* Implements a Java <code>long</code> in a way that can be translated to
* JavaScript.
@@ -670,7 +672,7 @@
/**
* Web mode implementation; the long is already the right object.
*/
- @SuppressWarnings("restriction")
+ @UnsafeNativeLong
private static native double[] typeChange0(long value) /*-{
return value;
}-*/;
diff --git a/dev/core/test/com/google/gwt/dev/jdt/LongFromJSNITest.java b/dev/core/test/com/google/gwt/dev/jdt/LongFromJSNITest.java
index 8e41ad7..fb1c5b2 100644
--- a/dev/core/test/com/google/gwt/dev/jdt/LongFromJSNITest.java
+++ b/dev/core/test/com/google/gwt/dev/jdt/LongFromJSNITest.java
@@ -17,7 +17,7 @@
import com.google.gwt.core.ext.TreeLogger;
import com.google.gwt.core.ext.UnableToCompleteException;
-import com.google.gwt.core.ext.TreeLogger.Type;
+import com.google.gwt.core.ext.typeinfo.TypeOracle;
import com.google.gwt.dev.util.UnitTestTreeLogger;
import junit.framework.TestCase;
@@ -34,10 +34,8 @@
code.append(" $wnd.alert(\"x is: \"+this.@Buggy::x); }-*/;\n");
code.append("}\n");
- shouldGenerateWarning(
- code,
- 3,
- "Referencing field 'Buggy.x': 'long' is an opaque, non-numeric value in JS code");
+ shouldGenerateError(code, 3,
+ "Referencing field 'Buggy.x': type 'long' is not safe to access in JSNI code");
}
public void testLongArray() throws UnableToCompleteException {
@@ -48,10 +46,10 @@
code.append(" $wnd.alert(this.@Buggy::m()()); }-*/;\n");
code.append("}\n");
- shouldGenerateWarning(
+ shouldGenerateError(
code,
3,
- "Referencing method \'Buggy.m\': return type \'long[]\' is an opaque, non-numeric value in JS code");
+ "Referencing method \'Buggy.m\': return type 'long[]' is not safe to access in JSNI code");
}
public void testLongParameter() throws UnableToCompleteException {
@@ -60,8 +58,8 @@
code.append(" native void jsniMeth(long x) /*-{ return; }-*/;\n");
code.append("}\n");
- shouldGenerateWarning(code, 2,
- "Parameter 'x': 'long' is an opaque, non-numeric value in JS code");
+ shouldGenerateError(code, 2,
+ "Parameter 'x': type 'long' is not safe to access in JSNI code");
}
public void testLongReturn() throws UnableToCompleteException {
@@ -70,8 +68,8 @@
code.append(" native long jsniMeth() /*-{ return 0; }-*/;\n");
code.append("}\n");
- shouldGenerateWarning(code, 2,
- "Return value of type 'long' is an opaque, non-numeric value in JS code");
+ shouldGenerateError(code, 2,
+ "Type 'long' may not be returned from a JSNI method");
}
public void testMethodArgument() throws UnableToCompleteException {
@@ -81,10 +79,10 @@
code.append(" native void jsniMeth() /*-{ this.@Buggy::print(J)(0); }-*/;\n");
code.append("}\n");
- shouldGenerateWarning(
+ shouldGenerateError(
code,
3,
- "Referencing method \'Buggy.print\': parameter \'x\': \'long\' is an opaque, non-numeric value in JS code");
+ "Parameter 1 of method \'Buggy.print\': type 'long' may not be passed out of JSNI code");
}
public void testMethodReturn() throws UnableToCompleteException {
@@ -95,10 +93,10 @@
code.append(" $wnd.alert(this.@Buggy::m()()); }-*/;\n");
code.append("}\n");
- shouldGenerateWarning(
+ shouldGenerateError(
code,
3,
- "Referencing method 'Buggy.m': return type 'long' is an opaque, non-numeric value in JS code");
+ "Referencing method 'Buggy.m': return type 'long' is not safe to access in JSNI code");
}
public void testOverloadedMethodWithNoWarning()
@@ -111,7 +109,7 @@
code.append(" $wnd.alert(this.@Buggy::m(Ljava/lang/String;)(\"hello\")); }-*/;\n");
code.append("}\n");
- shouldGenerateNoWarning(code);
+ shouldGenerateNoError(code);
}
public void testOverloadedMethodWithWarning()
@@ -124,53 +122,70 @@
code.append(" $wnd.alert(this.@Buggy::m(I)(10)); }-*/;\n");
code.append("}\n");
- shouldGenerateWarning(
+ shouldGenerateError(
code,
4,
- "Referencing method 'Buggy.m': return type 'long' is an opaque, non-numeric value in JS code");
+ "Referencing method 'Buggy.m': return type 'long' is not safe to access in JSNI code");
}
- public void testSuppressWarnings() throws UnableToCompleteException {
+ public void testUnsafeAnnotation() throws UnableToCompleteException {
{
StringBuffer code = new StringBuffer();
+ code.append("import com.google.gwt.core.client.UnsafeNativeLong;");
code.append("class Buggy {\n");
code.append(" void print(long x) { }\n");
- code.append(" @SuppressWarnings(\"restriction\")\n");
+ code.append(" @UnsafeNativeLong\n");
code.append(" native void jsniMeth() /*-{ this.@Buggy::print(J)(0); }-*/;\n");
code.append("}\n");
- shouldGenerateNoWarning(code);
+ shouldGenerateNoError(code);
}
+ }
+ private void addLongCheckingCups(TypeOracleBuilder builder)
+ throws UnableToCompleteException {
{
- StringBuffer code = new StringBuffer();
- code.append("@SuppressWarnings(\"restriction\")\n");
- code.append("class Buggy {\n");
- code.append(" void print(long x) { }\n");
- code.append(" native void jsniMeth() /*-{ this.@Buggy::print(J)(0); }-*/;\n");
+ StringBuilder code = new StringBuilder();
+ code.append("package com.google.gwt.core.client;\n");
+ code.append("public @interface UnsafeNativeLong {\n");
code.append("}\n");
- shouldGenerateNoWarning(code);
+ TypeOracleTestingUtils.addCup(builder,
+ "com.google.gwt.core.client.UnsafeNativeLong", code);
}
}
- private void shouldGenerateNoWarning(StringBuffer code)
- throws UnableToCompleteException {
- shouldGenerateWarning(code, -1, null);
+ private TypeOracle buildOracleWithCode(CharSequence code,
+ UnitTestTreeLogger logger) throws UnableToCompleteException {
+ TypeOracleBuilder builder = new TypeOracleBuilder();
+ TypeOracleTestingUtils.addStandardCups(builder);
+ addLongCheckingCups(builder);
+ TypeOracleTestingUtils.addCup(builder, "Buggy", code);
+ return builder.build(logger);
}
- private void shouldGenerateWarning(CharSequence code, int line, String message)
+ private void shouldGenerateError(CharSequence code, int line, String message)
throws UnableToCompleteException {
- Type logType = TreeLogger.WARN;
UnitTestTreeLogger.Builder b = new UnitTestTreeLogger.Builder();
- b.setLowestLogLevel(logType);
+ b.setLowestLogLevel(TreeLogger.ERROR);
if (message != null) {
- final String fullMessage = "transient source for Buggy(" + line + "): "
- + message;
- b.expect(logType, fullMessage, null);
+ b.expect(TreeLogger.ERROR, "Errors in 'transient source for Buggy'", null);
+ final String fullMessage = "Line " + line + ": " + message;
+ b.expect(TreeLogger.ERROR, fullMessage, null);
+ b.expect(TreeLogger.ERROR,
+ "Compilation problem due to 'transient source for Buggy'", null);
}
UnitTestTreeLogger logger = b.createLogger();
- TypeOracleTestingUtils.buildTypeOracleForCode("Buggy", code, logger);
+ TypeOracle oracle = buildOracleWithCode(code, logger);
logger.assertCorrectLogEntries();
+ if (message != null) {
+ assertEquals("Buggy compilation unit not removed from type oracle", null,
+ oracle.findType("Buggy"));
+ }
+ }
+
+ private void shouldGenerateNoError(StringBuffer code)
+ throws UnableToCompleteException {
+ shouldGenerateError(code, -1, null);
}
}
diff --git a/user/src/com/google/gwt/user/rebind/rpc/FieldSerializerCreator.java b/user/src/com/google/gwt/user/rebind/rpc/FieldSerializerCreator.java
index b87a6b5..82567eb 100644
--- a/user/src/com/google/gwt/user/rebind/rpc/FieldSerializerCreator.java
+++ b/user/src/com/google/gwt/user/rebind/rpc/FieldSerializerCreator.java
@@ -15,6 +15,7 @@
*/
package com.google.gwt.user.rebind.rpc;
+import com.google.gwt.core.client.UnsafeNativeLong;
import com.google.gwt.core.ext.GeneratorContext;
import com.google.gwt.core.ext.TreeLogger;
import com.google.gwt.core.ext.typeinfo.JArrayType;
@@ -23,6 +24,7 @@
import com.google.gwt.core.ext.typeinfo.JField;
import com.google.gwt.core.ext.typeinfo.JPrimitiveType;
import com.google.gwt.core.ext.typeinfo.JType;
+import com.google.gwt.dev.jdt.LongFromJSNIChecker;
import com.google.gwt.user.client.rpc.SerializationException;
import com.google.gwt.user.client.rpc.SerializationStreamReader;
import com.google.gwt.user.client.rpc.SerializationStreamWriter;
@@ -136,11 +138,11 @@
private void maybeSuppressLongWarnings(JType fieldType) {
if (fieldType == JPrimitiveType.LONG) {
/**
- * Accessing long from JSNI causes a warning, but field serializers need
+ * Accessing long from JSNI causes a error, but field serializers need
* to be able to do just that in order to bypass java accessibility
* restrictions.
*/
- sourceWriter.println("@SuppressWarnings(\"restriction\")");
+ sourceWriter.println("@" + UnsafeNativeLong.class.getName());
}
}
diff --git a/user/test/com/google/gwt/dev/jjs/test/HostedTest.java b/user/test/com/google/gwt/dev/jjs/test/HostedTest.java
index efe1e2c..56af8ca 100644
--- a/user/test/com/google/gwt/dev/jjs/test/HostedTest.java
+++ b/user/test/com/google/gwt/dev/jjs/test/HostedTest.java
@@ -22,6 +22,7 @@
import com.google.gwt.core.client.GWT;
import com.google.gwt.core.client.JavaScriptObject;
+import com.google.gwt.core.client.UnsafeNativeLong;
import com.google.gwt.junit.client.GWTTestCase;
import java.util.AbstractList;
@@ -160,7 +161,7 @@
return val;
}-*/;
- @SuppressWarnings("restriction")
+ @UnsafeNativeLong
private static native long passThroughLong(long val) /*-{
return val;
}-*/;