diff --git a/pmd-plsql/etc/grammar/PldocAST.jjt b/pmd-plsql/etc/grammar/PldocAST.jjt index 5e030fc847..470147434e 100644 --- a/pmd-plsql/etc/grammar/PldocAST.jjt +++ b/pmd-plsql/etc/grammar/PldocAST.jjt @@ -27,6 +27,11 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. /** + * Added ASTIsOfTypeCondition node, added support for USING IN|OUT|IN_OUT + * See PMD Bug #1520 + * + * Andreas Dangel 11/2016 + *==================================================================== * Adjusted ProgramUnit() to allow Pragma(), even though this is not * valid syntax. See PMD Bug #1527. * @@ -1368,7 +1373,7 @@ ASTOpenStatement OpenStatement() : { [Expression()] //[LOOKAHEAD(functionCall()) functionCall() | QualifiedName()] - [ Expression() [ Expression() ("," Expression())*]] + [ Expression() [ ( | | )? Expression() ("," ( | | )? Expression())*]] { return jjtThis ; } } @@ -1967,13 +1972,28 @@ ASTUnaryExpressionNotPlusMinus UnaryExpressionNotPlusMinus() : () {sb.append(" NOT "); } (simpleNode = UnaryExpression(false) ) { sb.append(simpleNode.getImage()); } | - (simpleNode = PrimaryExpression() ) { sb.append(simpleNode.getImage()); } + (simpleNode = IsOfTypeCondition() ) {sb.append(simpleNode.getImage()); } ) { jjtThis.setImage(sb.toString()); return jjtThis; } } +ASTIsOfTypeCondition IsOfTypeCondition() : +{ PLSQLNode simpleNode = null; PLSQLNode name = null; StringBuilder sb = new StringBuilder(); } +{ + ( + LOOKAHEAD( ) + ((name = Name()) {sb.append(name.getImage());} {sb.append(" IS");} [ {sb.append(" NOT");}] {sb.append(" OF");} [] + "(" [] Name() ("," [] Name() )* ")") + | + (simpleNode = PrimaryExpression() ) { sb.append(simpleNode.getImage()); } + ) + { + jjtThis.setImage(sb.toString()); return jjtThis; + } +} + /** * 2006-05-23 - Matthias Hendler - Added lookahead otherwise warning encountered. * Warning arised while adding methode triggerUnit(). @@ -3248,6 +3268,7 @@ TOKEN [IGNORE_CASE]: * Added: , , , * , , , * , + * 2016-11-04 - Andreas Dangel - Added , */ TOKEN [IGNORE_CASE]: @@ -3347,6 +3368,7 @@ TOKEN [IGNORE_CASE]: | | | + | | | | @@ -3408,6 +3430,7 @@ TOKEN [IGNORE_CASE]: | | | + | | | | diff --git a/pmd-plsql/src/main/java/net/sourceforge/pmd/lang/plsql/ast/PLSQLParserVisitorAdapter.java b/pmd-plsql/src/main/java/net/sourceforge/pmd/lang/plsql/ast/PLSQLParserVisitorAdapter.java index 87dda81911..470156e3e3 100644 --- a/pmd-plsql/src/main/java/net/sourceforge/pmd/lang/plsql/ast/PLSQLParserVisitorAdapter.java +++ b/pmd-plsql/src/main/java/net/sourceforge/pmd/lang/plsql/ast/PLSQLParserVisitorAdapter.java @@ -690,4 +690,8 @@ public class PLSQLParserVisitorAdapter implements PLSQLParserVisitor { return visit((PLSQLNode) node, data); } + @Override + public Object visit(ASTIsOfTypeCondition node, Object data) { + return visit((PLSQLNode) node, data); + } } diff --git a/pmd-plsql/src/main/java/net/sourceforge/pmd/lang/plsql/rule/AbstractPLSQLRule.java b/pmd-plsql/src/main/java/net/sourceforge/pmd/lang/plsql/rule/AbstractPLSQLRule.java index 00951897e1..2260a93e41 100644 --- a/pmd-plsql/src/main/java/net/sourceforge/pmd/lang/plsql/rule/AbstractPLSQLRule.java +++ b/pmd-plsql/src/main/java/net/sourceforge/pmd/lang/plsql/rule/AbstractPLSQLRule.java @@ -784,6 +784,10 @@ public abstract class AbstractPLSQLRule extends AbstractRule implements PLSQLPar public Object visit(ASTAccessibleByClause node, Object data) { return visit((PLSQLNode) node, data); } + @Override + public Object visit(ASTIsOfTypeCondition node, Object data) { + return visit((PLSQLNode) node, data); + } /* * Treat all Executable Code diff --git a/pmd-plsql/src/test/java/net/sourceforge/pmd/lang/plsql/PLSQLParserTest.java b/pmd-plsql/src/test/java/net/sourceforge/pmd/lang/plsql/PLSQLParserTest.java index dc11365fb6..df6e983ce1 100644 --- a/pmd-plsql/src/test/java/net/sourceforge/pmd/lang/plsql/PLSQLParserTest.java +++ b/pmd-plsql/src/test/java/net/sourceforge/pmd/lang/plsql/PLSQLParserTest.java @@ -50,4 +50,14 @@ public class PLSQLParserTest extends AbstractPLSQLParserTst { public void testBug1527() throws Exception { parsePLSQL(IOUtils.toString(PLSQLParserTest.class.getResourceAsStream("ast/InlinePragmaProcError.pls"))); } + + @Test + public void testBug1520IsOfType() throws Exception { + parsePLSQL(IOUtils.toString(PLSQLParserTest.class.getResourceAsStream("ast/IsOfType.pls"))); + } + + @Test + public void testBug1520Using() throws Exception { + parsePLSQL(IOUtils.toString(PLSQLParserTest.class.getResourceAsStream("ast/Using.pls"))); + } } diff --git a/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/IsOfType.pls b/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/IsOfType.pls new file mode 100644 index 0000000000..c536a73f45 --- /dev/null +++ b/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/IsOfType.pls @@ -0,0 +1,23 @@ +PROCEDURE IsOfType ( +inChannelID IN number, +inOperID IN number, +inClientId IN number, +ioFPOobj IN FPO_OBJ, +inPackageIDout IN number, +inStatusId IN number) +is +loFPOGE_OBJ FPOGE_OBJ; +BEGIN + +IF ioFPOobj IS OF (FPOGE_OBJ) THEN +loFPOGE_OBJ:=treat(ioFPOobj AS FPOGE_OBJ); +end if; + +IF ioFPOobj IS NOT OF TYPE (ONLY FPOGE_OBJ) THEN +loFPOGE_OBJ:=treat(ioFPOobj AS FPOGE_OBJ); +end if; + +loFPOGE_OBJ:=SELECT A FROM persons p WHERE IS OF TYPE (employee_t); +loFPOGE_OBJ:=SELECT A FROM persons p WHERE IS NOT OF TYPE (ONLY employee_t, other_t); + +end; \ No newline at end of file diff --git a/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/Using.pls b/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/Using.pls new file mode 100644 index 0000000000..3eaf1734f7 --- /dev/null +++ b/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/Using.pls @@ -0,0 +1,16 @@ +/* + * From: https://docs.oracle.com/cd/B13789_01/appdev.101/b10807/13_elems034.htm + */ +DECLARE + TYPE EmpCurTyp IS REF CURSOR; -- define weak REF CURSOR type + emp_cv EmpCurTyp; -- declare cursor variable + my_ename VARCHAR2(15); + my_sal NUMBER := 1000; +BEGIN + OPEN emp_cv FOR -- open cursor variable + 'SELECT ename, sal FROM emp WHERE sal > :s' USING my_sal; + open cursor for 'query' USING variable; + open cursor for 'query' USING IN variable; + open cursor for 'query' USING OUT variable, IN othervariable; + open cursor for 'query' USING IN_OUT variable; +END; diff --git a/src/site/markdown/overview/changelog.md b/src/site/markdown/overview/changelog.md index c6e2439e84..ec693a9b2c 100644 --- a/src/site/markdown/overview/changelog.md +++ b/src/site/markdown/overview/changelog.md @@ -41,6 +41,7 @@ * java-unusedcode/UnusedModifier * [#1480](https://sourceforge.net/p/pmd/bugs/1480/): false positive on public modifier used with inner interface in enum * PLSQL + * [#1520](https://sourceforge.net/p/pmd/bugs/1520/): \[plsql] Missing PL/SQL language constructs in parser: Is Of Type, Using * [#1527](https://sourceforge.net/p/pmd/bugs/1527/): \[plsql] PRAGMA AUTONOMOUS_TRANSACTION gives processing errors * [#1531](https://sourceforge.net/p/pmd/bugs/1531/): \[plsql] OOM/Endless loop while parsing (PL)SQL * General