diff --git a/qute.ls/com.redhat.qute.ls/src/main/java/com/redhat/qute/parser/validator/QuteSyntaxErrorCode.java b/qute.ls/com.redhat.qute.ls/src/main/java/com/redhat/qute/parser/validator/QuteSyntaxErrorCode.java
index a6a2c09a9..84fcb1672 100644
--- a/qute.ls/com.redhat.qute.ls/src/main/java/com/redhat/qute/parser/validator/QuteSyntaxErrorCode.java
+++ b/qute.ls/com.redhat.qute.ls/src/main/java/com/redhat/qute/parser/validator/QuteSyntaxErrorCode.java
@@ -48,8 +48,10 @@ public enum QuteSyntaxErrorCode implements IQuteErrorCode {
/**
* {#if test}Hello {name}
*/
- UNTERMINATED_SECTION("Parser error: unterminated section [{0}] detected", ParserError.UNTERMINATED_SECTION);
+ UNTERMINATED_SECTION("Parser error: unterminated section [{0}] detected", ParserError.UNTERMINATED_SECTION),
+ UNEXPECTED_TOKEN("Syntax error: `Unexpected ''{0}'' token`.", null);
+
private static List supportedErrorCodes;
private final String rawMessage;
diff --git a/qute.ls/com.redhat.qute.ls/src/main/java/com/redhat/qute/parser/validator/QuteSyntaxValidator.java b/qute.ls/com.redhat.qute.ls/src/main/java/com/redhat/qute/parser/validator/QuteSyntaxValidator.java
index 7ab833695..2aa3ffc58 100644
--- a/qute.ls/com.redhat.qute.ls/src/main/java/com/redhat/qute/parser/validator/QuteSyntaxValidator.java
+++ b/qute.ls/com.redhat.qute.ls/src/main/java/com/redhat/qute/parser/validator/QuteSyntaxValidator.java
@@ -16,9 +16,18 @@
import org.eclipse.lsp4j.Range;
+import com.redhat.qute.parser.expression.MethodPart;
+import com.redhat.qute.parser.expression.ObjectPart;
+import com.redhat.qute.parser.expression.Part;
+import com.redhat.qute.parser.expression.Parts.PartKind;
+import com.redhat.qute.parser.expression.PropertyPart;
import com.redhat.qute.parser.template.ASTVisitor;
+import com.redhat.qute.parser.template.Expression;
+import com.redhat.qute.parser.template.Node;
+import com.redhat.qute.parser.template.NodeKind;
+import com.redhat.qute.parser.template.Parameter;
import com.redhat.qute.parser.template.Section;
-import com.redhat.qute.parser.template.SectionKind;
+import com.redhat.qute.parser.template.Template;
import com.redhat.qute.parser.template.sections.CaseSection;
import com.redhat.qute.parser.template.sections.CustomSection;
import com.redhat.qute.parser.template.sections.EachSection;
@@ -218,4 +227,62 @@ private void validateSectionSyntax(Section section) {
}
}
+ @Override
+ public boolean visit(ObjectPart node) {
+ validateEndWithDotSyntax(node);
+ return super.visit(node);
+ }
+
+ public boolean visit(PropertyPart node) {
+ validateEndWithDotSyntax(node);
+ return super.visit(node);
+ }
+
+ public boolean visit(MethodPart node) {
+ // Validate end dot syntax for parameters
+ for (Parameter parameter : node.getParameters()) {
+ Expression expression = parameter.getJavaTypeExpression();
+ if (expression != null) {
+ expression.accept(this);
+ }
+ }
+ validateEndWithDotSyntax(node);
+ return super.visit(node);
+ }
+
+ private void validateEndWithDotSyntax(Part node) {
+ if (!hasFollowingPart(node)) {
+ Template template = node.getOwnerTemplate();
+ // It's the last part, check if it is not ended with '.'
+ int end = node.getPartKind() == PartKind.Method ? node.getEnd() + 1 : node.getEnd();
+ String text = template.getText();
+ if (end < text.length()) {
+ char c = text.charAt(end);
+ if (c == '.') {
+ Range range = QutePositionUtility.createRange(end, end + 1, template);
+ reporter.reportError(range, node,
+ QuteSyntaxErrorCode.UNEXPECTED_TOKEN, c);
+ }
+ }
+ }
+ }
+
+ private boolean hasFollowingPart(Part node) {
+ Node next = node.getNextSibling();
+ if (next == null) {
+ // - {name.}
+ // - {name.size().}
+ return false;
+ }
+ if (next.getKind() == NodeKind.ExpressionPart) {
+ Part nextPart = (Part) next;
+ if (nextPart.getPartKind() == PartKind.Method) {
+ // - {name.or(10)} <-- valid
+ // - {name. ?: 10} <-- invaid: infix notation
+ MethodPart methodPart = (MethodPart) nextPart;
+ return !methodPart.isInfixNotation();
+ }
+ }
+ return true;
+ }
}
diff --git a/qute.ls/com.redhat.qute.ls/src/main/java/com/redhat/qute/services/QuteDiagnostics.java b/qute.ls/com.redhat.qute.ls/src/main/java/com/redhat/qute/services/QuteDiagnostics.java
index ce32c8622..2c69573ff 100644
--- a/qute.ls/com.redhat.qute.ls/src/main/java/com/redhat/qute/services/QuteDiagnostics.java
+++ b/qute.ls/com.redhat.qute.ls/src/main/java/com/redhat/qute/services/QuteDiagnostics.java
@@ -597,21 +597,6 @@ private ResolvedJavaTypeInfo validateExpressionParts(Parts parts, Section ownerS
for (int i = 0; i < parts.getChildCount(); i++) {
Part current = parts.getChild(i);
- if (current.isLast()) {
- // It's the last part, check if it is not ended with '.'
- int end = current.getEnd();
- String text = template.getText();
- if (end < text.length()) {
- char c = text.charAt(end);
- if (c == '.') {
- Range range = QutePositionUtility.createRange(end, end + 1, template);
- Diagnostic diagnostic = createDiagnostic(range, DiagnosticSeverity.Error,
- QuteErrorCode.SyntaxError, "Unexpected '.' token.");
- diagnostics.add(diagnostic);
- }
- }
- }
-
switch (current.getPartKind()) {
case Namespace: {
diff --git a/qute.ls/com.redhat.qute.ls/src/test/java/com/redhat/qute/services/diagnostics/QuteDiagnosticsInExpressionTest.java b/qute.ls/com.redhat.qute.ls/src/test/java/com/redhat/qute/services/diagnostics/QuteDiagnosticsInExpressionTest.java
index 38e6a57ef..6f80914cc 100644
--- a/qute.ls/com.redhat.qute.ls/src/test/java/com/redhat/qute/services/diagnostics/QuteDiagnosticsInExpressionTest.java
+++ b/qute.ls/com.redhat.qute.ls/src/test/java/com/redhat/qute/services/diagnostics/QuteDiagnosticsInExpressionTest.java
@@ -365,22 +365,6 @@ public void undefineNamespace() throws Exception {
d)));
}
- @Test
- public void objectPartEndsWithDot() {
- String template = "{@java.util.List items}\r\n" + //
- "{items.}";
- testDiagnosticsFor(template, d(1, 6, 1, 7, QuteErrorCode.SyntaxError, //
- "Syntax error: `Unexpected '.' token.`.", DiagnosticSeverity.Error));
- }
-
- @Test
- public void propertyPartEndsWithDot() {
- String template = "{@java.util.List items}\r\n" + //
- "{items.size.}";
- testDiagnosticsFor(template, d(1, 11, 1, 12, QuteErrorCode.SyntaxError, //
- "Syntax error: `Unexpected '.' token.`.", DiagnosticSeverity.Error));
- }
-
@Test
public void invalidMethodVoid() {
String template = "{@java.lang.String string}\r\n" + //
diff --git a/qute.ls/com.redhat.qute.ls/src/test/java/com/redhat/qute/services/diagnostics/syntax/QuteDiagnosticsEndDotSyntaxErrorTest.java b/qute.ls/com.redhat.qute.ls/src/test/java/com/redhat/qute/services/diagnostics/syntax/QuteDiagnosticsEndDotSyntaxErrorTest.java
new file mode 100644
index 000000000..0dd530829
--- /dev/null
+++ b/qute.ls/com.redhat.qute.ls/src/test/java/com/redhat/qute/services/diagnostics/syntax/QuteDiagnosticsEndDotSyntaxErrorTest.java
@@ -0,0 +1,86 @@
+/*******************************************************************************
+* Copyright (c) 2023 Red Hat Inc. and others.
+* All rights reserved. This program and the accompanying materials
+* which accompanies this distribution, and is available at
+* http://www.eclipse.org/legal/epl-v20.html
+*
+* SPDX-License-Identifier: EPL-2.0
+*
+* Contributors:
+* Red Hat Inc. - initial API and implementation
+*******************************************************************************/
+package com.redhat.qute.services.diagnostics.syntax;
+
+import static com.redhat.qute.QuteAssert.d;
+import static com.redhat.qute.QuteAssert.testDiagnosticsFor;
+
+import org.eclipse.lsp4j.DiagnosticSeverity;
+import org.junit.jupiter.api.Test;
+
+import com.redhat.qute.parser.validator.QuteSyntaxErrorCode;
+
+/**
+ * Syntax error with end dot.
+ *
+ * @author Angelo ZERR
+ *
+ */
+public class QuteDiagnosticsEndDotSyntaxErrorTest {
+
+ @Test
+ public void objectPartEndsWithDot() {
+ String template = "{@java.util.List items}\r\n" + //
+ "{items.}";
+ testDiagnosticsFor(template, d(1, 6, 1, 7, QuteSyntaxErrorCode.UNEXPECTED_TOKEN, //
+ "Syntax error: `Unexpected '.' token`.", DiagnosticSeverity.Error));
+ }
+
+ @Test
+ public void objectPartInInfixNotationEndsWithDot() {
+ String template = "{@java.lang.String name}\r\n" + //
+ "{name. ?: \"Qute\"}";
+ testDiagnosticsFor(template, d(1, 5, 1, 6, QuteSyntaxErrorCode.UNEXPECTED_TOKEN, //
+ "Syntax error: `Unexpected '.' token`.", DiagnosticSeverity.Error));
+ }
+
+ @Test
+ public void objectPartInInfixNotationEndsWithDot2() {
+ String template = "{@java.lang.String name}\r\n" + //
+ "{name ?: name.}";
+ testDiagnosticsFor(template, d(1, 13, 1, 14, QuteSyntaxErrorCode.UNEXPECTED_TOKEN, //
+ "Syntax error: `Unexpected '.' token`.", DiagnosticSeverity.Error));
+ }
+
+ @Test
+ public void objectPartInMethodParamEndsWithDot() {
+ String template = "{@java.util.List items}\r\n" + //
+ "{@int index}\r\n" + //
+ "{items.get(index.)}";
+ testDiagnosticsFor(template, d(2, 16, 2, 17, QuteSyntaxErrorCode.UNEXPECTED_TOKEN, //
+ "Syntax error: `Unexpected '.' token`.", DiagnosticSeverity.Error));
+ }
+
+ @Test
+ public void propertyPartEndsWithDot() {
+ String template = "{@java.util.List items}\r\n" + //
+ "{items.size.}";
+ testDiagnosticsFor(template, d(1, 11, 1, 12, QuteSyntaxErrorCode.UNEXPECTED_TOKEN, //
+ "Syntax error: `Unexpected '.' token`.", DiagnosticSeverity.Error));
+ }
+
+ @Test
+ public void propertyPartInMethodParamEndsWithDot() {
+ String template = "{@java.util.List items}\r\n" + //
+ "{items.get(items.size.)}";
+ testDiagnosticsFor(template, d(1, 21, 1, 22, QuteSyntaxErrorCode.UNEXPECTED_TOKEN, //
+ "Syntax error: `Unexpected '.' token`.", DiagnosticSeverity.Error));
+ }
+
+ @Test
+ public void methodPartEndsWithDot() {
+ String template = "{@java.util.List items}\r\n" + //
+ "{items.size().}";
+ testDiagnosticsFor(template, d(1, 13, 1, 14, QuteSyntaxErrorCode.UNEXPECTED_TOKEN, //
+ "Syntax error: `Unexpected '.' token`.", DiagnosticSeverity.Error));
+ }
+}
diff --git a/qute.ls/com.redhat.qute.ls/src/test/java/com/redhat/qute/services/diagnostics/syntax/QuteDiagnosticsOverridedSyntaxErrorTest.java b/qute.ls/com.redhat.qute.ls/src/test/java/com/redhat/qute/services/diagnostics/syntax/overrided/QuteDiagnosticsSectionSyntaxErrorTest.java
similarity index 94%
rename from qute.ls/com.redhat.qute.ls/src/test/java/com/redhat/qute/services/diagnostics/syntax/QuteDiagnosticsOverridedSyntaxErrorTest.java
rename to qute.ls/com.redhat.qute.ls/src/test/java/com/redhat/qute/services/diagnostics/syntax/overrided/QuteDiagnosticsSectionSyntaxErrorTest.java
index 779e260eb..5caff9344 100644
--- a/qute.ls/com.redhat.qute.ls/src/test/java/com/redhat/qute/services/diagnostics/syntax/QuteDiagnosticsOverridedSyntaxErrorTest.java
+++ b/qute.ls/com.redhat.qute.ls/src/test/java/com/redhat/qute/services/diagnostics/syntax/overrided/QuteDiagnosticsSectionSyntaxErrorTest.java
@@ -9,7 +9,7 @@
* Contributors:
* Red Hat Inc. - initial API and implementation
*******************************************************************************/
-package com.redhat.qute.services.diagnostics.syntax;
+package com.redhat.qute.services.diagnostics.syntax.overrided;
import static com.redhat.qute.QuteAssert.ca;
import static com.redhat.qute.QuteAssert.d;
@@ -25,12 +25,13 @@
import com.redhat.qute.services.diagnostics.QuteErrorCode;
/**
- * Syntax error which improves the error of the real Qute parser.
+ * Syntax error which improves the error with sections from the real Qute
+ * parser.
*
* @author Angelo ZERR
*
*/
-public class QuteDiagnosticsOverridedSyntaxErrorTest {
+public class QuteDiagnosticsSectionSyntaxErrorTest {
@Test
public void UNTERMINATED_SECTION_with_let() throws Exception {