diff options
8 files changed, 101 insertions, 5 deletions
diff --git a/compilationTests/src/test/java/android/databinding/compilationTest/SimpleCompilationTest.java b/compilationTests/src/test/java/android/databinding/compilationTest/SimpleCompilationTest.java index 8268a5ff..17e88e07 100644 --- a/compilationTests/src/test/java/android/databinding/compilationTest/SimpleCompilationTest.java +++ b/compilationTests/src/test/java/android/databinding/compilationTest/SimpleCompilationTest.java @@ -36,6 +36,7 @@ import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; +@SuppressWarnings("ThrowableResultOfMethodCallIgnored") public class SimpleCompilationTest extends BaseCompilationTest { @Test @@ -123,6 +124,28 @@ public class SimpleCompilationTest extends BaseCompilationTest { } @Test + public void testBadSyntax() throws IOException, URISyntaxException, InterruptedException { + singleFileErrorTest("/layout/layout_with_bad_syntax.xml", + "/app/src/main/res/layout/broken.xml", + "myVar.length())", + String.format(ErrorMessages.SYNTAX_ERROR, + "extraneous input ')' expecting {<EOF>, ',', '.', '[', '+', '-', '*', '/', " + + "'%', '<<', '>>>', '>>', '<=', '>=', '>', '<', 'instanceof', " + + "'==', '!=', '&', '^', '|', '&&', '||', '?', '??'}")); + } + + @Test + public void testBrokenSyntax() throws IOException, URISyntaxException, InterruptedException { + singleFileErrorTest("/layout/layout_with_completely_broken_syntax.xml", + "/app/src/main/res/layout/broken.xml", + "new String()", + String.format(ErrorMessages.SYNTAX_ERROR, + "mismatched input 'String' expecting {<EOF>, ',', '.', '[', '+', '-', '*', " + + "'/', '%', '<<', '>>>', '>>', '<=', '>=', '>', '<', 'instanceof'," + + " '==', '!=', '&', '^', '|', '&&', '||', '?', '??'}")); + } + + @Test public void testUndefinedVariable() throws IOException, URISyntaxException, InterruptedException { ScopedException ex = singleFileErrorTest("/layout/undefined_variable_binding.xml", diff --git a/compilationTests/src/test/resources/layout/layout_with_bad_syntax.xml b/compilationTests/src/test/resources/layout/layout_with_bad_syntax.xml new file mode 100644 index 00000000..6a90af87 --- /dev/null +++ b/compilationTests/src/test/resources/layout/layout_with_bad_syntax.xml @@ -0,0 +1,28 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ Copyright (C) 2015 The Android Open Source Project + ~ 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. + --> + +<layout xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:bind="http://schemas.android.com/apk/res-auto"> + <data> + <variable name="myVar" type="String"/> + </data> + <LinearLayout + android:orientation="vertical" + android:layout_width="match_parent" + android:layout_height="match_parent"> + <!-- undefined variable --> + <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" + android:text="@{myVar.length())}"/> + </LinearLayout> +</layout>
\ No newline at end of file diff --git a/compilationTests/src/test/resources/layout/layout_with_completely_broken_syntax.xml b/compilationTests/src/test/resources/layout/layout_with_completely_broken_syntax.xml new file mode 100644 index 00000000..dca87ae2 --- /dev/null +++ b/compilationTests/src/test/resources/layout/layout_with_completely_broken_syntax.xml @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ Copyright (C) 2015 The Android Open Source Project + ~ 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. + --> + +<layout xmlns:android="http://schemas.android.com/apk/res/android"> + <LinearLayout + android:orientation="vertical" + android:layout_width="match_parent" + android:layout_height="match_parent"> + <!-- undefined variable --> + <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" + android:text="@{new String()}"/> + </LinearLayout> +</layout>
\ No newline at end of file diff --git a/compiler/src/main/java/android/databinding/tool/ExpressionParser.java b/compiler/src/main/java/android/databinding/tool/ExpressionParser.java index 467f658b..27168a63 100644 --- a/compiler/src/main/java/android/databinding/tool/ExpressionParser.java +++ b/compiler/src/main/java/android/databinding/tool/ExpressionParser.java @@ -17,17 +17,23 @@ package android.databinding.tool; import org.antlr.v4.runtime.ANTLRInputStream; +import org.antlr.v4.runtime.BaseErrorListener; import org.antlr.v4.runtime.CommonTokenStream; import org.antlr.v4.runtime.ParserRuleContext; +import org.antlr.v4.runtime.RecognitionException; +import org.antlr.v4.runtime.Recognizer; +import org.antlr.v4.runtime.Token; import org.antlr.v4.runtime.misc.Nullable; import org.antlr.v4.runtime.tree.ErrorNode; import org.antlr.v4.runtime.tree.ParseTreeListener; import org.antlr.v4.runtime.tree.TerminalNode; +import org.apache.commons.lang3.StringUtils; import android.databinding.parser.BindingExpressionLexer; import android.databinding.parser.BindingExpressionParser; import android.databinding.tool.expr.Expr; import android.databinding.tool.expr.ExprModel; +import android.databinding.tool.processing.ErrorMessages; import android.databinding.tool.store.Location; import android.databinding.tool.util.L; import android.databinding.tool.util.Preconditions; @@ -49,6 +55,14 @@ public class ExpressionParser { BindingExpressionLexer lexer = new BindingExpressionLexer(inputStream); CommonTokenStream tokenStream = new CommonTokenStream(lexer); final BindingExpressionParser parser = new BindingExpressionParser(tokenStream); + parser.addErrorListener(new BaseErrorListener() { + @Override + public <T extends Token> void syntaxError(Recognizer<T, ?> recognizer, + @Nullable T offendingSymbol, int line, int charPositionInLine, String msg, + @Nullable RecognitionException e) { + L.e(ErrorMessages.SYNTAX_ERROR, msg); + } + }); BindingExpressionParser.BindingSyntaxContext root = parser.bindingSyntax(); try { mModel.setCurrentLocationInFile(locationInFile); diff --git a/compiler/src/main/java/android/databinding/tool/LayoutBinder.java b/compiler/src/main/java/android/databinding/tool/LayoutBinder.java index 1871577b..e099f286 100644 --- a/compiler/src/main/java/android/databinding/tool/LayoutBinder.java +++ b/compiler/src/main/java/android/databinding/tool/LayoutBinder.java @@ -199,8 +199,13 @@ public class LayoutBinder implements FileScopeProvider { final BindingTarget bindingTarget = createBindingTarget(targetBundle); for (BindingTargetBundle.BindingBundle bindingBundle : targetBundle .getBindingBundleList()) { - bindingTarget.addBinding(bindingBundle.getName(), - parse(bindingBundle.getExpr(), bindingBundle.getValueLocation())); + try { + Scope.enter(bindingBundle.getValueLocation()); + bindingTarget.addBinding(bindingBundle.getName(), + parse(bindingBundle.getExpr(), bindingBundle.getValueLocation())); + } finally { + Scope.exit(); + } } bindingTarget.resolveMultiSetters(); bindingTarget.resolveListeners(); diff --git a/compilerCommon/src/main/java/android/databinding/tool/processing/ErrorMessages.java b/compilerCommon/src/main/java/android/databinding/tool/processing/ErrorMessages.java index 6853ddba..5d7cb313 100644 --- a/compilerCommon/src/main/java/android/databinding/tool/processing/ErrorMessages.java +++ b/compilerCommon/src/main/java/android/databinding/tool/processing/ErrorMessages.java @@ -39,4 +39,5 @@ public class ErrorMessages { public static final String ROOT_TAG_NOT_SUPPORTED = "android:tag is not supported on root " + "elements of data bound layouts unless targeting API version 14 or greater. Value " + "is '%s'"; + public static final String SYNTAX_ERROR = "Syntax error: %s"; } diff --git a/compilerCommon/src/main/java/android/databinding/tool/processing/ScopedException.java b/compilerCommon/src/main/java/android/databinding/tool/processing/ScopedException.java index 238a895b..d60c2d5f 100644 --- a/compilerCommon/src/main/java/android/databinding/tool/processing/ScopedException.java +++ b/compilerCommon/src/main/java/android/databinding/tool/processing/ScopedException.java @@ -40,7 +40,8 @@ public class ScopedException extends RuntimeException { private String mScopeLog; public ScopedException(String message, Object... args) { - super(message == null ? "unknown data binding exception" : String.format(message, args)); + super(message == null ? "unknown data binding exception" : + args.length == 0 ? message : String.format(message, args)); mScopedErrorReport = Scope.createReport(); mScopeLog = L.isDebugEnabled() ? Scope.produceScopeLog() : null; } diff --git a/databinding.properties b/databinding.properties index 844231b1..737324ed 100644 --- a/databinding.properties +++ b/databinding.properties @@ -1,7 +1,7 @@ # global settings for projects kotlinVersion = 0.13.1514 -version = 1.0-rc3-SNAPSHOT -releaseVersion = 1.0-rc3 +version = 1.0-rc4-SNAPSHOT +releaseVersion = 1.0-rc4 androidPluginVersion = 1.4.0-beta5 javaTargetCompatibility = 1.7 javaSourceCompatibility = 1.7 |