Merge branch 'master' into improve-method-naming-conventions-rule

This commit is contained in:
Clément Fournier
2018-04-27 00:07:52 +02:00
51 changed files with 1473 additions and 411 deletions

View File

@ -1,16 +1,11 @@
dist: trusty
sudo: false
addons:
apt:
packages:
- oracle-java9-installer
ssh_known_hosts:
- web.sourceforge.net
language: java
jdk: oraclejdk9
env:
global:
- secure: KBEuB6U1p5RQXSYe157AwydFr/zpXQPA0IChVCgZV+X1mMyy9ZtrjH1J1AXuviseDDXDbaT25sRnsvpl82rfRw2xOkMGXHy4N95/ylTSr8DjHxTao71BhXsvFycNobFva5y2EGNWqDvpS8I2oSZo7Qk4la3yep3rcJQvcy6RDbbhpDTbL1QMFyadunIBm0WtqbunrMqtjSqaoPsXz8TiQuxHvX4vEXzVbaxV1QQt79Vi+daa6wAV3mRQAugnx+UffsC8JqMxgm06usWeJgCJzxgm8E7clZCLmf53B2TL8dK6bIYbqyvOY3uFxitsTG0d8Z0GOJwXBgZNgbniTRO8ZJSty5eZP8LBybbjVLSL25DNTWtCjADUL/uySnXIEidlMt2N/3QmH7zrGAfAk/tIwKpdRca2GLLydeXf6PSkiahnPEkIY/QupcsOLELhdifpdOjb8QW1OenA+vUbNM9dccLwKnX6Fj9cu4VQG601AcYDr2eyhq8WYkr3wYdw/6KdUa3hmplowTBs+qguppP+eOSgGuEsy38KLtqnvm6WlHy6tcLmcVYKG3DmR1b7TWXsOXC6/VMH8BHBkvsF1QdRg9+Cgx07vX3Hw7roPiYzmaO9Ajs20ATsUfRskMuWCTeTSK5pN8X27veRCZlhFjeKQMDdmfVwzpAfRgKsl3TEn1I=
@ -31,9 +26,11 @@ matrix:
fast_finish: true
before_install:
- wget https://github.com/sormuras/bach/raw/master/install-jdk.sh
- bash .travis/setup-secrets.sh
- bash .travis/configure-maven.sh
install: true
# Install OracleJDK 10 - see https://sormuras.github.io/blog/2018-03-20-jdk-matrix.html
install: . ./install-jdk.sh -F 10 -L BCL
before_script: true
script: source .travis/build-$BUILD.sh
after_success: true

View File

@ -172,6 +172,9 @@ entries:
- title: Performance
output: web, pdf
url: /pmd_rules_java_performance.html
- title: Security
output: web, pdf
url: /pmd_rules_java_security.html
- title: null
output: web, pdf
subfolders:

View File

@ -323,6 +323,12 @@ folder: pmd/rules
* [UseStringBufferForStringAppends](pmd_rules_java_performance.html#usestringbufferforstringappends): The use of the '+=' operator for appending strings causes the JVM to create and use an internal S...
* [UseStringBufferLength](pmd_rules_java_performance.html#usestringbufferlength): Use StringBuffer.length() to determine StringBuffer length rather than using StringBuffer.toStrin...
## Security
{% include callout.html content="Rules that flag potential security flaws." %}
* [InsecureCryptoIv](pmd_rules_java_security.html#insecurecryptoiv): Do not use hard coded initialization vector in cryptographic operations. Please use a randomly ge...
## Additional rulesets
* Android (`rulesets/java/android.xml`):

View File

@ -0,0 +1,46 @@
---
title: Security
summary: Rules that flag potential security flaws.
permalink: pmd_rules_java_security.html
folder: pmd/rules/java
sidebaractiveurl: /pmd_rules_java.html
editmepath: ../pmd-java/src/main/resources/category/java/security.xml
keywords: Security, InsecureCryptoIv
language: Java
---
## InsecureCryptoIv
**Since:** PMD 6.3.0
**Priority:** Medium (3)
Do not use hard coded initialization vector in cryptographic operations. Please use a randomly generated IV.
**This rule is defined by the following Java class:** [net.sourceforge.pmd.lang.java.rule.security.InsecureCryptoIvRule](https://github.com/pmd/pmd/blob/master/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/security/InsecureCryptoIvRule.java)
**Example(s):**
``` java
public class Foo {
void good() {
SecureRandom random = new SecureRandom();
byte iv[] = new byte[16];
random.nextBytes(bytes);
}
void bad() {
byte[] iv = new byte[] { 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, };
}
void alsoBad() {
byte[] iv = "secret iv in here".getBytes();
}
}
```
**Use this rule by referencing it:**
``` xml
<rule ref="category/java/security.xml/InsecureCryptoIv" />
```

View File

@ -438,7 +438,8 @@ Here's a screenshot of CPD after running on the JDK 8 java.lang package:
## Suppression
Arbitrary blocks of code can be ignored through comments on **Java** by including the keywords `CPD-OFF` and `CPD-ON`.
Arbitrary blocks of code can be ignored through comments on **Java**, **C/C++**, **Javascript**, **Matlab**,
**Objective-C**, **PL/SQL** and **Python** by including the keywords `CPD-OFF` and `CPD-ON`.
public Object someParameterizedFactoryMethod(int x) throws Exception {
// some unignored code

View File

@ -57,7 +57,8 @@ After you add these references itll look something like this:
<!-- Now we'll customize a rule's property value -->
<rule ref="category/java/design.xml/CyclomaticComplexity">
<properties>
<property name="reportLevel" value="5"/>
<property name="classReportLevel" value="40"/>
<property name="methodReportLevel" value="5"/>
</properties>
</rule>

View File

@ -13,8 +13,11 @@ This is a minor release.
### Table Of Contents
* [New and noteworthy](#new-and-noteworthy)
* [Tree transversal revision](#tree-transversal-revision)
* [Naming rules enhancements](#naming-rules-enhancements)
* [Tree Traversal Revision](#tree-traversal-revision)
* [Naming Rules Enhancements](#naming-rules-enhancements)
* [CPD Suppression](#cpd-suppression)
* [Swift 4.1 Support](#swift-41-support)
* [New Rules](#new-rules)
* [Modified Rules](#modified-rules)
* [Fixed Issues](#fixed-issues)
* [API Changes](#api-changes)
@ -23,7 +26,7 @@ This is a minor release.
### New and noteworthy
#### Tree transversal revision
#### Tree Traversal Revision
As described in [#904](https://github.com/pmd/pmd/issues/904), when searching for child nodes of the AST methods
such as `hasDescendantOfType`, `getFirstDescendantOfType` and `findDescendantsOfType` were found to behave inconsistently,
@ -33,9 +36,9 @@ find boundaries.
This change implies several false positives / unexpected results (ie: `ASTBlockStatement` falsely returning `true` to `isAllocation()`)
have been fixed; and lots of searches are now restricted to smaller search areas, which improves performance (depending on the project,
we have measured up to 10% improvements during Type Resolution, Symbol Table analysis, and some rule's application).
we have measured up to 10% improvements during Type Resolution, Symbol Table analysis, and some rules' application).
#### Naming rules enhancements
#### Naming Rules Enhancements
* [`ClassNamingConventions`](pmd_rules_java_codestyle.html#classnamingconventions)
has been enhanced to allow granular configuration of naming
@ -47,10 +50,70 @@ we have measured up to 10% improvements during Type Resolution, Symbol Table ana
* [`MethodNamingConventions`](pmd_rules_java_codestyle.html#methodnamingconventions)
has been enhanced in the same way.
#### CPD Suppression
Back in PMD 5.6.0 we introduced the ability to suppress CPD warnings in Java using comments, by
including `CPD-OFF` (to start ignoring code), or `CPD-ON` (to resume analysis) during CPD execution.
This has proved to be much more flexible and versatile than the old annotation-based approach,
and has since been the preferred way to suppress CPD warnings.
On this ocassion, we are extending support for comment-based suppressions to many other languages:
* C/C++
* Ecmascript / Javascript
* Matlab
* Objective-C
* PL/SQL
* Python
So for instance, in Python we could now do:
```python
class BaseHandler(object):
def __init__(self):
# some unignored code
# tell cpd to start ignoring code - CPD-OFF
# mission critical code, manually loop unroll
GoDoSomethingAwesome(x + x / 2);
GoDoSomethingAwesome(x + x / 2);
GoDoSomethingAwesome(x + x / 2);
GoDoSomethingAwesome(x + x / 2);
GoDoSomethingAwesome(x + x / 2);
GoDoSomethingAwesome(x + x / 2);
# resume CPD analysis - CPD-ON
# further code will *not* be ignored
```
Other languages are equivalent.
#### Swift 4.1 Support
Thanks to major contributions from [kenji21](https://github.com/kenji21) the Swift grammar has been updated to support Swift 4.1.
This is a major update, since the old grammar was quite dated, and we are sure all iOS developers will enjoy it.
Unfortunately, this change is not compatible. The grammar elements that have been removed (ie: the keywords `__FILE__`,
`__LINE__`, `__COLUMN__` and `__FUNCTION__`) are no longer supported. We don't usually introduce such drastic / breaking
changes in minor releases, however, given that the whole Swift ecosystem pushes hard towards always using the latest
versions, and that Swift needs all code and libraries to be currently compiling against the same Swift version,
we felt strongly this change was both safe and necessary to be shipped as soon as possible. We had great feedback
from the comunity during the processm but if you have a legitimate use case for older Swift versions, please let us know
[on our Issue Tracke](https://github.com/pmd/pmd/issues).
#### New Rules
* The new Java rule [`InsecureCryptoIv`](pmd_rules_java_security.html#insecurecryptoiv) (`java-security`)
detects hard coded initialization vectors used in cryptographic operations. It is recommended to use
a randomly generated IV.
#### Modified Rules
* The Java rule `UnnecessaryConstructor` (`java-codestyle`) has been rewritten as a Java rule (previously it was
a XPath-based rule). It supports a new property `ignoredAnnotations` and ignores by default empty constructors,
* The Java rule [`UnnecessaryConstructor`](pmd_rules_java_codestyle.html#unnecessaryconstructor) (`java-codestyle`)
has been rewritten as a Java rule (previously it was a XPath-based rule). It supports a new property
`ignoredAnnotations` and ignores by default empty constructors,
that are annotated with `javax.inject.Inject`. Additionally, it detects now also unnecessary private constructors
in enums.
@ -62,12 +125,17 @@ we have measured up to 10% improvements during Type Resolution, Symbol Table ana
### Fixed Issues
* all
* [#695](https://github.com/pmd/pmd/issues/695): \[core] Extend comment-based suppression to all JavaCC languages
* [#988](https://github.com/pmd/pmd/issues/988): \[core] FileNotFoundException for missing classes directory with analysis cache enabled
* [#1036](https://github.com/pmd/pmd/issues/1036): \[core] Non-XML output breaks XML-based CLI integrations
* apex-errorprone
* [#776](https://github.com/pmd/pmd/issues/776): \[apex] AvoidHardcodingId false positives
* documentation
* [#994](https://github.com/pmd/pmd/issues/994): \[doc] Delete duplicate page contributing.md on the website
* java
* [#894](https://github.com/pmd/pmd/issues/894): \[java] Maven PMD plugin fails to process some files without any explanation
* [#899](https://github.com/pmd/pmd/issues/899): \[java] JavaTypeDefinitionSimple.toString can cause NPEs
* [#1020](https://github.com/pmd/pmd/issues/1020): \[java] The CyclomaticComplexity rule runs forever in 6.2.0
* [#1030](https://github.com/pmd/pmd/pull/1030): \[java] NoClassDefFoundError when analyzing PMD with PMD
* java-bestpractices
* [#370](https://github.com/pmd/pmd/issues/370): \[java] GuardLogStatementJavaUtil not considering lambdas
@ -77,8 +145,13 @@ we have measured up to 10% improvements during Type Resolution, Symbol Table ana
* java-codestyle
* [#1003](https://github.com/pmd/pmd/issues/1003): \[java] UnnecessaryConstructor triggered on required empty constructor (Dagger @Inject)
* [#1023](https://github.com/pmd/pmd/issues/1023): \[java] False positive for useless parenthesis
* java-errorprone
* [#629](https://github.com/pmd/pmd/issues/629): \[java] NullAssignment false positive
* [#816](https://github.com/pmd/pmd/issues/816): \[java] SingleMethodSingleton false positives with inner classes
* java-performance
* [#586](https://github.com/pmd/pmd/issues/586): \[java] AvoidUsingShortType erroneously triggered on overrides of 3rd party methods
* swift
* [#678](https://github.com/pmd/pmd/issues/678): \[swift][cpd] Exception when running for Swift 4 code (KeyPath)
### API Changes
@ -90,9 +163,14 @@ we have measured up to 10% improvements during Type Resolution, Symbol Table ana
### External Contributions
* [#778](https://github.com/pmd/pmd/pull/778): \[swift] Support Swift 4 grammar - [kenji21](https://github.com/kenji21)
* [#1002](https://github.com/pmd/pmd/pull/1002): \[doc] Delete duplicate page contributing.md on the website - [Ishan Srivastava](https://github.com/ishanSrt)
* [#1008](https://github.com/pmd/pmd/pull/1008): \[core] DOC: fix closing tag for &lt;pmdVersion> - [stonio](https://github.com/stonio)
* [#1010](https://github.com/pmd/pmd/pull/1010): \[java] UnnecessaryConstructor triggered on required empty constructor (Dagger @Inject) - [BBG](https://github.com/djydewang)
* [#1012](https://github.com/pmd/pmd/pull/1012): \[java] JUnitAssertionsShouldIncludeMessage - False positive with assertEquals and JUnit5 - [BBG](https://github.com/djydewang)
* [#1024](https://github.com/pmd/pmd/pull/1024): \[java]Issue 558: Properlogger for enums - [Utku Cuhadaroglu](https://github.com/utkuc)
* [#1024](https://github.com/pmd/pmd/pull/1024): \[java] Issue 558: Properlogger for enums - [Utku Cuhadaroglu](https://github.com/utkuc)
* [#1041](https://github.com/pmd/pmd/pull/1041): \[java] Make BasicProjectMemoizer thread safe. - [bergander](https://github.com/bergander)
* [#1042](https://github.com/pmd/pmd/pull/1042): \[java] New security rule: report usage of hard coded IV in crypto operations - [Sergey Gorbaty](https://github.com/sgorbaty)
* [#1044](https://github.com/pmd/pmd/pull/1044): \[java] Fix for issue #816 - [Akshat Bahety](https://github.com/akshatbahety)
* [#1048](https://github.com/pmd/pmd/pull/1048): \[core] Make MultiThreadProcessor more space efficient - [Gonzalo Exequiel Ibars Ingman](https://github.com/gibarsin)

View File

@ -4,18 +4,35 @@
package net.sourceforge.pmd.lang.apex.rule.errorprone;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Pattern;
import net.sourceforge.pmd.lang.apex.ast.ASTLiteralExpression;
import net.sourceforge.pmd.lang.apex.rule.AbstractApexRule;
public class AvoidHardcodingIdRule extends AbstractApexRule {
private static final Pattern PATTERN = Pattern.compile("^[a-zA-Z0-9]{5}[0][a-zA-Z0-9]{9,12}$", Pattern.CASE_INSENSITIVE);
private static final Pattern PATTERN = Pattern.compile("^[a-zA-Z0-9]{5}0[a-zA-Z0-9]{9}([a-zA-Z0-5]{3})?$");
private static final Map<String, Character> CHECKSUM_LOOKUP;
static {
final Map<String, Character> lookup = new HashMap<>();
final char[] chartable = "ABCDEFGHIJKLMNOPQRSTUVWXYZ012345".toCharArray();
for (int i = 0; i < chartable.length; i++) {
lookup.put(String.format("%5s", Integer.toBinaryString(i)).replace(' ', '0'), chartable[i]);
}
CHECKSUM_LOOKUP = Collections.unmodifiableMap(lookup);
}
public AvoidHardcodingIdRule() {
setProperty(CODECLIMATE_CATEGORIES, "Style");
setProperty(CODECLIMATE_REMEDIATION_MULTIPLIER, 100);
setProperty(CODECLIMATE_BLOCK_HIGHLIGHTING, false);
addRuleChainVisit(ASTLiteralExpression.class);
}
@Override
@ -24,9 +41,39 @@ public class AvoidHardcodingIdRule extends AbstractApexRule {
if (o instanceof String) {
String literal = (String) o;
if (PATTERN.matcher(literal).matches()) {
// 18-digit ids are just 15 digit ids + checksums, validate it or it's not an id
if (literal.length() == 18 && !validateChecksum(literal)) {
return data;
}
addViolation(data, node);
}
}
return data;
}
/*
* ID validation - sources:
* https://stackoverflow.com/questions/9742913/validating-a-salesforce-id#answer-29299786
* https://gist.github.com/jeriley/36b29f7c46527af4532aaf092c90dd56
*/
private boolean validateChecksum(String literal) {
final String part1 = literal.substring(0, 5);
final String part2 = literal.substring(5, 10);
final String part3 = literal.substring(10, 15);
final char checksum1 = checksum(part1);
final char checksum2 = checksum(part2);
final char checksum3 = checksum(part3);
return literal.charAt(15) == checksum1 && literal.charAt(16) == checksum2
&& literal.charAt(17) == checksum3;
}
private char checksum(String part) {
final StringBuilder sb = new StringBuilder(5);
for (int i = 4; i >= 0; i--) {
sb.append(Character.isUpperCase(part.charAt(i)) ? '1' : '0');
}
return CHECKSUM_LOOKUP.get(sb.toString());
}
}

View File

@ -50,4 +50,45 @@ public class Foo {
}
]]></code>
</test-code>
<test-code>
<description>Test for random string combinations - more than 15, less than 18 digits</description>
<expected-problems>0</expected-problems>
<code><![CDATA[
public class Foo {
void foo() {
return 'jatua0tzbtazi1243';
}
}
]]></code>
</test-code>
<test-code>
<description>Test for random string combinations - checksum doesn't match</description>
<expected-problems>0</expected-problems>
<code><![CDATA[
public class Foo {
void foo() {
return '001A0000006Vm9uIAE';
}
}
]]></code>
</test-code>
<test-code>
<description>[apex] AvoidHardcodingId false positives #776</description>
<expected-problems>0</expected-problems>
<code><![CDATA[
public class Foo {
void foo() {
// this is a false positive, we can't say, whether it's a salesforce id or not
@SuppressWarnings('PMD.AvoidHardcodingId')
String IMEI__c = '359040082913024';
// now the 6th character is non-0, definitive not a salesforce id
String IMEI2__c = '359041082913024';
}
}
]]></code>
</test-code>
</test-data>

View File

@ -15,7 +15,7 @@ import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.logging.Handler;
import java.util.logging.ConsoleHandler;
import java.util.logging.Level;
import java.util.logging.Logger;
@ -45,7 +45,6 @@ import net.sourceforge.pmd.util.database.DBURI;
import net.sourceforge.pmd.util.database.SourceObject;
import net.sourceforge.pmd.util.datasource.DataSource;
import net.sourceforge.pmd.util.datasource.ReaderDataSource;
import net.sourceforge.pmd.util.log.ConsoleLogHandler;
import net.sourceforge.pmd.util.log.ScopedLogHandlersManager;
/**
@ -450,8 +449,7 @@ public class PMD {
final PMDConfiguration configuration = params.toConfiguration();
final Level logLevel = params.isDebug() ? Level.FINER : Level.INFO;
final Handler logHandler = new ConsoleLogHandler();
final ScopedLogHandlersManager logHandlerManager = new ScopedLogHandlersManager(logLevel, logHandler);
final ScopedLogHandlersManager logHandlerManager = new ScopedLogHandlersManager(logLevel, new ConsoleHandler());
final Level oldLogLevel = LOG.getLevel();
// Need to do this, since the static logger has already been initialized
// at this point

View File

@ -351,7 +351,7 @@ public class CPDConfiguration extends AbstractConfiguration {
}
}
FilenameFilter filter = new FilenameFilter() {
return new FilenameFilter() {
@Override
public boolean accept(File dir, String name) {
File f = new File(dir, name);
@ -362,7 +362,6 @@ public class CPDConfiguration extends AbstractConfiguration {
return languageFilter.accept(dir, name);
}
};
return filter;
}
/**

View File

@ -720,7 +720,7 @@ public class GUI implements CPDListener {
final long start = System.currentTimeMillis();
Timer t = new Timer(1000, new ActionListener() {
return new Timer(1000, new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
long now = System.currentTimeMillis();
@ -731,7 +731,6 @@ public class GUI implements CPDListener {
timeField.setText(formatTime(minutes, seconds));
}
});
return t;
}
private static String formatTime(long minutes, long seconds) {
@ -762,7 +761,7 @@ public class GUI implements CPDListener {
private TableModel tableModelFrom(final List<Match> items) {
TableModel model = new SortingTableModel<Match>() {
return new SortingTableModel<Match>() {
private int sortColumn;
private boolean sortDescending;
@ -837,8 +836,6 @@ public class GUI implements CPDListener {
}
}
};
return model;
}
private void sortOnColumn(int columnIndex) {

View File

@ -0,0 +1,84 @@
/**
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
*/
package net.sourceforge.pmd.cpd.token;
import net.sourceforge.pmd.lang.TokenManager;
import net.sourceforge.pmd.lang.ast.GenericToken;
/**
* A generic filter for JavaCC-based token managers that allows to use comments
* to enable / disable analysis of parts of the stream
*/
public class JavaCCTokenFilter implements TokenFilter {
private final TokenManager tokenManager;
private boolean discardingSuppressing;
/**
* Creates a new JavaCCTokenFilter
* @param tokenManager The token manager from which to retrieve tokens to be filtered
*/
public JavaCCTokenFilter(final TokenManager tokenManager) {
this.tokenManager = tokenManager;
}
@Override
public final GenericToken getNextToken() {
GenericToken currentToken = (GenericToken) tokenManager.getNextToken();
while (!currentToken.getImage().isEmpty()) {
analyzeToken(currentToken);
processCPDSuppression(currentToken);
if (!isDiscarding()) {
return currentToken;
}
currentToken = (GenericToken) tokenManager.getNextToken();
}
return null;
}
private boolean isDiscarding() {
return discardingSuppressing || isLanguageSpecificDiscarding();
}
private void processCPDSuppression(final GenericToken currentToken) {
// Check if a comment is altering the suppression state
GenericToken comment = currentToken.getPreviousComment();
while (comment != null) {
if (comment.getImage().contains("CPD-OFF")) {
discardingSuppressing = true;
break;
}
if (comment.getImage().contains("CPD-ON")) {
discardingSuppressing = false;
break;
}
comment = comment.getPreviousComment();
}
}
/**
* Extension point for subclasses to indicate tokens are to be filtered.
*
* @return True if tokens should be filtered, false otherwise
*/
protected boolean isLanguageSpecificDiscarding() {
return false;
}
/**
* Extension point for subclasses to analyze all tokens (before filtering)
* and update internal status to decide on custom discard rules.
*
* @param currentToken The token to be analyzed
* @see #isLanguageSpecificDiscarding()
*/
protected void analyzeToken(final GenericToken currentToken) {
// noop
}
}

View File

@ -0,0 +1,19 @@
/**
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
*/
package net.sourceforge.pmd.cpd.token;
import net.sourceforge.pmd.lang.ast.GenericToken;
/**
* Defines filter to be applied to the token stream during CPD analysis
*/
public interface TokenFilter {
/**
* Retrieves the next token to pass the filter
* @return The next token to pass the filter, or null if the end of the stream was reached
*/
GenericToken getNextToken();
}

View File

@ -8,6 +8,7 @@ package net.sourceforge.pmd.lang;
* Common interface for interacting with parser Token Managers.
*/
public interface TokenManager {
// TODO : Change the return to GenericToken in 7.0.0 - maybe even use generics TokenManager<T extends GenericToken>
Object getNextToken();
void setFileName(String fileName);

View File

@ -28,6 +28,8 @@ public abstract class BasicProjectMemoizer<T extends QualifiableNode, O extends
private Map<QualifiedName, MetricMemoizer<T>> classes = new WeakHashMap<>();
private Map<QualifiedName, MetricMemoizer<O>> operations = new WeakHashMap<>();
private final Object classesSynchronizer = new Object();
private final Object operationsSynchronizer = new Object();
/** Clears all memoizers. Used for tests. */
public void reset() {
@ -38,8 +40,10 @@ public abstract class BasicProjectMemoizer<T extends QualifiableNode, O extends
@Override
public MetricMemoizer<O> getOperationMemoizer(QualifiedName qname) {
if (!operations.containsKey(qname)) {
operations.put(qname, new BasicMetricMemoizer<O>());
synchronized (operationsSynchronizer) {
if (!operations.containsKey(qname)) {
operations.put(qname, new BasicMetricMemoizer<O>());
}
}
return operations.get(qname);
@ -48,8 +52,10 @@ public abstract class BasicProjectMemoizer<T extends QualifiableNode, O extends
@Override
public MetricMemoizer<T> getClassMemoizer(QualifiedName qname) {
if (!classes.containsKey(qname)) {
classes.put(qname, new BasicMetricMemoizer<T>());
synchronized (classesSynchronizer) {
if (!classes.containsKey(qname)) {
classes.put(qname, new BasicMetricMemoizer<T>());
}
}
return classes.get(qname);

View File

@ -4,28 +4,26 @@
package net.sourceforge.pmd.processor;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CompletionService;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorCompletionService;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import net.sourceforge.pmd.PMDConfiguration;
import net.sourceforge.pmd.Report;
import net.sourceforge.pmd.renderers.Renderer;
/**
* @author Romain Pelisse &lt;belaran@gmail.com&gt;
*
*/
public class MultiThreadProcessor extends AbstractPMDProcessor {
private final ExecutorService executor;
private final CompletionService<Report> completionService;
private ExecutorService executor;
private CompletionService<Report> completionService;
private List<Future<Report>> tasks = new ArrayList<>();
private long submittedTasks = 0L;
public MultiThreadProcessor(final PMDConfiguration configuration) {
super(configuration);
@ -36,22 +34,21 @@ public class MultiThreadProcessor extends AbstractPMDProcessor {
@Override
protected void runAnalysis(PmdRunnable runnable) {
// multi-threaded execution, dispatch analysis to worker threads
tasks.add(completionService.submit(runnable));
completionService.submit(runnable);
submittedTasks++;
}
@Override
protected void collectReports(List<Renderer> renderers) {
// Collect result analysis, waiting for termination if needed
try {
for (int i = 0; i < tasks.size(); i++) {
for (int i = 0; i < submittedTasks; i++) {
final Report report = completionService.take().get();
super.renderReports(renderers, report);
}
} catch (InterruptedException ie) {
} catch (final InterruptedException ie) {
Thread.currentThread().interrupt();
} catch (ExecutionException ee) {
Throwable t = ee.getCause();
} catch (final ExecutionException ee) {
final Throwable t = ee.getCause();
if (t instanceof RuntimeException) {
throw (RuntimeException) t;
} else if (t instanceof Error) {

View File

@ -312,7 +312,7 @@ public class Designer implements ClipboardOwner {
@Override
public Enumeration<TreeNode> children() {
Enumeration<TreeNode> e = new Enumeration<TreeNode>() {
return new Enumeration<TreeNode>() {
int i = 0;
@Override
@ -325,7 +325,6 @@ public class Designer implements ClipboardOwner {
return kids[i++];
}
};
return e;
}
@Override
@ -395,7 +394,7 @@ public class Designer implements ClipboardOwner {
getChildAt(0); // force it to build kids
}
Enumeration<TreeNode> e = new Enumeration<TreeNode>() {
return new Enumeration<TreeNode>() {
int i = 0;
@Override
@ -408,7 +407,6 @@ public class Designer implements ClipboardOwner {
return kids[i++];
}
};
return e;
}
@Override

View File

@ -14,7 +14,9 @@ import java.util.logging.LogRecord;
* Log to the console using a basic formatter.
*
* @author Wouter Zelle
* @deprecated This class will be complety removed in 7.0.0
*/
@Deprecated
public class ConsoleLogHandler extends Handler {
private static final Formatter FORMATTER = new PmdLogFormatter();

View File

@ -36,7 +36,9 @@ public class ScopedLogHandlersManager {
}
for (Handler handler : newHandlers) {
logger.addHandler(handler);
handler.setLevel(level);
}
logger.setUseParentHandlers(false);
}
public void close() {
@ -47,5 +49,6 @@ public class ScopedLogHandlersManager {
logger.addHandler(handler);
}
logger.setLevel(oldLogLevel);
logger.setUseParentHandlers(true);
}
}

View File

@ -27,6 +27,6 @@
<rule ref="category/java/errorprone.xml" />
<rule ref="category/java/multithreading.xml" />
<rule ref="category/java/performance.xml" />
<!-- <rule ref="category/java/security.xml" /> -->
<rule ref="category/java/security.xml" />
</ruleset>

View File

@ -0,0 +1,13 @@
<?xml version="1.0"?>
<ruleset name="630"
xmlns="http://pmd.sourceforge.net/ruleset/2.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://pmd.sourceforge.net/ruleset/2.0.0 http://pmd.sourceforge.net/ruleset_2_0_0.xsd">
<description>
This ruleset contains links to rules that are new in PMD v6.3.0
</description>
<rule ref="category/java/security.xml/InsecureCryptoIv"/>
</ruleset>

View File

@ -129,10 +129,9 @@ public final class CppParser {
return sym.IsCtor(GetFullyScopedName());
}
}
PARSER_END(CppParser)
SKIP :
SKIP:
{
" "
|
@ -143,38 +142,28 @@ SKIP :
"\r\n"
|
"\n"
|
"//" : IN_LINE_COMMENT
|
"/*" : IN_COMMENT
|
"#" : PREPROCESSOR_OUTPUT
}
<IN_LINE_COMMENT> SKIP:
{
"\n" : DEFAULT
}
<DEFAULT,PREPROCESSOR_OUTPUT> SPECIAL_TOKEN:
{ <SINGLE_LINE_COMMENT: "//"(~["\n","\r"])* ("\n"|"\r"|"\r\n")?> }
<IN_LINE_COMMENT> MORE:
{
< ~[] >
}
MORE:
{ "/*" : IN_MULTI_LINE_COMMENT }
<IN_COMMENT> SKIP:
{ "*/" : DEFAULT }
<IN_MULTI_LINE_COMMENT> SPECIAL_TOKEN:
{ <MULTI_LINE_COMMENT: "*/">: DEFAULT }
<IN_COMMENT,IN_PREPROCESSOR_OUTPUT_COMMENT> MORE:
<IN_MULTI_LINE_COMMENT,IN_PREPROCESSOR_OUTPUT_COMMENT> MORE:
{ < ~[] > }
<IN_PREPROCESSOR_OUTPUT_COMMENT> SKIP:
{ "*/" : PREPROCESSOR_OUTPUT }
<IN_PREPROCESSOR_OUTPUT_COMMENT> SPECIAL_TOKEN:
{ <PREPROCESSOR_OUTPUT_COMMENT: "*/">: PREPROCESSOR_OUTPUT }
<PREPROCESSOR_OUTPUT> SKIP:
{
"\n" : DEFAULT
| "/*" : IN_PREPROCESSOR_OUTPUT_COMMENT
| "//" : IN_LINE_COMMENT
}
<PREPROCESSOR_OUTPUT> MORE:
@ -183,6 +172,8 @@ SKIP :
|
"\\\r\n"
|
"/*": IN_PREPROCESSOR_OUTPUT_COMMENT
|
< ~[] >
}

View File

@ -13,12 +13,13 @@ import java.util.Properties;
import org.apache.commons.io.IOUtils;
import net.sourceforge.pmd.PMD;
import net.sourceforge.pmd.cpd.token.JavaCCTokenFilter;
import net.sourceforge.pmd.cpd.token.TokenFilter;
import net.sourceforge.pmd.lang.LanguageRegistry;
import net.sourceforge.pmd.lang.LanguageVersionHandler;
import net.sourceforge.pmd.lang.TokenManager;
import net.sourceforge.pmd.lang.ast.GenericToken;
import net.sourceforge.pmd.lang.ast.TokenMgrError;
import net.sourceforge.pmd.lang.cpp.CppLanguageModule;
import net.sourceforge.pmd.lang.cpp.ast.Token;
import net.sourceforge.pmd.util.IOUtil;
/**
@ -61,13 +62,14 @@ public class CPPTokenizer implements Tokenizer {
.getDefaultVersion().getLanguageVersionHandler();
reader = new StringReader(maybeSkipBlocks(buffer.toString()));
reader = IOUtil.skipBOM(reader);
TokenManager tokenManager = languageVersionHandler
.getParser(languageVersionHandler.getDefaultParserOptions())
.getTokenManager(sourceCode.getFileName(), reader);
Token currentToken = (Token) tokenManager.getNextToken();
while (currentToken.image.length() > 0) {
tokenEntries.add(new TokenEntry(currentToken.image, sourceCode.getFileName(), currentToken.beginLine));
currentToken = (Token) tokenManager.getNextToken();
final TokenFilter tokenFilter = new JavaCCTokenFilter(
languageVersionHandler.getParser(languageVersionHandler.getDefaultParserOptions())
.getTokenManager(sourceCode.getFileName(), reader));
GenericToken currentToken = tokenFilter.getNextToken();
while (currentToken != null) {
tokenEntries.add(new TokenEntry(currentToken.getImage(), sourceCode.getFileName(), currentToken.getBeginLine()));
currentToken = tokenFilter.getNextToken();
}
tokenEntries.add(TokenEntry.getEOF());
System.err.println("Added " + sourceCode.getFileName());

View File

@ -5,6 +5,7 @@
package net.sourceforge.pmd.cpd;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotSame;
import static org.junit.Assert.assertTrue;
import java.util.Properties;
@ -19,7 +20,7 @@ public class CPPTokenizerTest {
@Test
public void testUTFwithBOM() {
Tokens tokens = parse("\ufeffint start()\n{ int ret = 1;\nreturn ret;\n}\n");
assertTrue(TokenEntry.getEOF() != tokens.getTokens().get(0));
assertNotSame(TokenEntry.getEOF(), tokens.getTokens().get(0));
assertEquals(15, tokens.size());
}
@ -29,9 +30,19 @@ public class CPPTokenizerTest {
+ "int main()\n" + "{\n" + " std::string text(\"ąęćśźńó\");\n" + " std::cout << text;\n"
+ " return 0;\n" + "}\n";
Tokens tokens = parse(code);
assertTrue(TokenEntry.getEOF() != tokens.getTokens().get(0));
assertNotSame(TokenEntry.getEOF(), tokens.getTokens().get(0));
assertEquals(24, tokens.size());
}
@Test
public void testIgnoreBetweenSpecialComments() {
String code = "#include <iostream>\n" + "#include <string>\n" + "\n" + "// CPD-OFF\n"
+ "int main()\n" + "{\n" + " std::string text(\"ąęćśźńó\");\n" + " std::cout << text;\n"
+ " return 0;\n" + "// CPD-ON\n" + "}\n";
Tokens tokens = parse(code);
assertNotSame(TokenEntry.getEOF(), tokens.getTokens().get(0));
assertEquals(2, tokens.size()); // "}" + EOF
}
@Test
public void testMultiLineMacros() {

View File

@ -9,9 +9,11 @@ import java.util.Deque;
import java.util.LinkedList;
import java.util.Properties;
import net.sourceforge.pmd.cpd.token.JavaCCTokenFilter;
import net.sourceforge.pmd.lang.LanguageRegistry;
import net.sourceforge.pmd.lang.LanguageVersionHandler;
import net.sourceforge.pmd.lang.TokenManager;
import net.sourceforge.pmd.lang.ast.GenericToken;
import net.sourceforge.pmd.lang.java.JavaLanguageModule;
import net.sourceforge.pmd.lang.java.ast.JavaParserConstants;
import net.sourceforge.pmd.lang.java.ast.Token;
@ -31,34 +33,30 @@ public class JavaTokenizer implements Tokenizer {
ignoreIdentifiers = Boolean.parseBoolean(properties.getProperty(IGNORE_IDENTIFIERS, "false"));
}
@Override
public void tokenize(SourceCode sourceCode, Tokens tokenEntries) {
StringBuilder stringBuilder = sourceCode.getCodeBuffer();
// Note that Java version is irrelevant for tokenizing
LanguageVersionHandler languageVersionHandler = LanguageRegistry.getLanguage(JavaLanguageModule.NAME)
.getVersion("1.4").getLanguageVersionHandler();
String fileName = sourceCode.getFileName();
TokenManager tokenMgr = languageVersionHandler.getParser(languageVersionHandler.getDefaultParserOptions())
.getTokenManager(fileName, new StringReader(stringBuilder.toString()));
Token currentToken = (Token) tokenMgr.getNextToken();
TokenDiscarder discarder = new TokenDiscarder(ignoreAnnotations);
ConstructorDetector constructorDetector = new ConstructorDetector(ignoreIdentifiers);
while (currentToken.image.length() > 0) {
discarder.updateState(currentToken);
if (discarder.isDiscarding()) {
currentToken = (Token) tokenMgr.getNextToken();
continue;
}
final String fileName = sourceCode.getFileName();
final JavaTokenFilter tokenFilter = createTokenFilter(sourceCode);
final ConstructorDetector constructorDetector = new ConstructorDetector(ignoreIdentifiers);
Token currentToken = (Token) tokenFilter.getNextToken();
while (currentToken != null) {
processToken(tokenEntries, fileName, currentToken, constructorDetector);
currentToken = (Token) tokenMgr.getNextToken();
currentToken = (Token) tokenFilter.getNextToken();
}
tokenEntries.add(TokenEntry.getEOF());
}
private JavaTokenFilter createTokenFilter(final SourceCode sourceCode) {
final StringBuilder stringBuilder = sourceCode.getCodeBuffer();
// Note that Java version is irrelevant for tokenizing
final LanguageVersionHandler languageVersionHandler = LanguageRegistry.getLanguage(JavaLanguageModule.NAME)
.getVersion("1.4").getLanguageVersionHandler();
final TokenManager tokenMgr = languageVersionHandler.getParser(languageVersionHandler.getDefaultParserOptions())
.getTokenManager(sourceCode.getFileName(), new StringReader(stringBuilder.toString()));
return new JavaTokenFilter(tokenMgr, ignoreAnnotations);
}
private void processToken(Tokens tokenEntries, String fileName, Token currentToken,
ConstructorDetector constructorDetector) {
String image = currentToken.image;
@ -93,15 +91,14 @@ public class JavaTokenizer implements Tokenizer {
}
/**
* The {@link TokenDiscarder} consumes token by token and maintains state.
* It can detect, whether the current token belongs to an annotation and
* whether the current token should be discarded by CPD.
* The {@link JavaTokenFilter} extends the {@link JavaCCTokenFilter} to discard
* Java-specific tokens.
* <p>
* By default, it discards semicolons, package and import statements, and
* enables CPD suppression. Optionally, all annotations can be ignored, too.
* enables annotation-based CPD suppression. Optionally, all annotations can be ignored, too.
* </p>
*/
private static class TokenDiscarder {
private static class JavaTokenFilter extends JavaCCTokenFilter {
private boolean isAnnotation = false;
private boolean nextTokenEndsAnnotation = false;
private int annotationStack = 0;
@ -112,22 +109,24 @@ public class JavaTokenizer implements Tokenizer {
private boolean discardingAnnotations = false;
private boolean ignoreAnnotations = false;
TokenDiscarder(boolean ignoreAnnotations) {
JavaTokenFilter(final TokenManager tokenManager, final boolean ignoreAnnotations) {
super(tokenManager);
this.ignoreAnnotations = ignoreAnnotations;
}
public void updateState(Token currentToken) {
detectAnnotations(currentToken);
@Override
protected void analyzeToken(final GenericToken currentToken) {
detectAnnotations((Token) currentToken);
skipSemicolon(currentToken);
skipPackageAndImport(currentToken);
skipCPDSuppression(currentToken);
skipSemicolon((Token) currentToken);
skipPackageAndImport((Token) currentToken);
skipAnnotationSuppression((Token) currentToken);
if (ignoreAnnotations) {
skipAnnotations();
}
}
private void skipPackageAndImport(Token currentToken) {
private void skipPackageAndImport(final Token currentToken) {
if (currentToken.kind == JavaParserConstants.PACKAGE || currentToken.kind == JavaParserConstants.IMPORT) {
discardingKeywords = true;
} else if (discardingKeywords && currentToken.kind == JavaParserConstants.SEMICOLON) {
@ -135,7 +134,7 @@ public class JavaTokenizer implements Tokenizer {
}
}
private void skipSemicolon(Token currentToken) {
private void skipSemicolon(final Token currentToken) {
if (currentToken.kind == JavaParserConstants.SEMICOLON) {
discardingSemicolon = true;
} else if (discardingSemicolon && currentToken.kind != JavaParserConstants.SEMICOLON) {
@ -143,21 +142,7 @@ public class JavaTokenizer implements Tokenizer {
}
}
private void skipCPDSuppression(Token currentToken) {
// Check if a comment is altering the suppression state
Token st = currentToken.specialToken;
while (st != null) {
if (st.image.contains("CPD-OFF")) {
discardingSuppressing = true;
break;
}
if (st.image.contains("CPD-ON")) {
discardingSuppressing = false;
break;
}
st = st.specialToken;
}
private void skipAnnotationSuppression(final Token currentToken) {
// if processing an annotation, look for a CPD-START or CPD-END
if (isAnnotation) {
if (!discardingSuppressing && currentToken.kind == JavaParserConstants.STRING_LITERAL
@ -178,7 +163,8 @@ public class JavaTokenizer implements Tokenizer {
}
}
public boolean isDiscarding() {
@Override
protected boolean isLanguageSpecificDiscarding() {
return discardingSemicolon || discardingKeywords || discardingAnnotations
|| discardingSuppressing;
}

View File

@ -5,21 +5,26 @@
package net.sourceforge.pmd.lang.java.rule.errorprone;
import net.sourceforge.pmd.lang.java.ast.ASTAssignmentOperator;
import net.sourceforge.pmd.lang.java.ast.ASTBlockStatement;
import net.sourceforge.pmd.lang.java.ast.ASTConditionalExpression;
import net.sourceforge.pmd.lang.java.ast.ASTEqualityExpression;
import net.sourceforge.pmd.lang.java.ast.ASTExpression;
import net.sourceforge.pmd.lang.java.ast.ASTLambdaExpression;
import net.sourceforge.pmd.lang.java.ast.ASTName;
import net.sourceforge.pmd.lang.java.ast.ASTNullLiteral;
import net.sourceforge.pmd.lang.java.ast.ASTReturnStatement;
import net.sourceforge.pmd.lang.java.ast.ASTStatementExpression;
import net.sourceforge.pmd.lang.java.ast.ASTVariableInitializer;
import net.sourceforge.pmd.lang.java.ast.AccessNode;
import net.sourceforge.pmd.lang.java.rule.AbstractJavaRule;
import net.sourceforge.pmd.lang.java.symboltable.VariableNameDeclaration;
// TODO - should check that this is not the first assignment. e.g., this is OK:
// Object x;
// x = null;
public class NullAssignmentRule extends AbstractJavaRule {
public NullAssignmentRule() {
addRuleChainVisit(ASTNullLiteral.class);
}
@Override
public Object visit(ASTNullLiteral node, Object data) {
@ -55,7 +60,19 @@ public class NullAssignmentRule extends AbstractJavaRule {
&& ((AccessNode) ((VariableNameDeclaration) name.getNameDeclaration()).getAccessNodeParent()).isFinal();
}
private boolean isBadTernary(ASTConditionalExpression n) {
return n.isTernary() && !(n.jjtGetChild(0) instanceof ASTEqualityExpression);
private boolean isBadTernary(ASTConditionalExpression ternary) {
boolean isInitializer = false;
ASTVariableInitializer variableInitializer = ternary.getFirstParentOfType(ASTVariableInitializer.class);
if (variableInitializer != null) {
ASTBlockStatement statement = ternary.getFirstParentOfType(ASTBlockStatement.class);
isInitializer = statement == variableInitializer.getFirstParentOfType(ASTBlockStatement.class);
}
return ternary.isTernary()
&& !(ternary.jjtGetChild(0) instanceof ASTEqualityExpression)
&& !isInitializer
&& !(ternary.getNthParent(2) instanceof ASTReturnStatement)
&& !(ternary.getNthParent(2) instanceof ASTLambdaExpression);
}
}

View File

@ -4,35 +4,49 @@
package net.sourceforge.pmd.lang.java.rule.errorprone;
import java.util.HashSet;
import java.util.Set;
import net.sourceforge.pmd.lang.java.ast.ASTCompilationUnit;
import java.util.List;
import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceDeclaration;
import net.sourceforge.pmd.lang.java.ast.ASTMethodDeclaration;
import net.sourceforge.pmd.lang.java.rule.AbstractJavaRule;
/**
* Returns Checks if the singleton rule is used properly.
*/
public class SingleMethodSingletonRule extends AbstractJavaRule {
private Set<String> methodset = new HashSet<String>();
/**
* Checks for getInstance method usage in the same class.
* @param node of ASTCLass
* @param data of Object
* @return Object
*
*/
@Override
public Object visit(ASTCompilationUnit node, Object data) {
methodset.clear();
return super.visit(node, data);
}
@Override
public Object visit(ASTMethodDeclaration node, Object data) {
if (node.getResultType().isVoid()) {
return super.visit(node, data);
}
public Object visit(ASTClassOrInterfaceDeclaration node, Object data) {
if ("getInstance".equals(node.getMethodName())) {
if (!methodset.add(node.getMethodName())) {
addViolation(data, node);
List<ASTMethodDeclaration> methods = node.findDescendantsOfType(ASTMethodDeclaration.class); // Find the name of methods in it
int count = 0;
for (ASTMethodDeclaration method : methods) {
if (method.getName().equals("getInstance")) {
count++;
if (count > 1) {
addViolation(data, node);
break;
}
}
}
return super.visit(node, data);
}
}

View File

@ -0,0 +1,132 @@
/**
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
*/
package net.sourceforge.pmd.lang.java.rule.security;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import net.sourceforge.pmd.lang.java.ast.ASTAllocationExpression;
import net.sourceforge.pmd.lang.java.ast.ASTArrayInitializer;
import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceBodyDeclaration;
import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceType;
import net.sourceforge.pmd.lang.java.ast.ASTLiteral;
import net.sourceforge.pmd.lang.java.ast.ASTLocalVariableDeclaration;
import net.sourceforge.pmd.lang.java.ast.ASTName;
import net.sourceforge.pmd.lang.java.ast.ASTPrimaryExpression;
import net.sourceforge.pmd.lang.java.ast.ASTPrimitiveType;
import net.sourceforge.pmd.lang.java.ast.ASTReferenceType;
import net.sourceforge.pmd.lang.java.ast.ASTVariableDeclarator;
import net.sourceforge.pmd.lang.java.ast.ASTVariableInitializer;
import net.sourceforge.pmd.lang.java.rule.AbstractJavaRule;
import net.sourceforge.pmd.lang.java.symboltable.VariableNameDeclaration;
import net.sourceforge.pmd.lang.symboltable.NameOccurrence;
/**
* Finds hardcoded static Initialization Vectors vectors used with cryptographic
* operations.
*
* //bad: byte[] ivBytes = new byte[] {32, 87, -14, 25, 78, -104, 98, 40};
* //bad: byte[] ivBytes = "hardcoded".getBytes(); //bad: byte[] ivBytes =
* someString.getBytes();
*
* javax.crypto.spec.IvParameterSpec must not be created from a static sources
*
* @author sergeygorbaty
* @since 6.3.0
*
*/
public class InsecureCryptoIvRule extends AbstractJavaRule {
public InsecureCryptoIvRule() {
addRuleChainVisit(ASTClassOrInterfaceBodyDeclaration.class);
}
@Override
public Object visit(ASTClassOrInterfaceBodyDeclaration node, Object data) {
Set<ASTLocalVariableDeclaration> foundLocalVars = new HashSet<>();
Set<String> passedInIvVarNames = new HashSet<>();
// find new javax.crypto.spec.IvParameterSpec(...)
List<ASTAllocationExpression> allocations = node.findDescendantsOfType(ASTAllocationExpression.class);
for (ASTAllocationExpression allocation : allocations) {
ASTClassOrInterfaceType declClassName = allocation.getFirstDescendantOfType(ASTClassOrInterfaceType.class);
if (declClassName != null) {
Class<?> foundClass = declClassName.getType();
if (foundClass != null && javax.crypto.spec.IvParameterSpec.class.isAssignableFrom(foundClass)) {
ASTPrimaryExpression init = allocation.getFirstDescendantOfType(ASTPrimaryExpression.class);
if (init != null) {
ASTName name = init.getFirstDescendantOfType(ASTName.class);
if (name != null) {
passedInIvVarNames.add(name.getImage());
}
}
}
}
}
List<ASTLocalVariableDeclaration> localVars = node.findDescendantsOfType(ASTLocalVariableDeclaration.class);
for (ASTLocalVariableDeclaration localVar : localVars) {
foundLocalVars.addAll(extractPrimitiveTypes(localVar));
}
Map<VariableNameDeclaration, List<NameOccurrence>> globalDecls = node.getScope()
.getDeclarations(VariableNameDeclaration.class);
for (VariableNameDeclaration fieldVar : globalDecls.keySet()) {
if (passedInIvVarNames.contains(fieldVar.getNode().getImage())) {
ASTVariableDeclarator var = fieldVar.getNode().getFirstParentOfType(ASTVariableDeclarator.class);
if (var != null) {
validateProperIv(data, var.getFirstDescendantOfType(ASTVariableInitializer.class));
}
}
}
for (ASTLocalVariableDeclaration foundLocalVar : foundLocalVars) {
if (passedInIvVarNames.contains(foundLocalVar.getVariableName())) {
validateProperIv(data, foundLocalVar.getFirstDescendantOfType(ASTVariableInitializer.class));
}
}
return data;
}
private Set<ASTLocalVariableDeclaration> extractPrimitiveTypes(ASTLocalVariableDeclaration localVar) {
List<ASTPrimitiveType> types = localVar.findDescendantsOfType(ASTPrimitiveType.class);
Set<ASTLocalVariableDeclaration> retVal = new HashSet<>();
extractPrimitiveTypesInner(retVal, localVar, types);
return retVal;
}
private <T> void extractPrimitiveTypesInner(Set<T> retVal, T field, List<ASTPrimitiveType> types) {
for (ASTPrimitiveType type : types) {
if (type.hasImageEqualTo("byte")) {
ASTReferenceType parent = type.getFirstParentOfType(ASTReferenceType.class);
if (parent != null) {
retVal.add(field);
}
}
}
}
private void validateProperIv(Object data, ASTVariableInitializer varInit) {
// hard coded array
ASTArrayInitializer arrayInit = varInit.getFirstDescendantOfType(ASTArrayInitializer.class);
if (arrayInit != null) {
addViolation(data, varInit);
}
// string literal
ASTLiteral literal = varInit.getFirstDescendantOfType(ASTLiteral.class);
if (literal != null && literal.isStringLiteral()) {
addViolation(data, varInit);
}
}
}

View File

@ -9,7 +9,5 @@ rulesets.filenames=\
category/java/documentation.xml,\
category/java/errorprone.xml,\
category/java/multithreading.xml,\
category/java/performance.xml
# security doesn't contain any rules yet
# category/java/security.xml
category/java/performance.xml,\
category/java/security.xml

Some files were not shown because too many files have changed in this diff Show More