diff --git a/pmd-visualforce/etc/grammar/VfParser.jjt b/pmd-visualforce/etc/grammar/VfParser.jjt index d8725ddaa7..f92958a36b 100644 --- a/pmd-visualforce/etc/grammar/VfParser.jjt +++ b/pmd-visualforce/etc/grammar/VfParser.jjt @@ -70,7 +70,7 @@ PARSER_END(VfParser) | <#XMLNAME: ( | "_" | ":") ()* > | <#QUOTED_STRING_NO_BREAKS: ( "'" ( ~["'", "\r", "\n"] )* "'" ) | ( "\"" ( ~["\"", "\r", "\n"] )* "\"" ) > -| <#QUOTED_STRING: ( "'" ( ~["'"] )* "'" ) | ( "\"" ( ~["\""] )* "\"" ) > +| <#QUOTED_STRING: ( "'" ( ~["'"] )* "'" ) | ( "\"" ( ~["\""] | "\\\"" )* "\"" ) > | <#WHITESPACE: ( " " | "\t" | "\n" | "\r" ) > | <#NEWLINE: ( "\r\n" | "\r" | "\n" ) > | <#QUOTE: ( "'" | "\"" )> @@ -82,6 +82,8 @@ PARSER_END(VfParser) | <#TEXT_IN_EL: (~["}", "'", "\""])+ > | <#CLOSEBRACE: ("}")> | <#DOT: "." > +| <#COMMNT_START: "/*" > +| <#COMMNT_END: "*/" > } @@ -90,7 +92,7 @@ PARSER_END(VfParser) < ()+ > } - SPECIAL_TOKEN: + SPECIAL_TOKEN: { < ()+ > } @@ -104,7 +106,6 @@ PARSER_END(VfParser) | : DocTypeState | : CDataState | : InTagState -| : InTagState } @@ -116,7 +117,7 @@ PARSER_END(VfParser) TOKEN : { - + | | | @@ -162,22 +163,25 @@ PARSER_END(VfParser) TOKEN : { - )? > : AttrValueBetweenSingleQuotesState + > : InlineCommentStateSQ +| )? > : AttrValueBetweenSingleQuotesState } TOKEN : -{ - )? > : AttrValueBetweenDoubleQuotesState +{ + > : InlineCommentStateDQ +| )? > : AttrValueBetweenDoubleQuotesState } TOKEN : { - )? > : AttrValueNoQuotesState + )? > : AttrValueNoQuotesState } TOKEN : { - )? > : HtmlScriptContentState + > : InlineCommentStateScript + | )? > : HtmlScriptContentState } TOKEN : @@ -232,7 +236,7 @@ PARSER_END(VfParser) { : InTagState | )? > : ElAttribTagStateNQ - | + | } @@ -246,18 +250,37 @@ PARSER_END(VfParser) TOKEN : { - : InTagState + : InTagState | )? > : ElAttribTagStateDQ - | } TOKEN : { - < COMMENT_END: ("--" (" ")* ">" | "->") > : AfterTagState + < COMMENT_END: ("--" (" ")* ">" ) > : AfterTagState | < COMMENT_TEXT: (~[]) > } + TOKEN : +{ + < COMMENT_CLOSE_SCRIPT: () > : ElInScriptState +| < COMMENT_INNER_TEXT_SCRIPT: (~[]) > +} + + TOKEN : +{ + < COMMENT_CLOSE_SQ: () > : ElAttribTagStateSQ +| < COMMENT_INNER_TEXT_SQ: (~[]) > +} + + + TOKEN : +{ + < COMMENT_CLOSE_DQ: () > : ElAttribTagStateDQ +| < COMMENT_INNER_TEXT_DQ: (~[]) > +} + TOKEN : { " > : AfterTagState @@ -265,12 +288,6 @@ PARSER_END(VfParser) | } - TOKEN : -{ - - | " > : AfterTagState -} - /** ************************* VF GRAMMAR **************************** */ /** @@ -328,11 +345,10 @@ void ContentElement() #void : {} { ( - CommentTag() + CommentTag() | Element() | CData() - | HtmlScript() - | HtmlStyle() + | HtmlScript() ) } @@ -409,7 +425,11 @@ void ElExpression() : void Expression() : {} { - ConditionalExpression() [ AssignmentOperator() Expression() ] + ConditionalExpression() [ AssignmentOperator() Expression() ] +| CommentExpression() ( ConditionalExpression() | CommentExpression() )* +| ELDQCommentExpression() ( ConditionalExpression() | ELDQCommentExpression() )* +| ELSQCommentExpression() ( ConditionalExpression() | ELSQCommentExpression() )* + } void AssignmentOperator() #void : @@ -489,17 +509,34 @@ void NegationExpression() #void : void PrimaryExpression() #void : {} { - PrimaryPrefix() ( LOOKAHEAD(2) PrimarySuffix() )* + PrimaryPrefix() ( LOOKAHEAD(2) PrimarySuffix() )* +} + +void ELSQCommentExpression() #void : +{} +{ + ( )* +} + +void ELDQCommentExpression() #void : +{} +{ + ( )* +} + +void CommentExpression() #void : +{} +{ + ( )* } void PrimaryPrefix() #void : {} { - Literal() - | Identifier() + Literal() + | Identifier() | Expression() | Expression() ( Expression())* - } void PrimarySuffix() #void : @@ -660,18 +697,10 @@ void Attribute() : ) } -void CommentTag() : +void CommentTag() #void : +{} { - StringBuffer content = new StringBuffer(); - Token t; -} -{ - - ( t = { content.append(t.image); } )* - - { - jjtThis.setImage(content.toString().trim()); - } + ( )* } void Declaration() : @@ -745,26 +774,3 @@ void HtmlScriptContent() #Text : { jjtThis.setImage(content.toString()); } } - -void HtmlStyle() : -{ - StringBuffer content = new StringBuffer(); - String tagName; - Token t; -} -{ - {} - (Attribute() )* {} - ( - ( - {token_source.SwitchTo(HtmlStyleContentState);} - (t = { content.append(t.image); })* - { jjtThis.setImage(content.toString().trim());} - - ) - | - ( - - ) - ) -} diff --git a/pmd-visualforce/src/main/ant/alljavacc.xml b/pmd-visualforce/src/main/ant/alljavacc.xml index a8890aab8f..9637b35151 100644 --- a/pmd-visualforce/src/main/ant/alljavacc.xml +++ b/pmd-visualforce/src/main/ant/alljavacc.xml @@ -33,8 +33,7 @@ javacchome="${javacc-home.path}" /> - comments = getNodes(ASTCommentTag.class, TEST_COMMENT); - assertEquals("One comment expected!", 1, comments.size()); - ASTCommentTag comment = comments.iterator().next(); - assertEquals("Correct comment content expected!", "comment", comment.getImage()); - } - /** * Test parsing of HTML <script> element. */ @@ -151,8 +139,48 @@ public class VfDocStyleTest extends AbstractVfNodesTest { ASTText text = script.getFirstChildOfType(ASTText.class); assertEquals("Correct script content expected!", "Script!", text.getImage()); } - - + + /** + * Test parsing of EL in attribute of an element. + */ + @Test + public void testELInTagValue() { + Set elememts = getNodes(ASTElement.class, TEST_EL_IN_TAG_ATTRIBUTE); + assertEquals("One element expected!", 1, elememts.size()); + ASTElement element = elememts.iterator().next(); + ASTAttributeValue attribute = element.getFirstDescendantOfType(ASTAttributeValue.class); + ASTIdentifier id = attribute.getFirstDescendantOfType(ASTIdentifier.class); + assertEquals("Correct identifier expected", "foo", id.getImage()); + + } + + /** + * Test parsing of EL in attribute of an element that also has a comment. + */ + @Test + public void testELInTagValueWithCommentDQ() { + Set elememts = getNodes(ASTElement.class, TEST_EL_IN_TAG_ATTRIBUTE_WITH_COMMENT); + assertEquals("One element expected!", 1, elememts.size()); + ASTElement element = elememts.iterator().next(); + ASTElExpression elExpr = element.getFirstDescendantOfType(ASTElExpression.class); + ASTIdentifier id = elExpr.getFirstDescendantOfType(ASTIdentifier.class); + assertEquals("Correct identifier expected", "init", id.getImage()); + } + + /** + * Test parsing of EL in attribute of an element that also has a comment. + */ + @Test + public void testELInTagValueWithCommentSQ() { + Set elememts = getNodes(ASTElement.class, TEST_EL_IN_TAG_ATTRIBUTE_WITH_COMMENT_SQ); + assertEquals("One element expected!", 1, elememts.size()); + ASTElement element = elememts.iterator().next(); + ASTElExpression elExpr = element.getFirstDescendantOfType(ASTElExpression.class); + ASTIdentifier id = elExpr.getFirstDescendantOfType(ASTIdentifier.class); + assertEquals("Correct identifier expected", "init", id.getImage()); + + } + /** * Test parsing of EL in HTML <script> element. */ @@ -167,7 +195,22 @@ public class VfDocStyleTest extends AbstractVfNodesTest { ASTIdentifier id = el.getFirstDescendantOfType(ASTIdentifier.class); assertEquals("Correct EL content expected!", "elInScript", id.getImage()); } - + + /** + * Test parsing of inline comment in EL. + */ + @Test + public void testInlineCommentInEL() { + Set scripts = getNodes(ASTHtmlScript.class, TEST_EL_IN_HTML_SCRIPT_WITH_COMMENT); + assertEquals("One script expected!", 1, scripts.size()); + ASTHtmlScript script = scripts.iterator().next(); + ASTText text = script.getFirstChildOfType(ASTText.class); + assertEquals("Correct script content expected!", "vartext=", text.getImage()); + ASTElExpression el = script.getFirstChildOfType(ASTElExpression.class); + ASTIdentifier id = el.getFirstDescendantOfType(ASTIdentifier.class); + assertEquals("Correct EL content expected!", "elInScript", id.getImage()); + } + /** * Test parsing of quoted EL in HTML <script> element. */ @@ -177,7 +220,7 @@ public class VfDocStyleTest extends AbstractVfNodesTest { assertEquals("One script expected!", 1, scripts.size()); ASTHtmlScript script = scripts.iterator().next(); ASTText text = script.getFirstChildOfType(ASTText.class); - assertEquals("Correct script content expected!", "vartext='textHere", text.getImage()); + assertEquals("Correct script content expected!", "vartext='textHere", text.getImage()); ASTElExpression el = script.getFirstChildOfType(ASTElExpression.class); ASTIdentifier id = el.getFirstDescendantOfType(ASTIdentifier.class); assertEquals("Correct EL content expected!", "elInScript", id.getImage()); @@ -224,19 +267,16 @@ public class VfDocStyleTest extends AbstractVfNodesTest { ASTHtmlScript next = script.iterator().next(); ASTText text = next.getFirstChildOfType(ASTText.class); assertTrue(text.getImage().contains(""; - private static final String TEST_ATTRIBUTE_VALUE_CONTAINING_HASH = " foo "; private static final String TEST_HTML_SCRIPT = ""; + private static final String TEST_EL_IN_TAG_ATTRIBUTE = "text"; + private static final String TEST_EL_IN_TAG_ATTRIBUTE_WITH_COMMENT = "text"; + private static final String TEST_EL_IN_TAG_ATTRIBUTE_WITH_COMMENT_SQ = "text"; + private static final String TEST_EL_IN_HTML_SCRIPT = ""; + private static final String TEST_EL_IN_HTML_SCRIPT_WITH_COMMENT = ""; private static final String TEST_QUOTED_EL_IN_HTML_SCRIPT = ""; diff --git a/src/site/markdown/overview/changelog.md b/src/site/markdown/overview/changelog.md index 1d94e760ab..2448b841c4 100644 --- a/src/site/markdown/overview/changelog.md +++ b/src/site/markdown/overview/changelog.md @@ -572,5 +572,6 @@ You need to use this, if you have a large project with many files, and you hit t * [#327](https://github.com/pmd/pmd/pull/327): \[apex] Fixed SOQL injection detection for escaped vars * [#331](https://github.com/pmd/pmd/pull/331): \[java] JunitTestsShouldIncludeAssertRule now handles AllocationExpression correctly * [#332](https://github.com/pmd/pmd/pull/332): \[java] Future-proof DontImportJavaLangRule +* [#340](https://github.com/pmd/pmd/pull/340): \[vf] Multiple parser bug fixes * [#341](https://github.com/pmd/pmd/pull/341): \[vf] JSON.parse(..) and NOT(..) are safely evaluated