From ec8759c1f52e2f62285c2b2f0f835ac9354b1c41 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg-Michael=20Grassau?= Date: Fri, 22 Sep 2023 17:16:46 +0200 Subject: [PATCH] improve Parser error message for chain colon inside parentheses (#91) --- .../sap/adt/abapcleaner/parser/Command.java | 53 +++++++++++-------- .../com/sap/adt/abapcleaner/parser/Token.java | 12 ++++- .../sap/adt/abapcleaner/parser/TokenTest.java | 14 +++++ 3 files changed, 54 insertions(+), 25 deletions(-) diff --git a/com.sap.adt.abapcleaner/src/com/sap/adt/abapcleaner/parser/Command.java b/com.sap.adt.abapcleaner/src/com/sap/adt/abapcleaner/parser/Command.java index 2740d058..2094cf94 100644 --- a/com.sap.adt.abapcleaner/src/com/sap/adt/abapcleaner/parser/Command.java +++ b/com.sap.adt.abapcleaner/src/com/sap/adt/abapcleaner/parser/Command.java @@ -2739,29 +2739,7 @@ public final boolean changesSyTFillOrTLeng() { return false; } - /** Returns true if the Command matches a hard-coded pattern or condition. - * This method can be used during development to search for examples in all sample code files. */ - public final boolean matchesPattern() { - // useful snippets: - // - is this a certain ABAP command? - // return firstCodeTokenIsKeyword("ABAP_KEYWORD"); - // - is a certain Token found anywhere? - // Token token = firstToken.getLastTokenDeep(true, TokenSearch.ASTERISK, "SEARCH_TEXT|ALTERNATIVE|..."); - // return (token != null && ...); - // - was a certain cleanup rule used? - // return changeControl.wasRuleUsed(RuleID....); - // - is a certain system field modified with at least 2 reads on this system field in subsequent program flow? - // return changesSyField(ABAP.SyField.SUBRC) && SyFieldAnalyzer.getSyFieldReadersFor(ABAP.SyField.SUBRC, this).size() >= 2; - // - getCommandsRelatedToPatternMatch() can then return SyFieldAnalyzer.getSyFieldReadersFor(ABAP.SyField.SUBRC, this); - - return this.getFirstToken().isAnyKeyword("WITH", "ENDWITH"); - //return false; - } - - public final ArrayList getCommandsRelatedToPatternMatch() { - return null; - } - + public final boolean containsMethodCallInsideConstructorExp() { Token token = firstToken; while (token != null) { @@ -2789,4 +2767,33 @@ public final boolean containsFunctionalMethodCallBetween(Token startToken, Token } return false; } + + public final boolean containsChainColonInsideParentheses() { + Token token = firstToken.getLastTokenDeep(true, TokenSearch.ASTERISK, ":"); + return (token != null && token.getParent() != null); + } + + /** Returns true if the Command matches a hard-coded pattern or condition. + * This method can be used during development to search for examples in all sample code files. */ + public final boolean matchesPattern() { + // useful snippets: + // - is this a certain ABAP command? + // return firstCodeTokenIsKeyword("ABAP_KEYWORD"); + // - is a certain Token found anywhere? + // Token token = firstToken.getLastTokenDeep(true, TokenSearch.ASTERISK, "SEARCH_TEXT|ALTERNATIVE|..."); + // return (token != null && ...); + // - was a certain cleanup rule used? + // return changeControl.wasRuleUsed(RuleID....); + // - is a certain system field modified with at least 2 reads on this system field in subsequent program flow? + // return changesSyField(ABAP.SyField.SUBRC) && SyFieldAnalyzer.getSyFieldReadersFor(ABAP.SyField.SUBRC, this).size() >= 2; + // - getCommandsRelatedToPatternMatch() can then return SyFieldAnalyzer.getSyFieldReadersFor(ABAP.SyField.SUBRC, this); + + return this.getFirstToken().isAnyKeyword("WITH", "ENDWITH"); + //return false; + } + + public final ArrayList getCommandsRelatedToPatternMatch() { + return null; + } + } \ No newline at end of file diff --git a/com.sap.adt.abapcleaner/src/com/sap/adt/abapcleaner/parser/Token.java b/com.sap.adt.abapcleaner/src/com/sap/adt/abapcleaner/parser/Token.java index b8d180a1..53314ed5 100644 --- a/com.sap.adt.abapcleaner/src/com/sap/adt/abapcleaner/parser/Token.java +++ b/com.sap.adt.abapcleaner/src/com/sap/adt/abapcleaner/parser/Token.java @@ -402,8 +402,16 @@ public final void addNext(Token newToken) throws UnexpectedSyntaxException { if (opensLevel && !newToken.closesLevel) { addChild(newToken); } else if (!opensLevel && newToken.closesLevel) { - if (parent == null) - throw new UnexpectedSyntaxException(this, "The Token '" + newToken.text + "' cannot be added to '" + text + "', because the latter has no parent Token."); + if (parent == null) { + String msg ; + if (parentCommand.containsChainColonInsideParentheses()) { + msg = "Chain colons inside parentheses or brackets are currently not supported by " + Program.PRODUCT_NAME + ". "; + msg += "Please rewrite this ABAP statement manually before running " + Program.PRODUCT_NAME + " on this code."; + } else { + msg = "The Token '" + newToken.text + "' cannot be added to '" + text + "', because the latter has no parent Token."; + } + throw new UnexpectedSyntaxException(this, msg); + } parent.addSibling(newToken); } else { addSibling(newToken); diff --git a/test/com.sap.adt.abapcleaner.test/src/com/sap/adt/abapcleaner/parser/TokenTest.java b/test/com.sap.adt.abapcleaner.test/src/com/sap/adt/abapcleaner/parser/TokenTest.java index 5aea1f12..937b63e9 100644 --- a/test/com.sap.adt.abapcleaner.test/src/com/sap/adt/abapcleaner/parser/TokenTest.java +++ b/test/com.sap.adt.abapcleaner.test/src/com/sap/adt/abapcleaner/parser/TokenTest.java @@ -249,6 +249,20 @@ void testAddNextErr() { } } + @Test + void testColonInsideParens() { + String codeText = "any_method( : 1 ), 2 )."; + try { + Code.parse(null, ParseParams.createForTest(codeText, ABAP.NEWEST_RELEASE)); + fail(); + } catch(ParseException ex) { + // expected case + assertTrue(ex.getMessage().indexOf("Chain colons inside parentheses") >= 0); + assertTrue(ex.getMessage().indexOf("not supported") >= 0); + assertTrue(ex.getMessage().indexOf("Please rewrite") >= 0); + } + } + @Test void testGetLastTokenOfSequence() { Command command = buildCommand("a = 1 + 2.");