Fixes a bug in r2611: when doing a sloppy scan for JSNI
references, @ signs that do not begin a valid JSNI
reference would cause an exception to be thrown.
This patch suppresses such errors and skips to the
next @ sign.
Review by: scottb
git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@2651 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/dev/core/build.xml b/dev/core/build.xml
index a89c2eb..748985e 100755
--- a/dev/core/build.xml
+++ b/dev/core/build.xml
@@ -105,6 +105,9 @@
<pathelement location="${gwt.tools.lib}/eclipse/org.eclipse.swt.gtk-linux-3.2.1.jar" />
</classpath>
</gwt.javac>
+ <copy todir="${javac.out}">
+ <fileset dir="src" includes="**/*.properties"/>
+ </copy>
</target>
<target name="checkstyle" description="Static analysis of source">
@@ -131,7 +134,7 @@
</classpath>
</taskdef>
- <echo message="Writing test results to @{junit.out}/reports for @{test.cases}" />
+ <echo message="Writing test results to ${junit.out}/reports for ${test.cases}" />
<mkdir dir="${junit.out}/reports" />
<echo message="${javac.out} ${javac.junit.out}" />
diff --git a/dev/core/src/com/google/gwt/dev/jdt/FindJsniRefVisitor.java b/dev/core/src/com/google/gwt/dev/jdt/FindJsniRefVisitor.java
index e9a1e5b..afbeef1 100644
--- a/dev/core/src/com/google/gwt/dev/jdt/FindJsniRefVisitor.java
+++ b/dev/core/src/com/google/gwt/dev/jdt/FindJsniRefVisitor.java
@@ -24,6 +24,9 @@
import com.google.gwt.dev.js.ast.JsProgram;
import com.google.gwt.dev.js.ast.JsStatement;
import com.google.gwt.dev.js.ast.JsVisitor;
+import com.google.gwt.dev.js.rhino.Context;
+import com.google.gwt.dev.js.rhino.ErrorReporter;
+import com.google.gwt.dev.js.rhino.EvaluatorException;
import com.google.gwt.dev.js.rhino.TokenStream;
import com.google.gwt.dev.util.Jsni;
@@ -33,6 +36,7 @@
import org.eclipse.jdt.internal.compiler.lookup.ClassScope;
import java.io.IOException;
+import java.io.Reader;
import java.io.StringReader;
import java.util.Collections;
import java.util.LinkedHashSet;
@@ -46,6 +50,26 @@
* quickly but it will return a superset of the actual JSNI references.
*/
public class FindJsniRefVisitor extends ASTVisitor {
+ /**
+ * A Rhino error reporter that discards any errors it sees.
+ */
+ private static ErrorReporter NullErrorReporter = new ErrorReporter() {
+ public void error(String message, String sourceName, int line,
+ String lineSource, int lineOffset) {
+ // ignore it
+ }
+
+ public EvaluatorException runtimeError(String message, String sourceName,
+ int line, String lineSource, int lineOffset) {
+ throw new InternalCompilerException("Rhino run-time error: " + message);
+ }
+
+ public void warning(String message, String sourceName, int line,
+ String lineSource, int lineOffset) {
+ // ignore it
+ }
+ };
+
private final Set<String> jsniRefs = new LinkedHashSet<String>();
private boolean sloppy = false;
@@ -113,8 +137,7 @@
}
}.acceptList(result);
} catch (IOException e) {
- throw new InternalCompilerException(
- "Internal error searching for JSNI references", e);
+ throw new InternalCompilerException(e.getMessage(), e);
} catch (JsParserException e) {
// ignore, we only care about finding valid references
}
@@ -129,20 +152,19 @@
break;
}
try {
- // use Rhino to read a JavaScript identifier
reader.reset();
reader.skip(idx);
- TokenStream tokStr = new TokenStream(reader, "(memory)", 0);
- if (tokStr.getToken() != TokenStream.NAME) {
- // scottb: Why do we break here?
- break;
- }
- String jsniRefString = tokStr.getString();
+ } catch (IOException e) {
+ throw new InternalCompilerException(e.getMessage(), e);
+ }
+ String jsniRefString = readJsIdentifier(reader);
+ if (jsniRefString == null) {
+ // badly formatted identifier; skip to the next @ sign
+ idx++;
+ } else {
assert (jsniRefString.charAt(0) == '@');
jsniRefs.add(jsniRefString.substring(1));
idx += jsniRefString.length();
- } catch (IOException e) {
- throw new InternalCompilerException("Unexpected IO error while reading a JS identifier", e);
}
}
}
@@ -164,4 +186,24 @@
return jsniCode;
}
+ /**
+ * Read a JavaScript identifier using Rhino. If the parse fails, returns null.
+ */
+ private String readJsIdentifier(Reader reader)
+ throws InternalCompilerException {
+ try {
+ Context.enter().setErrorReporter(NullErrorReporter);
+ TokenStream tokStr = new TokenStream(reader, "(memory)", 0);
+ if (tokStr.getToken() == TokenStream.NAME) {
+ return tokStr.getString();
+ } else {
+ return null;
+ }
+ } catch (IOException e) {
+ throw new InternalCompilerException(e.getMessage(), e);
+ } finally {
+ Context.exit();
+ }
+ }
+
}
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 2412ad2..4bb445c 100644
--- a/dev/core/test/com/google/gwt/dev/jdt/LongFromJSNITest.java
+++ b/dev/core/test/com/google/gwt/dev/jdt/LongFromJSNITest.java
@@ -26,6 +26,19 @@
* Test access to longs from JSNI.
*/
public class LongFromJSNITest extends TestCase {
+ public void testBogusRef() throws UnableToCompleteException {
+ StringBuffer code = new StringBuffer();
+ code.append("class Buggy { \n");
+ code.append("volatile long x = -1; \n");
+ code.append("native void jsniMeth() /*-{ \n");
+ code.append(" // @\\bogus refs should just be skipped \n");
+ code.append(" $wnd.alert(\"x is: \"+this.@Buggy::x); }-*/; \n");
+ code.append("} \n");
+
+ shouldGenerateError(code, 3,
+ "Referencing field 'Buggy.x': type 'long' is not safe to access in JSNI code");
+ }
+
public void testCyclicReferences() throws UnableToCompleteException {
{
StringBuffer buggy = new StringBuffer();
@@ -191,6 +204,19 @@
"Referencing method 'Buggy.m': return type 'long' is not safe to access in JSNI code");
}
+ public void testRefInString() 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(" native void jsniMeth() /*-{ 'this.@Buggy::print(J)(0)'; }-*/;\n");
+ code.append("}\n");
+
+ shouldGenerateNoError(code);
+ }
+ }
+
public void testUnsafeAnnotation() throws UnableToCompleteException {
{
StringBuffer code = new StringBuffer();
@@ -204,19 +230,6 @@
shouldGenerateNoError(code);
}
}
-
- public void testRefInString() 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(" native void jsniMeth() /*-{ 'this.@Buggy::print(J)(0)'; }-*/;\n");
- code.append("}\n");
-
- shouldGenerateNoError(code);
- }
- }
public void testViolator() throws UnableToCompleteException {
{
@@ -317,8 +330,8 @@
shouldGenerateNoError(code, null);
}
- private void shouldGenerateNoError(CharSequence code,
- CharSequence extraCode) throws UnableToCompleteException {
+ private void shouldGenerateNoError(CharSequence code, CharSequence extraCode)
+ throws UnableToCompleteException {
shouldGenerateError(code, extraCode, -1, null);
}
}