Revision: 7045 Author: [email protected] Date: Thu Nov 19 14:34:20 2009 Log: trunk c7033-c7039 were merged into this branch Fixes an NPE in JsniChecker; improves test coverage on JsniCollector and JsniChecker. JsniChecker should support the "::new" syntax. In JsniChecker, suppressed warnings should cascade down to nested members. JUnit's -noserver option was not actually doing anything useful. GWTShell must not link public and autogenerated artifacts into the shell generated resource directory. Fix up native lines + mime type svn props. svn merge --ignore-ancestry -r7032:7039 https://google-web-toolkit.googlecode.com/svn/trunk/ .
http://code.google.com/p/google-web-toolkit/source/detail?r=7045 Added: /releases/2.0/dev/core/test/com/google/gwt/dev/javac/JsniCollectorTest.java Modified: /releases/2.0/branch-info.txt /releases/2.0/dev/core/src/com/google/gwt/dev/DevMode.java /releases/2.0/dev/core/src/com/google/gwt/dev/DevModeBase.java /releases/2.0/dev/core/src/com/google/gwt/dev/GWTShell.java /releases/2.0/dev/core/src/com/google/gwt/dev/javac/JsniChecker.java /releases/2.0/dev/core/test/com/google/gwt/dev/javac/CompilationStateTestBase.java /releases/2.0/dev/core/test/com/google/gwt/dev/javac/JavaCompilationSuite.java /releases/2.0/dev/core/test/com/google/gwt/dev/javac/JsniCheckerTest.java /releases/2.0/dev/core/test/com/google/gwt/dev/javac/impl/StaticJavaResource.java /releases/2.0/user/src/com/google/gwt/junit/JUnitShell.java /releases/2.0/user/src/com/google/gwt/user/rebind/rpc/FieldSerializerCreator.java ======================================= --- /dev/null +++ /releases/2.0/dev/core/test/com/google/gwt/dev/javac/JsniCollectorTest.java Thu Nov 19 14:34:20 2009 @@ -0,0 +1,142 @@ +/* + * Copyright 2009 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.dev.javac; + +import com.google.gwt.dev.javac.impl.StaticJavaResource; +import com.google.gwt.dev.jjs.SourceInfo; +import com.google.gwt.dev.js.ast.JsContext; +import com.google.gwt.dev.js.ast.JsExpression; +import com.google.gwt.dev.js.ast.JsNameRef; +import com.google.gwt.dev.js.ast.JsVisitor; + +import org.eclipse.jdt.core.compiler.CategorizedProblem; + +import java.util.ArrayList; +import java.util.List; + +/** + * Tests {...@link JsniCollector}. + */ +public class JsniCollectorTest extends CompilationStateTestBase { + + /** + * TODO: currently JSNI does not parse character position. Turn this on (and + * delete it, actually) when it does. + */ + public static final boolean JSNI_PARSES_SOURCE_POSITION = false; + + public void testErrorPosition() { + StringBuffer code = new StringBuffer(); + code.append("class Foo {\n"); + code.append(" native void m(Object o) /*-{\n"); + code.append(" o...@foo::m(Ljava/lang/String);\n"); + code.append(" }-*/;\n"); + code.append("}\n"); + String source = code.toString(); + + CategorizedProblem[] problems = getProblems("Foo", source); + assertEquals(1, problems.length); + CategorizedProblem problem = problems[0]; + if (JSNI_PARSES_SOURCE_POSITION) { + assertEquals(source.indexOf('@'), problem.getSourceStart()); + } + assertEquals(3, problem.getSourceLineNumber()); + assertTrue(problem.isWarning()); + assertEquals( + "Referencing method 'Foo.m(Ljava/lang/String)': unable to resolve method, expect subsequent failures", + problem.getMessage()); + } + + public void testMalformedJsniRefPosition() { + StringBuffer code = new StringBuffer(); + code.append("class Foo {\n"); + code.append(" native void m() /*-{\n"); + code.append(" @Bar;\n"); + code.append(" }-*/;\n"); + code.append("}\n"); + String source = code.toString(); + CategorizedProblem[] problems = getProblems("Foo", source); + assertEquals(1, problems.length); + CategorizedProblem problem = problems[0]; + assertEquals(source.indexOf('@') + "Bar".length(), problem.getSourceStart()); + assertEquals(3, problem.getSourceLineNumber()); + assertTrue(problem.isError()); + assertEquals("Expected \":\" in JSNI reference", problem.getMessage()); + } + + public void testMalformedJsniRefPositionWithExtraLines() { + StringBuffer code = new StringBuffer(); + code.append("class Foo {\n"); + code.append(" native\nvoid\nm()\n\n\n/*-{\n\n"); + code.append(" @Bar;\n"); + code.append(" }-*/;\n"); + code.append("}\n"); + String source = code.toString(); + CategorizedProblem[] problems = getProblems("Foo", source); + assertEquals(1, problems.length); + CategorizedProblem problem = problems[0]; + assertEquals(source.indexOf('@') + "Bar".length(), problem.getSourceStart()); + assertEquals(9, problem.getSourceLineNumber()); + assertTrue(problem.isError()); + assertEquals("Expected \":\" in JSNI reference", problem.getMessage()); + } + + public void testSourcePosition() { + StringBuffer code = new StringBuffer(); + code.append("class Foo {\n"); + code.append(" native void m(Object o) /*-{\n"); + code.append(" o...@foo::m(Ljava/lang/Object);\n"); + code.append(" }-*/;\n"); + code.append("}\n"); + String source = code.toString(); + + List<JsNameRef> foundRefs = findJsniRefs("Foo", source); + assertEquals(1, foundRefs.size()); + JsNameRef ref = foundRefs.get(0); + SourceInfo info = ref.getSourceInfo(); + if (JSNI_PARSES_SOURCE_POSITION) { + assertEquals(source.indexOf('@'), info.getStartPos()); + } + assertEquals(3, info.getStartLine()); + } + + private List<JsNameRef> findJsniRefs(String typeName, final String source) { + addGeneratedUnits(new StaticJavaResource(typeName, source)); + CompilationUnit unit = state.getCompilationUnitMap().get(typeName); + assertNotNull(unit); + List<JsniMethod> jsniMethods = unit.getJsniMethods(); + assertEquals(1, jsniMethods.size()); + JsniMethod jsniMethod = jsniMethods.get(0); + final List<JsNameRef> foundRefs = new ArrayList<JsNameRef>(); + new JsVisitor() { + @Override + public void endVisit(JsNameRef x, JsContext<JsExpression> ctx) { + if (x.getIdent().startsWith("@")) { + foundRefs.add(x); + } + } + }.accept(jsniMethod.function()); + return foundRefs; + } + + private CategorizedProblem[] getProblems(String typeName, String source) { + addGeneratedUnits(new StaticJavaResource(typeName, source)); + CompilationUnit unit = state.getCompilationUnitMap().get(typeName); + assertNotNull(unit); + CategorizedProblem[] problems = unit.getProblems(); + return problems; + } +} ======================================= --- /releases/2.0/branch-info.txt Thu Nov 19 14:17:04 2009 +++ /releases/2.0/branch-info.txt Thu Nov 19 14:34:20 2009 @@ -837,6 +837,15 @@ svn merge --ignore-ancestry -c7027 \ https://google-web-toolkit.googlecode.com/svn/trunk/ . +trunk c7033-c7039 were merged into this branch + Fixes an NPE in JsniChecker; improves test coverage on JsniCollector and JsniChecker. + JsniChecker should support the "::new" syntax. + In JsniChecker, suppressed warnings should cascade down to nested members. + JUnit's -noserver option was not actually doing anything useful. + GWTShell must not link public and autogenerated artifacts into the shell generated resource directory. + Fix up native lines + mime type svn props. + svn merge --ignore-ancestry -r7032:7039 https://google-web-toolkit.googlecode.com/svn/trunk/ . + tr...@7041 was merged into this branch Making CookieTest use client time to set cookie expiration. svn merge --ignore-ancestry -c 7041 https://google-web-toolkit.googlecode.com/svn/trunk . ======================================= --- /releases/2.0/dev/core/src/com/google/gwt/dev/DevMode.java Wed Nov 18 14:09:08 2009 +++ /releases/2.0/dev/core/src/com/google/gwt/dev/DevMode.java Thu Nov 19 14:34:20 2009 @@ -376,10 +376,11 @@ @Override protected synchronized void produceOutput(TreeLogger logger, - StandardLinkerContext linkerStack, ArtifactSet artifacts, ModuleDef module) - throws UnableToCompleteException { + StandardLinkerContext linkerStack, ArtifactSet artifacts, + ModuleDef module, boolean isRelink) throws UnableToCompleteException { File moduleOutDir = new File(options.getWarDir(), module.getName()); linkerStack.produceOutputDirectory(logger, artifacts, moduleOutDir); + if (options.getExtraDir() != null) { File moduleExtraDir = new File(options.getExtraDir(), module.getName()); linkerStack.produceExtraDirectory(logger, artifacts, moduleExtraDir); ======================================= --- /releases/2.0/dev/core/src/com/google/gwt/dev/DevModeBase.java Thu Nov 19 13:50:21 2009 +++ /releases/2.0/dev/core/src/com/google/gwt/dev/DevModeBase.java Thu Nov 19 14:34:20 2009 @@ -866,7 +866,7 @@ StandardLinkerContext linkerStack = new StandardLinkerContext(linkLogger, module, options); ArtifactSet artifacts = linkerStack.invokeLink(linkLogger); - produceOutput(linkLogger, linkerStack, artifacts, module); + produceOutput(linkLogger, linkerStack, artifacts, module, false); return linkerStack; } @@ -921,8 +921,8 @@ } protected abstract void produceOutput(TreeLogger logger, - StandardLinkerContext linkerStack, ArtifactSet artifacts, ModuleDef module) - throws UnableToCompleteException; + StandardLinkerContext linkerStack, ArtifactSet artifacts, + ModuleDef module, boolean isRelink) throws UnableToCompleteException; protected final void setDone() { blockUntilDone.release(); @@ -1008,6 +1008,6 @@ ArtifactSet artifacts = linkerContext.invokeRelink(linkLogger, newlyGeneratedArtifacts); - produceOutput(linkLogger, linkerContext, artifacts, module); + produceOutput(linkLogger, linkerContext, artifacts, module, true); } } ======================================= --- /releases/2.0/dev/core/src/com/google/gwt/dev/GWTShell.java Mon Nov 16 19:22:20 2009 +++ /releases/2.0/dev/core/src/com/google/gwt/dev/GWTShell.java Thu Nov 19 14:34:20 2009 @@ -199,7 +199,7 @@ TreeLogger logger = ui.getWebServerLogger("Tomcat", null); // TODO(bruce): make tomcat work in terms of the modular launcher String whyFailed = EmbeddedTomcatServer.start(isHeadless() ? getTopLogger() - : logger, getPort(), options); + : logger, getPort(), options, shouldAutoGenerateResources()); if (whyFailed != null) { getTopLogger().log(TreeLogger.ERROR, "Starting Tomcat: " + whyFailed); @@ -209,9 +209,21 @@ } protected synchronized void produceOutput(TreeLogger logger, - StandardLinkerContext linkerStack, ArtifactSet artifacts, ModuleDef module) - throws UnableToCompleteException { - File moduleOutDir = options.getShellPublicGenDir(module); - linkerStack.produceOutputDirectory(logger, artifacts, moduleOutDir); + StandardLinkerContext linkerStack, ArtifactSet artifacts, + ModuleDef module, boolean isRelink) throws UnableToCompleteException { + /* + * Legacy: in GWTShell we only copy generated artifacts into the public gen + * folder. Public files and "autogen" files have special handling (that + * needs to die). + */ + if (isRelink) { + File outputDir = options.getShellPublicGenDir(module); + outputDir.mkdirs(); + linkerStack.produceOutputDirectory(logger, artifacts, outputDir); + } + } + + protected boolean shouldAutoGenerateResources() { + return true; } } ======================================= --- /releases/2.0/dev/core/src/com/google/gwt/dev/javac/JsniChecker.java Fri Nov 13 08:09:56 2009 +++ /releases/2.0/dev/core/src/com/google/gwt/dev/javac/JsniChecker.java Thu Nov 19 14:34:20 2009 @@ -39,14 +39,19 @@ import org.eclipse.jdt.internal.compiler.ast.MemberValuePair; import org.eclipse.jdt.internal.compiler.ast.MethodDeclaration; import org.eclipse.jdt.internal.compiler.ast.StringLiteral; +import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration; import org.eclipse.jdt.internal.compiler.ast.TypeReference; import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; import org.eclipse.jdt.internal.compiler.lookup.BaseTypeBinding; +import org.eclipse.jdt.internal.compiler.lookup.BlockScope; import org.eclipse.jdt.internal.compiler.lookup.ClassScope; +import org.eclipse.jdt.internal.compiler.lookup.CompilationUnitScope; import org.eclipse.jdt.internal.compiler.lookup.FieldBinding; import org.eclipse.jdt.internal.compiler.lookup.MethodBinding; +import org.eclipse.jdt.internal.compiler.lookup.NestedTypeBinding; import org.eclipse.jdt.internal.compiler.lookup.ProblemReferenceBinding; import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding; +import org.eclipse.jdt.internal.compiler.lookup.SyntheticArgumentBinding; import org.eclipse.jdt.internal.compiler.lookup.TypeBinding; import org.eclipse.jdt.internal.compiler.lookup.TypeIds; import org.eclipse.jdt.internal.compiler.lookup.UnresolvedReferenceBinding; @@ -54,6 +59,7 @@ import java.util.Locale; import java.util.Map; import java.util.Set; +import java.util.Stack; /** * Tests for access to Java from JSNI. Issues a warning for: @@ -84,8 +90,47 @@ checkDecl(meth, scope); } JsniMethod jsniMethod = jsniMethods.get(meth); - new JsniRefChecker(meth, hasUnsafeLongsAnnotation).check(jsniMethod.function()); - } + if (jsniMethod != null) { + new JsniRefChecker(meth, hasUnsafeLongsAnnotation).check(jsniMethod.function()); + } + } + suppressWarningsStack.pop(); + } + + public void endVisit(TypeDeclaration typeDeclaration, BlockScope scope) { + suppressWarningsStack.pop(); + } + + public void endVisit(TypeDeclaration typeDeclaration, ClassScope scope) { + suppressWarningsStack.pop(); + } + + public void endVisit(TypeDeclaration typeDeclaration, + CompilationUnitScope scope) { + suppressWarningsStack.pop(); + } + + @Override + public boolean visit(MethodDeclaration meth, ClassScope scope) { + suppressWarningsStack.push(getSuppressedWarnings(meth.annotations)); + return true; + } + + public boolean visit(TypeDeclaration typeDeclaration, BlockScope scope) { + suppressWarningsStack.push(getSuppressedWarnings(typeDeclaration.annotations)); + return true; + } + + @Override + public boolean visit(TypeDeclaration typeDeclaration, ClassScope scope) { + suppressWarningsStack.push(getSuppressedWarnings(typeDeclaration.annotations)); + return true; + } + + public boolean visit(TypeDeclaration typeDeclaration, + CompilationUnitScope scope) { + suppressWarningsStack.push(getSuppressedWarnings(typeDeclaration.annotations)); + return true; } private void checkDecl(MethodDeclaration meth, ClassScope scope) { @@ -121,13 +166,11 @@ private transient SourceInfo errorInfo; private final boolean hasUnsafeLongsAnnotation; private final MethodDeclaration method; - private final Set<String> suppressWarnings; public JsniRefChecker(MethodDeclaration method, boolean hasUnsafeLongsAnnotation) { this.method = method; this.hasUnsafeLongsAnnotation = hasUnsafeLongsAnnotation; - this.suppressWarnings = getSuppressedWarnings(method); } public void check(JsFunction function) { @@ -156,6 +199,9 @@ } FieldBinding target = getField(clazz, jsniRef); if (target == null) { + emitWarning("jsni", "Referencing field '" + jsniRef.className() + "." + + jsniRef.memberName() + + "': unable to resolve field, expect subsequent failures"); return; } if (target.isDeprecated()) { @@ -177,6 +223,9 @@ assert jsniRef.isMethod(); MethodBinding target = getMethod(clazz, jsniRef); if (target == null) { + emitWarning("jsni", "Referencing method '" + jsniRef.className() + "." + + jsniRef.memberSignature() + + "': unable to resolve method, expect subsequent failures"); return; } if (target.isDeprecated()) { @@ -262,7 +311,7 @@ } } else { emitWarning("jsni", "Referencing class '" + className - + ": unable to resolve class, expect subsequent failures"); + + "': unable to resolve class, expect subsequent failures"); } } @@ -271,9 +320,11 @@ } private void emitWarning(String category, String msg) { - if (suppressWarnings.contains(category) - || suppressWarnings.contains("all")) { - return; + for (Set<String> suppressWarnings : suppressWarningsStack) { + if (suppressWarnings.contains(category) + || suppressWarnings.contains("all")) { + return; + } } JsniCollector.reportJsniWarning(errorInfo, method, msg); } @@ -299,46 +350,40 @@ private MethodBinding getMethod(ReferenceBinding clazz, JsniRef jsniRef) { assert jsniRef.isMethod(); - for (MethodBinding findMethod : clazz.getMethods(jsniRef.memberName().toCharArray())) { - if (paramTypesMatch(findMethod, jsniRef)) { - return findMethod; - } - } - return null; - } - - private Set<String> getSuppressedWarnings(MethodDeclaration method) { - Annotation[] annotations = method.annotations; - if (annotations == null) { - return Sets.create(); - } - - for (Annotation a : annotations) { - if (SuppressWarnings.class.getName().equals( - CharOperation.toString(((ReferenceBinding) a.resolvedType).compoundName))) { - for (MemberValuePair pair : a.memberValuePairs()) { - if (String.valueOf(pair.name).equals("value")) { - Expression valueExpr = pair.value; - if (valueExpr instanceof StringLiteral) { - // @SuppressWarnings("Foo") - return Sets.create(((StringLiteral) valueExpr).constant.stringValue().toLowerCase(Locale.ENGLISH)); - } else if (valueExpr instanceof ArrayInitializer) { - // @SuppressWarnings({ "Foo", "Bar"}) - ArrayInitializer ai = (ArrayInitializer) valueExpr; - String[] values = new String[ai.expressions.length]; - for (int i = 0, j = values.length; i < j; i++) { - values[i] = ((StringLiteral) ai.expressions[i]).constant.stringValue().toLowerCase(Locale.ENGLISH); - } - return Sets.create(values); - } else { - throw new InternalCompilerException( - "Unable to analyze SuppressWarnings annotation"); + String methodName = jsniRef.memberName(); + if ("new".equals(methodName)) { + for (MethodBinding findMethod : clazz.getMethods(INIT_CTOR_CHARS)) { + StringBuilder methodSig = new StringBuilder(); + if (clazz instanceof NestedTypeBinding) { + // Match synthetic args for enclosing instances. + NestedTypeBinding nestedBinding = (NestedTypeBinding) clazz; + if (nestedBinding.enclosingInstances != null) { + for (int i = 0; i < nestedBinding.enclosingInstances.length; ++i) { + SyntheticArgumentBinding arg = nestedBinding.enclosingInstances[i]; + methodSig.append(arg.type.signature()); } } } + if (findMethod.parameters != null) { + for (TypeBinding binding : findMethod.parameters) { + methodSig.append(binding.signature()); + } + } + if (methodSig.toString().equals(jsniRef.paramTypesString())) { + return findMethod; + } + } + } else { + while (clazz != null) { + for (MethodBinding findMethod : clazz.getMethods(methodName.toCharArray())) { + if (paramTypesMatch(findMethod, jsniRef)) { + return findMethod; + } + } + clazz = clazz.superclass(); } } - return Sets.create(); + return null; } private boolean looksLikeAnonymousClass(JsniRef jsniRef) { @@ -365,6 +410,8 @@ return String.valueOf(type.shortReadableName()); } } + + private static final char[] INIT_CTOR_CHARS = "<init>".toCharArray(); private static final char[][] UNSAFE_LONG_ANNOTATION_CHARS = CharOperation.splitOn( '.', UnsafeNativeLong.class.getName().toCharArray()); @@ -379,9 +426,43 @@ TypeResolver typeResolver) { new JsniChecker(cud, typeResolver, jsniMethods).check(); } + + static Set<String> getSuppressedWarnings(Annotation[] annotations) { + if (annotations != null) { + for (Annotation a : annotations) { + if (SuppressWarnings.class.getName().equals( + CharOperation.toString(((ReferenceBinding) a.resolvedType).compoundName))) { + for (MemberValuePair pair : a.memberValuePairs()) { + if (String.valueOf(pair.name).equals("value")) { + Expression valueExpr = pair.value; + if (valueExpr instanceof StringLiteral) { + // @SuppressWarnings("Foo") + return Sets.create(((StringLiteral) valueExpr).constant.stringValue().toLowerCase( + Locale.ENGLISH)); + } else if (valueExpr instanceof ArrayInitializer) { + // @SuppressWarnings({ "Foo", "Bar"}) + ArrayInitializer ai = (ArrayInitializer) valueExpr; + String[] values = new String[ai.expressions.length]; + for (int i = 0, j = values.length; i < j; i++) { + values[i] = ((StringLiteral) ai.expressions[i]).constant.stringValue().toLowerCase( + Locale.ENGLISH); + } + return Sets.create(values); + } else { + throw new InternalCompilerException( + "Unable to analyze SuppressWarnings annotation"); + } + } + } + } + } + } + return Sets.create(); + } private final CompilationUnitDeclaration cud; private final Map<AbstractMethodDeclaration, JsniMethod> jsniMethods; + private final Stack<Set<String>> suppressWarningsStack = new Stack<Set<String>>(); private final TypeResolver typeResolver; private JsniChecker(CompilationUnitDeclaration cud, ======================================= --- /releases/2.0/dev/core/test/com/google/gwt/dev/javac/CompilationStateTestBase.java Thu Nov 12 05:54:31 2009 +++ /releases/2.0/dev/core/test/com/google/gwt/dev/javac/CompilationStateTestBase.java Thu Nov 19 14:34:20 2009 @@ -17,7 +17,6 @@ import com.google.gwt.core.ext.TreeLogger; import com.google.gwt.dev.javac.impl.JavaResourceBase; -import com.google.gwt.dev.javac.impl.MockJavaResource; import com.google.gwt.dev.javac.impl.MockResource; import com.google.gwt.dev.javac.impl.MockResourceOracle; import com.google.gwt.dev.resource.Resource; @@ -48,7 +47,7 @@ boolean reallyLog = false; if (reallyLog) { AbstractTreeLogger logger = new PrintWriterTreeLogger(); - logger.setMaxDetail(TreeLogger.ALL); + logger.setMaxDetail(TreeLogger.WARN); return logger; } return TreeLogger.NULL; @@ -102,7 +101,7 @@ protected CompilationState state = isolatedBuilder.doBuildFrom( createTreeLogger(), oracle.getResources()); - protected void addGeneratedUnits(MockJavaResource... sourceFiles) { + protected void addGeneratedUnits(MockResource... sourceFiles) { state.addGeneratedCompilationUnits(createTreeLogger(), getGeneratedUnits(sourceFiles)); } ======================================= --- /releases/2.0/dev/core/test/com/google/gwt/dev/javac/JavaCompilationSuite.java Wed Nov 11 11:04:31 2009 +++ /releases/2.0/dev/core/test/com/google/gwt/dev/javac/JavaCompilationSuite.java Thu Nov 19 14:34:20 2009 @@ -39,6 +39,7 @@ suite.addTestSuite(JdtCompilerTest.class); suite.addTestSuite(JSORestrictionsTest.class); suite.addTestSuite(JsniCheckerTest.class); + suite.addTestSuite(JsniCollectorTest.class); suite.addTestSuite(TypeOracleMediatorTest.class); suite.addTestSuite(CollectClassDataTest.class); ======================================= --- /releases/2.0/dev/core/test/com/google/gwt/dev/javac/JsniCheckerTest.java Wed Nov 11 11:04:31 2009 +++ /releases/2.0/dev/core/test/com/google/gwt/dev/javac/JsniCheckerTest.java Thu Nov 19 14:34:20 2009 @@ -61,6 +61,29 @@ shouldGenerateError(code, 10, "Referencing class \'Buggy$1.A: " + "JSNI references to anonymous classes are illegal"); } + + public void testArrayBadMember() { + StringBuffer code = new StringBuffer(); + code.append("class Buggy {\n"); + code.append(" native void jsniMethod() /*-{\n"); + code.append(" @Buggy[][]::blah;\n"); + code.append(" }-*/;\n"); + code.append("}\n"); + shouldGenerateError( + code, + 3, + "Referencing member 'Buggy[][].blah': 'class' is the only legal reference for array types"); + } + + public void testArrayClass() { + StringBuffer code = new StringBuffer(); + code.append("class Buggy {\n"); + code.append(" native void jsniMethod() /*-{\n"); + code.append(" @Buggy[][]::class;\n"); + code.append(" }-*/;\n"); + code.append("}\n"); + shouldGenerateNoWarning(code); + } public void testCyclicReferences() { { @@ -153,7 +176,28 @@ code.append(" @D::bar;\n"); code.append(" }-*/;\n"); code.append("}\n"); - + shouldGenerateNoWarning(code); + + // Check inherited suppress warnings. + code = new StringBuffer(); + code.append("@Deprecated class D {\n"); + code.append(" int bar;\n"); + code.append("}\n"); + code.append("@SuppressWarnings(\"deprecation\")\n"); + code.append("class Buggy {\n"); + code.append(" @Deprecated void foo(){}\n"); + code.append(" @Deprecated int bar;\n"); + code.append(" native void jsniMethod1() /*-{\n"); + code.append(" @Buggy::foo();\n"); + code.append(" @Buggy::bar;\n"); + code.append(" @D::bar;\n"); + code.append(" }-*/;\n"); + code.append(" native void jsniMethod2() /*-{\n"); + code.append(" @Buggy::foo();\n"); + code.append(" @Buggy::bar;\n"); + code.append(" @D::bar;\n"); + code.append(" }-*/;\n"); + code.append("}\n"); shouldGenerateNoWarning(code); } @@ -212,6 +256,47 @@ shouldGenerateError(code, 6, "Referencing field 'Buggy$Inner.x': " + "type 'long' is not safe to access in JSNI code"); } + + public void testInnerNew() { + StringBuffer code = new StringBuffer(); + code.append("public class Buggy {\n"); + code.append(" class Inner {\n"); + code.append(" long x = 3;\n"); + code.append(" Inner(boolean b) { };\n"); + code.append(" }\n"); + code.append(" native void jsniMeth() /*-{\n"); + code.append(" $wnd.alert(@Buggy.Inner::new(Z)(true).toString());\n"); + code.append(" }-*/;\n"); + code.append("}\n"); + + // Cannot resolve, missing synthetic enclosing instance. + shouldGenerateWarning(code, 7, "Referencing method 'Buggy.Inner.new(Z)': " + + "unable to resolve method, expect subsequent failures"); + + code = new StringBuffer(); + code.append("public class Buggy {\n"); + code.append(" static class Inner {\n"); + code.append(" long x = 3;\n"); + code.append(" Inner(boolean b) { };\n"); + code.append(" }\n"); + code.append(" native void jsniMeth() /*-{\n"); + code.append(" $wnd.alert(@Buggy.Inner::new(Z)(this, true).toString());\n"); + code.append(" }-*/;\n"); + code.append("}\n"); + shouldGenerateNoWarning(code); + + code = new StringBuffer(); + code.append("public class Buggy {\n"); + code.append(" class Inner {\n"); + code.append(" long x = 3;\n"); + code.append(" Inner(boolean b) { };\n"); + code.append(" }\n"); + code.append(" native void jsniMeth() /*-{\n"); + code.append(" $wnd.alert(@Buggy.Inner::new(LBuggy;Z)(this, true).toString());\n"); + code.append(" }-*/;\n"); + code.append("}\n"); + shouldGenerateNoWarning(code); + } /** * The proper behavior here is a close call. In hosted mode, Java arrays are @@ -248,6 +333,16 @@ shouldGenerateError(code, 2, "Type 'long' may not be returned from a JSNI method"); } + + public void testMalformedJsniRef() { + StringBuffer code = new StringBuffer(); + code.append("class Buggy {\n"); + code.append(" native void jsniMethod() /*-{\n"); + code.append(" @Buggy;\n"); + code.append(" }-*/;\n"); + code.append("}\n"); + shouldGenerateError(code, 3, "Expected \":\" in JSNI reference"); + } public void testMethodArgument() { StringBuffer code = new StringBuffer(); @@ -275,6 +370,25 @@ 4, "Referencing method 'Buggy.m': return type 'long' is not safe to access in JSNI code"); } + + public void testNew() { + StringBuffer code = new StringBuffer(); + code.append("class Buggy {\n"); + code.append(" static native Object main() /*-{\n"); + code.append(" return @Buggy::new()();\n"); + code.append(" }-*/;\n"); + code.append("}\n"); + shouldGenerateNoWarning(code); + + code = new StringBuffer(); + code.append("class Buggy {\n"); + code.append(" Buggy(boolean b) { }\n"); + code.append(" static native Object main() /*-{\n"); + code.append(" return @Buggy::new(Z)(true);\n"); + code.append(" }-*/;\n"); + code.append("}\n"); + shouldGenerateNoWarning(code); + } public void testNullField() { StringBuffer code = new StringBuffer(); @@ -324,6 +438,29 @@ 5, "Referencing method 'Buggy.m': return type 'long' is not safe to access in JSNI code"); } + + public void testPrimitiveBadMember() { + StringBuffer code = new StringBuffer(); + code.append("class Buggy {\n"); + code.append(" native void jsniMethod() /*-{\n"); + code.append(" @Z::blah;\n"); + code.append(" }-*/;\n"); + code.append("}\n"); + shouldGenerateError( + code, + 3, + "Referencing member 'Z.blah': 'class' is the only legal reference for primitive types"); + } + + public void testPrimitiveClass() { + StringBuffer code = new StringBuffer(); + code.append("class Buggy {\n"); + code.append(" native void jsniMethod() /*-{\n"); + code.append(" @Z::class;\n"); + code.append(" }-*/;\n"); + code.append("}\n"); + shouldGenerateNoWarning(code); + } public void testRefInString() { { @@ -337,6 +474,43 @@ shouldGenerateNoError(code); } } + + public void testUnresolvedClass() { + StringBuffer code = new StringBuffer(); + code.append("class Buggy {\n"); + code.append(" native void jsniMethod() /*-{\n"); + code.append(" @Foo::x;\n"); + code.append(" }-*/;\n"); + code.append("}\n"); + shouldGenerateWarning(code, 3, + "Referencing class 'Foo': unable to resolve class, expect subsequent failures"); + } + + public void testUnresolvedField() { + StringBuffer code = new StringBuffer(); + code.append("class Buggy {\n"); + code.append(" native void jsniMethod() /*-{\n"); + code.append(" @Buggy::x;\n"); + code.append(" }-*/;\n"); + code.append("}\n"); + shouldGenerateWarning( + code, + 3, + "Referencing field 'Buggy.x': unable to resolve field, expect subsequent failures"); + } + + public void testUnresolvedMethod() { + StringBuffer code = new StringBuffer(); + code.append("class Buggy {\n"); + code.append(" native void jsniMethod() /*-{\n"); + code.append(" @Buggy::x(Ljava/lang/String);\n"); + code.append(" }-*/;\n"); + code.append("}\n"); + shouldGenerateWarning( + code, + 3, + "Referencing method 'Buggy.x(Ljava/lang/String)': unable to resolve method, expect subsequent failures"); + } public void testUnsafeAnnotation() { { ======================================= --- /releases/2.0/dev/core/test/com/google/gwt/dev/javac/impl/StaticJavaResource.java Wed Nov 11 11:04:31 2009 +++ /releases/2.0/dev/core/test/com/google/gwt/dev/javac/impl/StaticJavaResource.java Thu Nov 19 14:34:20 2009 @@ -15,14 +15,12 @@ */ package com.google.gwt.dev.javac.impl; -import com.google.gwt.dev.javac.Shared; - -public class StaticJavaResource extends MockResource { +public class StaticJavaResource extends MockJavaResource { private final CharSequence source; - public StaticJavaResource(String typeName, CharSequence source) { - super(Shared.toPath(typeName)); + public StaticJavaResource(String qualifiedTypeName, CharSequence source) { + super(qualifiedTypeName); this.source = source; } ======================================= --- /releases/2.0/user/src/com/google/gwt/junit/JUnitShell.java Wed Nov 18 14:04:15 2009 +++ /releases/2.0/user/src/com/google/gwt/junit/JUnitShell.java Thu Nov 19 14:34:20 2009 @@ -899,6 +899,7 @@ return true; } + @Override protected boolean shouldAutoGenerateResources() { return shouldAutoGenerateResources; } ======================================= --- /releases/2.0/user/src/com/google/gwt/user/rebind/rpc/FieldSerializerCreator.java Wed Nov 11 12:06:42 2009 +++ /releases/2.0/user/src/com/google/gwt/user/rebind/rpc/FieldSerializerCreator.java Thu Nov 19 14:34:20 2009 @@ -143,7 +143,7 @@ ClassSourceFileComposerFactory composerFactory = new ClassSourceFileComposerFactory( packageName, className); - + composerFactory.addAnnotationDeclaration("@SuppressWarnings(\"deprecation\")"); return composerFactory.createSourceWriter(ctx, printWriter); } -- http://groups.google.com/group/Google-Web-Toolkit-Contributors
