Merge branch 'origin/master' into pr-3498

This commit is contained in:
Andreas Dangel 2021-09-23 13:25:40 +02:00
commit cacfeda085
No known key found for this signature in database
GPG Key ID: 93450DF2DF9A3FA3
21 changed files with 9105 additions and 61 deletions

6434
.all-contributorsrc Normal file

File diff suppressed because it is too large Load Diff

3
.gitignore vendored
View File

@ -16,5 +16,8 @@ pmd-core/dependency-reduced-pom.xml
vendor
.DS_Store
# node modules for https://allcontributors.org/docs/en/cli/installation
node_modules
# rule docs are generated
docs/pages/pmd/rules

View File

@ -57,4 +57,20 @@ See [pmd-checkstyle-config.xml](https://github.com/pmd/build-tools/blob/master/s
[the eclipse configuration files](https://github.com/pmd/build-tools/tree/master/eclipse) that can
be imported into a fresh workspace.
## Add yourself as contributor
We use [All Contributors](https://allcontributors.org/en).
To add yourself to the table of contributors, follow the
[bot usage instructions](https://allcontributors.org/docs/en/bot/usage) ;).
Or use the CLI:
1. Install the CLI: `npm i` (in PMD's top level directory)
2. Add yourself: `npx all-contributors add <username> <contribution>`
Where `username` is your GitHub username and `contribution` is a `,`-separated list
of contributions. See [Emoji Key](https://allcontributors.org/docs/en/emoji-key) for a list
of valid types. Common types are: "code", "doc", "bug", "blog", "talk", "test", "tutorial".
See also [cli documentation](https://allcontributors.org/docs/en/cli/usage)

View File

@ -1,4 +1,4 @@
# PMD
# PMD - source code analyzer
![PMD Logo](https://raw.githubusercontent.com/pmd/pmd/pmd/7.0.x/docs/images/logo/pmd-logo-300px.png)
@ -9,18 +9,42 @@
[![Coverage Status](https://coveralls.io/repos/github/pmd/pmd/badge.svg)](https://coveralls.io/github/pmd/pmd)
[![Codacy Badge](https://api.codacy.com/project/badge/Grade/a674ee8642ed44c6ba7633626ee95967)](https://www.codacy.com/app/pmd/pmd?utm_source=github.com&amp;utm_medium=referral&amp;utm_content=pmd/pmd&amp;utm_campaign=Badge_Grade)
[![Contributor Covenant](https://img.shields.io/badge/Contributor%20Covenant-v2.0%20adopted-ff69b4.svg)](code_of_conduct.md)
## About
[![Documentation (latest)](https://img.shields.io/badge/docs-latest-green)](https://pmd.github.io/latest/)
**PMD** is a source code analyzer. It finds common programming flaws like unused variables, empty catch blocks,
unnecessary object creation, and so forth. It supports Java, JavaScript, Salesforce.com Apex and Visualforce,
unnecessary object creation, and so forth. It supports many languages. It can be extended with custom rules.
It uses JavaCC and Antlr to parse source files into abstract syntax trees (AST) and runs rules against them to find violations.
Rules can be written in Java or using a XPath query.
It supports Java, JavaScript, Salesforce.com Apex and Visualforce,
Modelica, PLSQL, Apache Velocity, XML, XSL, Scala.
Additionally it includes **CPD**, the copy-paste-detector. CPD finds duplicated code in
C/C++, C#, Dart, Fortran, Go, Groovy, Java, JavaScript, JSP, Kotlin, Lua, Matlab, Modelica,
Objective-C, Perl, PHP, PLSQL, Python, Ruby, Salesforce.com Apex, Scala, Swift, Visualforce and XML.
## Support
In the future we hope to add support for data/control flow analysis and automatic (quick) fixes where
it makes sense.
## 🚀 Installation and Usage
Download the latest binary zip from the [releases](https://github.com/pmd/pmd/releases/latest)
and extract it somewhere.
Execute `bin/run.sh pmd` or `bin\pmd.bat`.
See also [Getting Started](https://pmd.github.io/latest/pmd_userdocs_installation.html)
**Demo:**
This shows how PMD can detect for loops, that can be replaced by for-each loops.
![Demo](docs/images/userdocs/pmd-demo.gif)
There are plugins for Maven and Gradle as well as for various IDEs.
See [Tools / Integrations](https://pmd.github.io/latest/pmd_userdocs_tools.html)
## How to get support?
* How do I? -- Ask a question on [StackOverflow](https://stackoverflow.com/questions/tagged/pmd)
or on [discussions](https://github.com/pmd/pmd/discussions).
@ -31,7 +55,9 @@ Objective-C, Perl, PHP, PLSQL, Python, Ruby, Salesforce.com Apex, Scala, Swift,
* I have a quick question -- ask on our [Gitter chat](https://gitter.im/pmd/pmd).
* Where's your documentation? -- <https://pmd.github.io/latest/>
## Source
## 🤝 Contributing
Pull requests are welcome. For major changes, please open an issue first to discuss what you would like to change.
Our latest source of PMD can be found on [GitHub](https://github.com/pmd/pmd). Fork us!
@ -42,6 +68,17 @@ The rule designer is developed over at [pmd/pmd-designer](https://github.com/pmd
Please see [its README](https://github.com/pmd/pmd-designer#contributing) for
developer documentation.
## Website
## 💵 Financial Contributors
More information can be found on our [Website](https://pmd.github.io).
Become a financial contributor and help us sustain our community. [Contribute](https://opencollective.com/pmd/contribute)
## ✨ Contributors
This project follows the [all-contributors](https://github.com/all-contributors/all-contributors) specification.
Contributions of any kind welcome!
See [credits](docs/pages/pmd/projectdocs/credits.md) for the complete list.
## 📝 License
[BSD Style](LICENSE)

View File

@ -1098,3 +1098,8 @@ h4.panel-title {
padding-top: 0px;
margin-top: 0px;
}
.post-content .all-contributors-list img {
width: 100px;
height: 100px;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 953 KiB

View File

@ -19,7 +19,7 @@ additional_js:
## Overview
## 💡 Overview
<!-- You can link to an individual panel, the id is determined from the title of the panel -->
<!-- See custom/shuffle_panel.html for the details -->
@ -45,18 +45,24 @@ things, PMD can be run:
**CPD**, the **copy-paste detector**, is also distributed with PMD. You can also use it
in a variety of ways, which are [documented here](pmd_userdocs_cpd.html).
## Download
## 💾 Download
The latest release of PMD can be downloaded from our [Github releases page](https://github.com/pmd/pmd/releases/latest).
The Logo is available from the [Logo Project Page](pmd_projectdocs_logo.html).
## Documentation
## 📖 Documentation
The rest of this page exposes the contents of the documentation site thematically,
which you can further scope down using the blue filter buttons. To navigate the site,
you may also use the search bar in the top right, or the sidebar on the left.
## ✨ Contributors
This project follows the [all-contributors](https://github.com/all-contributors/all-contributors) specification.
Contributions of any kind welcome!
See [credits](pmd_projectdocs_credits.html) for the complete list.
<br/>

File diff suppressed because it is too large Load Diff

View File

@ -19,12 +19,21 @@ This is a {{ site.pmd.release_type }} release.
### New and noteworthy
#### All Contributors
PMD follows the [All Contributors](https://allcontributors.org/) specification.
Contributions of any kind welcome!
See [credits](https://pmd.github.io/latest/pmd_projectdocs_credits.html) for our complete contributors list.
### Fixed Issues
* core
* [#3499](https://github.com/pmd/pmd/pull/3499): \[core] Fix XPath rulechain with combined node tests
* java-errorprone
* [#3493](https://github.com/pmd/pmd/pull/3493): \[java] AvoidAccessibilityAlteration: add tests and fix rule
* plsql
* [#3487](https://github.com/pmd/pmd/issues/3487): \[plsql] Parsing exception OPEN ref_cursor_name FOR statement
### API Changes

1160
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

5
package.json Normal file
View File

@ -0,0 +1,5 @@
{
"devDependencies": {
"all-contributors-cli": "^6.20.0"
}
}

View File

@ -4,9 +4,10 @@
package net.sourceforge.pmd.lang.apex.ast;
import java.lang.reflect.Field;
import java.util.Optional;
import org.apache.commons.lang3.reflect.FieldUtils;
import apex.jorje.data.Identifier;
import apex.jorje.data.ast.LiteralType;
import apex.jorje.semantic.ast.expression.LiteralExpression;
@ -69,29 +70,21 @@ public final class ASTLiteralExpression extends AbstractApexNode<LiteralExpressi
public String getName() {
if (getParent() instanceof ASTNewKeyValueObjectExpression) {
ASTNewKeyValueObjectExpression parent = (ASTNewKeyValueObjectExpression) getParent();
try {
Field exprField = NameValueParameter.class.getDeclaredField("expression");
exprField.setAccessible(true);
Optional<NameValueParameter> parameter = parent.node.getParameters().stream().filter(p -> {
try {
return this.node.equals(exprField.get(p));
} catch (IllegalArgumentException | IllegalAccessException e) {
return false;
}
}).findFirst();
Optional<NameValueParameter> parameter = parent.node.getParameters().stream().filter(p -> {
try {
return this.node.equals(FieldUtils.readDeclaredField(p, "expression", true));
} catch (IllegalArgumentException | IllegalAccessException e) {
return false;
}
}).findFirst();
Field nameField = NameValueParameter.class.getDeclaredField("name");
nameField.setAccessible(true);
return parameter.map(p -> {
try {
return (Identifier) nameField.get(p);
} catch (IllegalArgumentException | IllegalAccessException e) {
return null;
}
}).map(Identifier::getValue).orElse(null);
} catch (NoSuchFieldException | SecurityException e1) {
return null;
}
return parameter.map(p -> {
try {
return (Identifier) FieldUtils.readDeclaredField(p, "name", true);
} catch (IllegalArgumentException | IllegalAccessException e) {
return null;
}
}).map(Identifier::getValue).orElse(null);
}
return null;
}

View File

@ -4,7 +4,7 @@
package net.sourceforge.pmd.lang.apex.ast;
import java.lang.reflect.Field;
import org.apache.commons.lang3.reflect.FieldUtils;
import apex.jorje.semantic.ast.statement.TypeWhenBlock;
@ -22,9 +22,7 @@ public final class ASTTypeWhenBlock extends AbstractApexNode<TypeWhenBlock> {
public String getName() {
// unfortunately the name is not exposed...
try {
Field nameField = TypeWhenBlock.class.getDeclaredField("name");
nameField.setAccessible(true);
return String.valueOf(nameField.get(node));
return String.valueOf(FieldUtils.readDeclaredField(node, "name", true));
} catch (SecurityException | ReflectiveOperationException e) {
return null;
}

View File

@ -11,8 +11,6 @@ import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
@ -22,6 +20,8 @@ import java.util.Properties;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.reflect.FieldUtils;
import org.apache.commons.lang3.reflect.MethodUtils;
import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.types.Parameter;
@ -193,14 +193,14 @@ public class Formatter {
return writer;
}
// Note: With Java17, there will be
// https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/io/Console.html#charset()
private static String getConsoleEncoding() {
Console console = System.console();
// in case of pipe or redirect, no interactive console.
if (console != null) {
try {
Field f = Console.class.getDeclaredField("cs");
f.setAccessible(true);
Object res = f.get(console);
Object res = FieldUtils.readDeclaredField(console, "cs", true);
if (res instanceof Charset) {
return ((Charset) res).name();
}
@ -214,9 +214,7 @@ public class Formatter {
private static String getNativeConsoleEncoding() {
try {
Method m = Console.class.getDeclaredMethod("encoding");
m.setAccessible(true);
Object res = m.invoke(null);
Object res = MethodUtils.invokeStaticMethod(Console.class, "encoding");
if (res instanceof String) {
return (String) res;
}

View File

@ -50,6 +50,7 @@ public class AntLogHandler extends Handler {
this.project = project;
}
@SuppressWarnings("PMD.AvoidAccessibilityAlteration")
public Level getAntLogLevel() {
for (final BuildListener l : project.getBuildListeners()) {
Field declaredField = null;
@ -129,6 +130,7 @@ public class AntLogHandler extends Handler {
// nothing to do
}
@SuppressWarnings("PMD.AvoidAccessibilityAlteration")
private Level determineGradleLogLevel(BuildListener l) {
try {
project.log("Detected gradle AntLoggingAdapter", Project.MSG_DEBUG);

View File

@ -27,6 +27,10 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
/**
* Add support for Select statement within OPEN FOR Statements
*
* Andreas Dangel 09/2021
*====================================================================
* Add support for XMLROOT, improve ExtractExpression to support xml
*
* Piotr Szymanski 03/2020
@ -84,7 +88,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Andreas Dangel 07/2018
*====================================================================
* Added ASTIsOfTypeCondition node, added support for USING IN|OUT|IN_OUT
* Added ASTIsOfTypeCondition node, added support for USING IN|OUT|IN OUT
* See PMD Bug #1520
*
* Andreas Dangel 11/2016
@ -2713,13 +2717,17 @@ ASTCloseStatement CloseStatement() :
{ jjtThis.setImage(cursor.getImage()) ; return jjtThis ; }
}
/*
* See https://docs.oracle.com/en/database/oracle/oracle-database/18/lnpls/OPEN-statement.html#GUID-FB5A9CC3-655F-4AF4-8105-14CB39F2FEA8
* and https://docs.oracle.com/en/database/oracle/oracle-database/18/lnpls/OPEN-FOR-statement.html#GUID-EB7AF439-FDD3-4461-9E3F-B621E8ABFB96
*/
ASTOpenStatement OpenStatement() :
{}
{
<OPEN> [Expression()]
//[LOOKAHEAD(functionCall()) functionCall() | QualifiedName()]
[<FOR> Expression() [<USING> (<IN> | <OUT> | <IN_OUT>)? Expression() ("," (<IN> | <OUT> | <IN_OUT>)? Expression())*]]
{ return jjtThis ; }
<OPEN> [Expression()]
[<FOR> ( SelectStatement() | Expression() ) [ UsingClause() ] ]
{ return jjtThis ; }
}
/*
@ -2740,12 +2748,18 @@ ASTEmbeddedSqlStatement EmbeddedSqlStatement() :
{
<EXECUTE> <IMMEDIATE> StringExpression()
[ <INTO> Name() ("," Name())* ]
[ <USING> [ <IN> [ <OUT> ] | <OUT> ] Expression() ("," [ <IN> [ <OUT> ] | <OUT> ] Expression())* ]
[ UsingClause() ]
[ ( <RETURN> | <RETURNING> ) <INTO> Expression() ("," Expression())*] ";"
// PIPELINED FUNCTION OUTPUT
{ return jjtThis ; }
}
void UsingClause() #void :
{}
{
<USING> [ <IN> [ <OUT> ] | <OUT> ] Expression() ("," [ <IN> [ <OUT> ] | <OUT> ] Expression())*
}
ASTPipelineStatement PipelineStatement() :
{}
{
@ -4872,7 +4886,6 @@ TOKEN [IGNORE_CASE]:
<HOUR: "HOUR"> |
<IMMEDIATE: "IMMEDIATE"> |
<INNER: "INNER"> |
<IN_OUT: "IN_OUT"> |
<INDICES: "INDICES"> |
<INCLUDING: "INCLUDING"> |
<INDEXTYPE: "INDEXTYPE"> |

View File

@ -32,4 +32,8 @@ public class PlsqlTreeDumpTest extends BaseTreeDumpTest {
doTest("ParsingExclusion");
}
@Test
public void parseOpenForStatement() {
doTest("OpenForStatement");
}
}

View File

@ -0,0 +1,62 @@
--
-- See https://docs.oracle.com/en/database/oracle/oracle-database/18/lnpls/OPEN-FOR-statement.html#GUID-EB7AF439-FDD3-4461-9E3F-B621E8ABFB96
-- https://github.com/pmd/pmd/issues/3487
--
CREATE OR REPLACE PROCEDURE EXAMPLE_PROCEDURE IS
--
TYPE t_ref_cursor IS REF CURSOR;
--
l_ref_cursor t_ref_cursor;
--
BEGIN
--
OPEN l_ref_cursor FOR
SELECT *
FROM DUAL;
--
END EXAMPLE_PROCEDURE;
--
-- Example 6-26 Fetching Data with Cursor Variables
-- https://docs.oracle.com/en/database/oracle/oracle-database/18/lnpls/static-sql.html#GUID-AA5A2016-1B76-4961-9AFB-EB052F0D0FB2
--
DECLARE
cv SYS_REFCURSOR; -- cursor variable
v_lastname employees.last_name%TYPE; -- variable for last_name
v_jobid employees.job_id%TYPE; -- variable for job_id
query_2 VARCHAR2(200) :=
'SELECT * FROM employees
WHERE REGEXP_LIKE (job_id, ''[ACADFIMKSA]_M[ANGR]'')
ORDER BY job_id';
v_employees employees%ROWTYPE; -- record variable row of table
BEGIN
OPEN cv FOR
SELECT last_name, job_id FROM employees
WHERE REGEXP_LIKE (job_id, 'S[HT]_CLERK')
ORDER BY last_name;
LOOP -- Fetches 2 columns into variables
FETCH cv INTO v_lastname, v_jobid;
EXIT WHEN cv%NOTFOUND;
DBMS_OUTPUT.PUT_LINE( RPAD(v_lastname, 25, ' ') || v_jobid );
END LOOP;
DBMS_OUTPUT.PUT_LINE( '-------------------------------------' );
OPEN cv FOR query_2;
LOOP -- Fetches entire row into the v_employees record
FETCH cv INTO v_employees;
EXIT WHEN cv%NOTFOUND;
DBMS_OUTPUT.PUT_LINE( RPAD(v_employees.last_name, 25, ' ') ||
v_employees.job_id );
END LOOP;
CLOSE cv;
END;
/

View File

@ -12,5 +12,5 @@ BEGIN
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;
open cursor for 'query' USING IN OUT variable;
END;

View File

@ -94,7 +94,7 @@
<surefire.version>3.0.0-M5</surefire.version>
<checkstyle.version>8.42</checkstyle.version>
<checkstyle.plugin.version>3.1.2</checkstyle.plugin.version>
<pmd.plugin.version>3.14.0</pmd.plugin.version>
<pmd.plugin.version>3.15.0</pmd.plugin.version>
<ant.version>1.10.11</ant.version>
<javadoc.plugin.version>3.2.0</javadoc.plugin.version>
<antlr.version>4.8</antlr.version>