diff options
author | Yigit Boyar <yboyar@google.com> | 2015-10-07 13:37:23 -0700 |
---|---|---|
committer | Yigit Boyar <yboyar@google.com> | 2015-10-07 13:44:56 -0700 |
commit | fd8342a51a96282df315cd27055ba539e89a8c9e (patch) | |
tree | 091a7001896fe75286e672e64cfedfd10e143226 | |
parent | 8510dab6a17ccd59a2a9cbc07f900dfc2f11ff2b (diff) | |
download | data-binding-fd8342a51a96282df315cd27055ba539e89a8c9e.tar.gz |
Report syntax errors even though Antlr can recover
This CL makes Antlr parser more strict by not allowing errors.
Antlr usually tries to recover from these errors but thats
not what we really want for this use case.
This CL also updates version codes to rc4 since rc3 is already out.
Change-Id: I0d305e06a6cdcbae2f37573c3c6ae4233cdd7958
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 |