Merge branch 'master' into new-properties-framework
This commit is contained in:
@@ -411,7 +411,7 @@ in a single method makes its behaviour hard to read and change.
|
||||
Cyclomatic complexity assesses the complexity of a method by counting the number of decision points in a method,
|
||||
plus one for the method entry. Decision points are places where the control flow jumps to another place in the
|
||||
program. As such, they include all control flow statements, such as `if`, `while`, `for`, and `case`. For more
|
||||
details on the calculation, see the documentation of the [Cyclo metric](/pmd_java_metrics_index.html#cyclomatic-complexity-cyclo).
|
||||
details on the calculation, see the documentation of the [Cyclo metric](pmd_java_metrics_index.html#cyclomatic-complexity-cyclo).
|
||||
|
||||
Generally, numbers ranging from 1-4 denote low complexity, 5-7 denote moderate complexity, 8-10 denote
|
||||
high complexity, and 11+ is very high complexity. By default, this rule reports methods with a complexity >= 10.
|
||||
|
||||
+38
-11
@@ -20,40 +20,65 @@ This is a {{ site.pmd.release_type }} release.
|
||||
verifies that numeric literals over a given length (4 chars by default, but configurable) are using
|
||||
underscores every 3 digits for readability. The rule only applies to Java 7+ codebases.
|
||||
|
||||
#### Modified Rules
|
||||
|
||||
* The Java rule {% rule "java/bestpractices/JUnitTestsShouldIncludeAssert" %} (`java-bestpractices`)
|
||||
now also detects [Soft Assertions](https://github.com/joel-costigliola/assertj-core).
|
||||
|
||||
### Fixed Issues
|
||||
* all
|
||||
* [#1284](https://github.com/pmd/pmd/issues/1284): \[doc] Keep record of every currently deprecated API
|
||||
|
||||
* all
|
||||
* [#1318](https://github.com/pmd/pmd/issues/1318): \[test] Kotlin DSL to ease test writing
|
||||
* [#1341](https://github.com/pmd/pmd/issues/1341): \[doc] Documentation Error with Regex Properties
|
||||
* java
|
||||
* [#1460](https://github.com/pmd/pmd/issues/1460): \[java] Intermittent PMD failure : PMD processing errors while no violations reported
|
||||
* java-codestyle
|
||||
* [#1232](https://github.com/pmd/pmd/issues/1232): \[java] Detector for large numbers not separated by _
|
||||
* [#1372](https://github.com/pmd/pmd/issues/1372): \[java] false positive for UselessQualifiedThis
|
||||
* [#1435](https://github.com/pmd/pmd/issues/1435): \[java] JUnitTestsShouldIncludeAssert: Support AssertJ soft assertions
|
||||
|
||||
### API Changes
|
||||
|
||||
* The implementation of the adapters for the XPath engines Saxon and Jaxen (package `net.sourceforge.pmd.lang.ast.xpath`)
|
||||
are now deprecated. They'll be moved to an internal package come 7.0.0. Only `Attribute` remains public API.
|
||||
|
||||
#### Properties framework
|
||||
|
||||
The properties framework is about to get a lifting, and for that reason, the following APIs are
|
||||
now deprecated until 7.0.0. The proposed changes to the API are described [on the wiki](https://github.com/pmd/pmd/wiki/Property-framework-7-0-0)
|
||||
|
||||
* Several classes and interfaces from the properties framework are now deprecated and will be removed with 7.0.0.
|
||||
* MethodProperty, FloatProperty, FileProperty, TypeProperty and their multi-valued counterparts
|
||||
* `MethodProperty`, `FloatProperty`, `FileProperty`, `TypeProperty` and their multi-valued counterparts
|
||||
are discontinued for lack of a use-case, and will probably not be replaced with 7.0.0.
|
||||
Users of FloatProperty should consider using a DoubleProperty.
|
||||
* EnumeratedPropertyDescriptor, NumericPropertyDescriptor, PackagedPropertyDescriptor, and the related builders
|
||||
(in net.sourceforge.pmd.properties.builders) will be removed. In the future, these interfaces won't be around
|
||||
Users of `FloatProperty` should consider using a `DoubleProperty`.
|
||||
* `EnumeratedPropertyDescriptor`, `NumericPropertyDescriptor`, `PackagedPropertyDescriptor`, and the related builders
|
||||
(in `net.sourceforge.pmd.properties.builders`) will be removed. In the future, these interfaces won't be around
|
||||
but their functionality will, under another form. The related methods `PropertyTypeId#isPropertyNumeric` and
|
||||
`PropertyTypeId#isPropertyPackaged` are also deprecated.
|
||||
* All classes of net.sourceforge.pmd.properties.modules are deprecated and will be removed. They were
|
||||
never intended as public api.
|
||||
* The classes PropertyDescriptorField, PropertyDescriptorBuilderConversionWrapper, and the methods
|
||||
* The classes `PropertyDescriptorField`, `PropertyDescriptorBuilderConversionWrapper`, and the methods
|
||||
`PropertyDescriptor#attributeValuesById`, `PropertyDescriptor#isDefinedExternally` and `PropertyTypeId#getFactory` are deprecated with no
|
||||
intended replacement. These were used to read and write properties to and from XML, and were never
|
||||
intended as public API.
|
||||
* The class ValueParserConstants is deprecated with no intended replacement, it was not intended as
|
||||
public API.
|
||||
* The method `PropertyDescriptor#preferredRowCount` is deprecated with no intended replacement. It was
|
||||
never implemented, and does not belong in this interface.
|
||||
* The class `ValueParserConstants` and the interface `ValueParser` are deprecated with no intended replacement,
|
||||
they were not intended as public API.
|
||||
* Methods from `PropertyDescriptor`:
|
||||
* `preferredRowCount` is deprecated with no intended replacement. It was never implemented, and does not belong
|
||||
in this interface. The methods `uiOrder` and `compareTo` are deprecated for the same reason. These methods mix presentation logic
|
||||
with business logic and are not necessary for PropertyDescriptors to work. `PropertyDescriptor` will not
|
||||
extend `Comparable<PropertyDescriptor>` anymore come 7.0.0.
|
||||
* The method `PropertyDescriptor#propertyErrorFor` is deprecated and will be removed with no intended
|
||||
replacement. It's really just a shortcut for `prop.errorFor(rule.getProperty(prop))`.
|
||||
* `T valueFrom(String)` and `String asDelimitedString(T)` are deprecated and will be removed. These were
|
||||
used to serialize and deserialize properties to/from a string, but 7.0.0 will introduce a more flexible
|
||||
XML syntax which will make them obsolete.
|
||||
* `isMultiValue` and `type` are deprecated and won't be replaced. The new XML syntax will remove the need
|
||||
for a divide between multi- and single-value properties, and will allow arbitrary types to be represented.
|
||||
Since arbitrary types may be represented, `type` will become obsolete as it can't represent generic types,
|
||||
which will nevertheless be representable with the XML syntax. It was only used for documentation, but a
|
||||
new way to document these properties exhaustively will be added with 7.0.0.
|
||||
* `errorFor` is deprecated as its return type will be changed to `Optional<String>` with the shift to Java 8.
|
||||
|
||||
### External Contributions
|
||||
|
||||
@@ -61,6 +86,8 @@ This is a {{ site.pmd.release_type }} release.
|
||||
* [#1424](https://github.com/pmd/pmd/pull/1424): \[doc] #1341 Updating Regex Values in default Value Property - [avishvat](https://github.com/vishva007)
|
||||
* [#1428](https://github.com/pmd/pmd/pull/1428): \[core] Upgrading JCommander from 1.48 to 1.72 - [Thunderforge](https://github.com/Thunderforge)
|
||||
* [#1430](https://github.com/pmd/pmd/pull/1430): \[doc] Who really knows regex? - [Dem Pilafian](https://github.com/dpilafian)
|
||||
* [#1434](https://github.com/pmd/pmd/pull/1434): \[java] JUnitTestsShouldIncludeAssert: Recognize AssertJ soft assertions as valid assert statements - [Loïc Ledoyen](https://github.com/ledoyen)
|
||||
* [#1464](https://github.com/pmd/pmd/pull/1464): \[doc] Fix XSS on documentation web page - [Maxime Robert](https://github.com/marob)
|
||||
|
||||
{% endtocmaker %}
|
||||
|
||||
|
||||
@@ -16,12 +16,6 @@ import net.sourceforge.pmd.annotation.InternalApi;
|
||||
* any associated GUIs. While concrete descriptor instances are static and immutable they provide validation,
|
||||
* serialization, and default values for any specific datatypes.
|
||||
*
|
||||
* <p>This interface is primarily specialized according to whether the property is multi-valued or single-valued, see
|
||||
* {@link SingleValuePropertyDescriptor} and {@link MultiValuePropertyDescriptor}.
|
||||
*
|
||||
* <p>Several interfaces further specialize the behaviour of descriptors to accommodate specific types of descriptors,
|
||||
* see {@link NumericPropertyDescriptor} and {@link EnumeratedPropertyDescriptor}.
|
||||
*
|
||||
* <h1>Upcoming API changes to the properties framework: see https://github.com/pmd/pmd/issues/1415</h1>
|
||||
*
|
||||
* @param <T> type of the property's value. This is a list type for multi-valued properties.
|
||||
@@ -48,31 +42,6 @@ public interface PropertyDescriptor<T> extends Comparable<PropertyDescriptor<?>>
|
||||
String description();
|
||||
|
||||
|
||||
/**
|
||||
* Denotes the value datatype. For multi value properties, this is not the List class but the list's component
|
||||
* class.
|
||||
*
|
||||
* @return Class literal of the value type
|
||||
*/
|
||||
// TODO Type is used only to document the expected value format, but generic arguments are erased.
|
||||
// This will become a problem when we remove the divide between multi-/single-value properties and
|
||||
// let users make properties out of any type they want.
|
||||
// We'll probably have to remove this method and find another solution to document the expected format.
|
||||
Class<?> type();
|
||||
|
||||
|
||||
/**
|
||||
* Returns whether the property is multi-valued, i.e. an array of strings,
|
||||
*
|
||||
* <p>As unary property rule properties will return a value of one, you must use the get/setProperty accessors when
|
||||
* working with the actual values. When working with multi-value properties then the get/setProperties accessors
|
||||
* must be used.</p>
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
boolean isMultiValue();
|
||||
|
||||
|
||||
/**
|
||||
* Default value to use when the user hasn't specified one or when they wish to revert to a known-good state.
|
||||
*
|
||||
@@ -88,8 +57,39 @@ public interface PropertyDescriptor<T> extends Comparable<PropertyDescriptor<?>>
|
||||
* @param value The value to check.
|
||||
*
|
||||
* @return A diagnostic message.
|
||||
*
|
||||
* @deprecated PMD 7.0.0 will change the return type to {@code Optional<String>}
|
||||
*/
|
||||
String errorFor(T value);
|
||||
@Deprecated
|
||||
String errorFor(T value); // TODO Java 1.8 make optional
|
||||
|
||||
|
||||
/**
|
||||
* Denotes the value datatype. For multi value properties, this is not the List class but the list's component
|
||||
* class.
|
||||
*
|
||||
* @return Class literal of the value type
|
||||
*
|
||||
* @deprecated This method is mainly used for documentation, but will not prove general enough
|
||||
* to support PMD 7.0.0's improved property types.
|
||||
*/
|
||||
@Deprecated
|
||||
Class<?> type();
|
||||
|
||||
|
||||
/**
|
||||
* Returns whether the property is multi-valued, i.e. an array of strings,
|
||||
*
|
||||
* <p>As unary property rule properties will return a value of one, you must use the get/setProperty accessors when
|
||||
* working with the actual values. When working with multi-value properties then the get/setProperties accessors
|
||||
* must be used.</p>
|
||||
*
|
||||
* @return boolean
|
||||
*
|
||||
* @deprecated The hard divide between multi- and single-value properties will be removed with 7.0.0
|
||||
*/
|
||||
@Deprecated
|
||||
boolean isMultiValue();
|
||||
|
||||
|
||||
/**
|
||||
@@ -97,24 +97,34 @@ public interface PropertyDescriptor<T> extends Comparable<PropertyDescriptor<?>>
|
||||
* edit property values. If the value returned has a non-zero fractional part then this is can be used to place
|
||||
* adjacent fields on the same row.
|
||||
*
|
||||
* <p>Example:<br> name -> 0.0 description 1.0 minValue -> 2.0 maxValue -> 2.1 </p> ..would have their
|
||||
* fields placed like:<br>
|
||||
* @return The relative order compared to other properties of the same rule
|
||||
*
|
||||
* <code>name: [ ] description: [ ] minimum: [ ] maximum: [ ]</code>
|
||||
*
|
||||
* @return float
|
||||
* @deprecated This method confuses the presentation layer and the business logic. The order of the
|
||||
* property in a UI is irrelevant to the functioning of the property in PMD. With PMD 7.0.0, this
|
||||
* method will be removed. UI and documentation tools will decide on their own convention.
|
||||
*/
|
||||
@Deprecated
|
||||
float uiOrder();
|
||||
|
||||
|
||||
/**
|
||||
* @deprecated Comparing property descriptors is not useful within PMD
|
||||
*/
|
||||
@Deprecated
|
||||
@Override
|
||||
int compareTo(PropertyDescriptor<?> o);
|
||||
|
||||
|
||||
/**
|
||||
* Returns the value represented by this string.
|
||||
*
|
||||
* @param propertyString The string to parse
|
||||
*
|
||||
* @return The value represented by the string
|
||||
* @throws IllegalArgumentException if the given string cannot be parsed
|
||||
* @deprecated PMD 7.0.0 will use a more powerful scheme to represent values than
|
||||
* simple strings, this method won't be general enough
|
||||
*/
|
||||
@Deprecated
|
||||
T valueFrom(String propertyString) throws IllegalArgumentException;
|
||||
|
||||
|
||||
@@ -124,7 +134,11 @@ public interface PropertyDescriptor<T> extends Comparable<PropertyDescriptor<?>>
|
||||
* @param value Object
|
||||
*
|
||||
* @return String
|
||||
*
|
||||
* @deprecated PMD 7.0.0 will use a more powerful scheme to represent values than
|
||||
* simple strings, this method won't be general enough
|
||||
*/
|
||||
@Deprecated
|
||||
String asDelimitedString(T value);
|
||||
|
||||
|
||||
@@ -134,8 +148,10 @@ public interface PropertyDescriptor<T> extends Comparable<PropertyDescriptor<?>>
|
||||
*
|
||||
* @param rule Rule
|
||||
*
|
||||
* @return String
|
||||
* @deprecated Used nowhere, and fails if the rule doesn't define the property descriptor
|
||||
* A better solution will be added on property source
|
||||
*/
|
||||
@Deprecated
|
||||
String propertyErrorFor(Rule rule);
|
||||
|
||||
|
||||
|
||||
@@ -4,12 +4,17 @@
|
||||
|
||||
package net.sourceforge.pmd.properties;
|
||||
|
||||
import net.sourceforge.pmd.annotation.InternalApi;
|
||||
|
||||
|
||||
/**
|
||||
* Parses a value from a string.
|
||||
*
|
||||
* @param <U> The type of the value to parse
|
||||
*/
|
||||
// FUTURE @FunctionalInterface
|
||||
@Deprecated
|
||||
@InternalApi
|
||||
public interface ValueParser<U> {
|
||||
|
||||
/**
|
||||
|
||||
+2
@@ -63,8 +63,10 @@ public abstract class PropertyDescriptorBuilder<E, T extends PropertyDescriptorB
|
||||
* @param f The UI order
|
||||
*
|
||||
* @return The same builder
|
||||
* @deprecated See {@link PropertyDescriptor#uiOrder()}
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
@Deprecated
|
||||
public T uiOrder(float f) {
|
||||
this.uiOrder = f;
|
||||
return (T) this;
|
||||
|
||||
@@ -176,5 +176,10 @@
|
||||
<artifactId>ant-testutil</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.assertj</groupId>
|
||||
<artifactId>assertj-core</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
|
||||
+46
-6
@@ -20,6 +20,7 @@ import net.sourceforge.pmd.lang.java.ast.ASTPrimaryExpression;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTReferenceType;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTStatementExpression;
|
||||
import net.sourceforge.pmd.lang.java.rule.AbstractJUnitRule;
|
||||
import net.sourceforge.pmd.lang.java.symboltable.VariableNameDeclaration;
|
||||
import net.sourceforge.pmd.lang.java.typeresolution.TypeHelper;
|
||||
import net.sourceforge.pmd.lang.symboltable.NameDeclaration;
|
||||
import net.sourceforge.pmd.lang.symboltable.NameOccurrence;
|
||||
@@ -39,10 +40,12 @@ public class JUnitTestsShouldIncludeAssertRule extends AbstractJUnitRule {
|
||||
public Object visit(ASTMethodDeclaration method, Object data) {
|
||||
if (isJUnitMethod(method, data)) {
|
||||
if (!isExpectAnnotated(method.jjtGetParent())) {
|
||||
Map<String, VariableNameDeclaration> variables = getVariables(method);
|
||||
|
||||
Scope classScope = method.getScope().getParent();
|
||||
Map<String, List<NameOccurrence>> expectables = getRuleAnnotatedExpectedExceptions(classScope);
|
||||
|
||||
if (!containsExpectOrAssert(method.getBlock(), expectables)) {
|
||||
|
||||
if (!containsExpectOrAssert(method.getBlock(), expectables, variables)) {
|
||||
addViolation(data, method);
|
||||
}
|
||||
}
|
||||
@@ -50,24 +53,35 @@ public class JUnitTestsShouldIncludeAssertRule extends AbstractJUnitRule {
|
||||
return data;
|
||||
}
|
||||
|
||||
private boolean containsExpectOrAssert(Node n, Map<String, List<NameOccurrence>> expectables) {
|
||||
private boolean containsExpectOrAssert(Node n,
|
||||
Map<String, List<NameOccurrence>> expectables,
|
||||
Map<String, VariableNameDeclaration> variables) {
|
||||
if (n instanceof ASTStatementExpression) {
|
||||
if (isExpectStatement((ASTStatementExpression) n, expectables)
|
||||
|| isAssertOrFailStatement((ASTStatementExpression) n)
|
||||
|| isVerifyStatement((ASTStatementExpression) n)) {
|
||||
|| isVerifyStatement((ASTStatementExpression) n)
|
||||
|| isSoftAssertionStatement((ASTStatementExpression) n, variables)) {
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
for (int i = 0; i < n.jjtGetNumChildren(); i++) {
|
||||
Node c = n.jjtGetChild(i);
|
||||
if (containsExpectOrAssert(c, expectables)) {
|
||||
if (containsExpectOrAssert(c, expectables, variables)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
private Map<String, VariableNameDeclaration> getVariables(ASTMethodDeclaration method) {
|
||||
Map<String, VariableNameDeclaration> variables = new HashMap<>();
|
||||
for (VariableNameDeclaration vnd : method.getScope().getDeclarations(VariableNameDeclaration.class).keySet()) {
|
||||
variables.put(vnd.getName(), vnd);
|
||||
}
|
||||
return variables;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a list of NameDeclarations for all the fields that have type
|
||||
* ExpectedException and have a Rule annotation.
|
||||
@@ -189,4 +203,30 @@ public class JUnitTestsShouldIncludeAssertRule extends AbstractJUnitRule {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean isSoftAssertionStatement(ASTStatementExpression expression,
|
||||
Map<String, VariableNameDeclaration> variables) {
|
||||
if (expression != null) {
|
||||
ASTPrimaryExpression pe = expression.getFirstChildOfType(ASTPrimaryExpression.class);
|
||||
if (pe != null) {
|
||||
Node name = pe.getFirstDescendantOfType(ASTName.class);
|
||||
if (name != null) {
|
||||
String img = name.getImage();
|
||||
if (img.indexOf(".") == -1) {
|
||||
return false;
|
||||
}
|
||||
String[] tokens = img.split("\\.");
|
||||
String methodName = tokens[1];
|
||||
boolean methodIsAssertAll = "assertAll".equals(methodName);
|
||||
|
||||
String varName = tokens[0];
|
||||
boolean variableTypeIsSoftAssertion = variables.containsKey(varName)
|
||||
&& TypeHelper.isA(variables.get(varName), "org.assertj.core.api.AbstractSoftAssertions");
|
||||
|
||||
return methodIsAssertAll && variableTypeIsSoftAssertion;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
+3
-1
@@ -118,7 +118,9 @@ public class VariableNameDeclaration extends AbstractNameDeclaration implements
|
||||
if (typeNode != null) {
|
||||
return typeNode.getType();
|
||||
}
|
||||
return null;
|
||||
// if there is no type node, then return the type of the declarator id.
|
||||
// this might be a inferred type
|
||||
return getDeclaratorId().getType();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+33
-16
@@ -54,23 +54,29 @@ public final class TypeHelper {
|
||||
|
||||
private static Class<?> loadClassWithNodeClassloader(final TypeNode n, final String clazzName) {
|
||||
if (n.getType() != null) {
|
||||
try {
|
||||
ClassLoader classLoader = n.getType().getClassLoader();
|
||||
if (classLoader == null) {
|
||||
// Using the system classloader then
|
||||
classLoader = ClassLoader.getSystemClassLoader();
|
||||
}
|
||||
|
||||
// If the requested type is in the classpath, using the same classloader should work
|
||||
return ClassUtils.getClass(classLoader, clazzName);
|
||||
} catch (final ClassNotFoundException ignored) {
|
||||
// The requested type is not on the auxclasspath. This might happen, if the type node
|
||||
// is probed for a specific type (e.g. is is a JUnit5 Test Annotation class).
|
||||
// Failing to resolve clazzName does not necessarily indicate an incomplete auxclasspath.
|
||||
} catch (final LinkageError expected) {
|
||||
// We found the class but it's invalid / incomplete. This may be an incomplete auxclasspath
|
||||
// if it was a NoClassDefFoundError. TODO : Report it?
|
||||
return loadClass(n.getType().getClassLoader(), clazzName);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private static Class<?> loadClass(final ClassLoader nullableClassLoader, final String clazzName) {
|
||||
try {
|
||||
ClassLoader classLoader = nullableClassLoader;
|
||||
if (classLoader == null) {
|
||||
// Using the system classloader then
|
||||
classLoader = ClassLoader.getSystemClassLoader();
|
||||
}
|
||||
|
||||
// If the requested type is in the classpath, using the same classloader should work
|
||||
return ClassUtils.getClass(classLoader, clazzName);
|
||||
} catch (ClassNotFoundException ignored) {
|
||||
// The requested type is not on the auxclasspath. This might happen, if the type node
|
||||
// is probed for a specific type (e.g. is is a JUnit5 Test Annotation class).
|
||||
// Failing to resolve clazzName does not necessarily indicate an incomplete auxclasspath.
|
||||
} catch (final LinkageError expected) {
|
||||
// We found the class but it's invalid / incomplete. This may be an incomplete auxclasspath
|
||||
// if it was a NoClassDefFoundError. TODO : Report it?
|
||||
}
|
||||
|
||||
return null;
|
||||
@@ -133,4 +139,15 @@ public final class TypeHelper {
|
||||
|
||||
return clazz.isAssignableFrom(type);
|
||||
}
|
||||
|
||||
public static boolean isA(TypedNameDeclaration vnd, String className) {
|
||||
Class<?> type = vnd.getType();
|
||||
if (type != null) {
|
||||
Class<?> clazz = loadClass(type.getClassLoader(), className);
|
||||
if (clazz != null) {
|
||||
return clazz.isAssignableFrom(type);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
+2
-2
@@ -7,17 +7,17 @@ package net.sourceforge.pmd.lang.java.typeresolution.typedefinition;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Type;
|
||||
import java.lang.reflect.TypeVariable;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import org.apache.commons.lang3.ArrayUtils;
|
||||
|
||||
|
||||
public abstract class JavaTypeDefinition implements TypeDefinition {
|
||||
// contains non-generic and raw EXACT types
|
||||
private static final Map<Class<?>, JavaTypeDefinition> CLASS_EXACT_TYPE_DEF_CACHE = new HashMap<>();
|
||||
private static final Map<Class<?>, JavaTypeDefinition> CLASS_EXACT_TYPE_DEF_CACHE = new ConcurrentHashMap<>();
|
||||
|
||||
private final TypeDefinitionType definitionType;
|
||||
|
||||
|
||||
@@ -410,7 +410,7 @@ in a single method makes its behaviour hard to read and change.
|
||||
Cyclomatic complexity assesses the complexity of a method by counting the number of decision points in a method,
|
||||
plus one for the method entry. Decision points are places where the control flow jumps to another place in the
|
||||
program. As such, they include all control flow statements, such as `if`, `while`, `for`, and `case`. For more
|
||||
details on the calculation, see the documentation of the [Cyclo metric](/pmd_java_metrics_index.html#cyclomatic-complexity-cyclo).
|
||||
details on the calculation, see the documentation of the [Cyclo metric](pmd_java_metrics_index.html#cyclomatic-complexity-cyclo).
|
||||
|
||||
Generally, numbers ranging from 1-4 denote low complexity, 5-7 denote moderate complexity, 8-10 denote
|
||||
high complexity, and 11+ is very high complexity. By default, this rule reports methods with a complexity >= 10.
|
||||
|
||||
@@ -20,7 +20,6 @@ import net.sourceforge.pmd.lang.java.ast.ASTCompilationUnit;
|
||||
public abstract class STBBaseTst {
|
||||
|
||||
protected ASTCompilationUnit acu;
|
||||
protected SymbolFacade stb;
|
||||
|
||||
protected void parseCode(final String code) {
|
||||
parseCode(code, LanguageRegistry.getLanguage(JavaLanguageModule.NAME).getDefaultVersion());
|
||||
@@ -34,8 +33,9 @@ public abstract class STBBaseTst {
|
||||
final LanguageVersionHandler languageVersionHandler = languageVersion.getLanguageVersionHandler();
|
||||
acu = (ASTCompilationUnit) languageVersionHandler.getParser(languageVersionHandler.getDefaultParserOptions())
|
||||
.parse(null, new StringReader(code));
|
||||
stb = new SymbolFacade();
|
||||
stb.initializeWith(acu);
|
||||
languageVersionHandler.getQualifiedNameResolutionFacade(STBBaseTst.class.getClassLoader()).start(acu);
|
||||
languageVersionHandler.getSymbolFacade(STBBaseTst.class.getClassLoader()).start(acu);
|
||||
languageVersionHandler.getTypeResolutionFacade(STBBaseTst.class.getClassLoader()).start(acu);
|
||||
}
|
||||
|
||||
// Note: If you're using Eclipse or some other IDE to run this test, you
|
||||
|
||||
+71
@@ -8,6 +8,8 @@ import static net.sourceforge.pmd.lang.java.ParserTstUtil.getNodes;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
import org.junit.Test;
|
||||
@@ -85,6 +87,61 @@ public class VariableNameDeclarationTest extends STBBaseTst {
|
||||
assertEquals("String", ((TypedNameDeclaration) decl).getTypeImage());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testVarKeywordTypeImage() {
|
||||
parseCode(TEST6);
|
||||
NameDeclaration decl = acu.findDescendantsOfType(ASTVariableDeclaratorId.class).get(0).getScope()
|
||||
.getDeclarations().keySet().iterator().next();
|
||||
assertEquals("java.util.ArrayList", ((TypedNameDeclaration) decl).getType().getName());
|
||||
// since the type is inferred, there is no type image
|
||||
assertEquals(null, ((TypedNameDeclaration) decl).getTypeImage());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testVarKeywordWithPrimitiveTypeImage() {
|
||||
parseCode(TEST7);
|
||||
NameDeclaration decl = acu.findDescendantsOfType(ASTVariableDeclaratorId.class).get(0).getScope()
|
||||
.getDeclarations().keySet().iterator().next();
|
||||
assertEquals("long", ((TypedNameDeclaration) decl).getType().getName());
|
||||
// since the type is inferred, there is no type image
|
||||
assertEquals(null, ((TypedNameDeclaration) decl).getTypeImage());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testVarKeywordWithIndirectReference() {
|
||||
parseCode(TEST8);
|
||||
Iterator<NameDeclaration> nameDeclarationIterator = acu.findDescendantsOfType(ASTVariableDeclaratorId.class).get(0).getScope()
|
||||
.getDeclarations().keySet().iterator();
|
||||
nameDeclarationIterator.next(); // first variable 'bar'
|
||||
NameDeclaration decl = nameDeclarationIterator.next(); // second variable 'foo'
|
||||
assertEquals("java.lang.String", ((TypedNameDeclaration) decl).getType().getName());
|
||||
// since the type is inferred, there is no type image
|
||||
assertEquals(null, ((TypedNameDeclaration) decl).getTypeImage());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLamdaParameterTypeImage() {
|
||||
parseCode(TEST9);
|
||||
List<ASTVariableDeclaratorId> variableDeclaratorIds = acu.findDescendantsOfType(
|
||||
ASTVariableDeclaratorId.class,
|
||||
true
|
||||
);
|
||||
|
||||
List<VariableNameDeclaration> nameDeclarations = new ArrayList<>();
|
||||
for (ASTVariableDeclaratorId variableDeclaratorId : variableDeclaratorIds) {
|
||||
nameDeclarations.add(variableDeclaratorId.getNameDeclaration());
|
||||
}
|
||||
|
||||
assertEquals("Map", nameDeclarations.get(0).getTypeImage()); // variable 'bar'
|
||||
assertEquals(null, nameDeclarations.get(1).getTypeImage()); // variable 'key'
|
||||
assertEquals(null, nameDeclarations.get(2).getTypeImage()); // variable 'value'
|
||||
|
||||
// variable 'foo'
|
||||
assertEquals("foo", nameDeclarations.get(3).getName());
|
||||
assertEquals("long", nameDeclarations.get(3).getType().getName());
|
||||
// since the type is inferred, there is no type image
|
||||
assertEquals(null, nameDeclarations.get(3).getTypeImage());
|
||||
}
|
||||
|
||||
private static final String EXCEPTION_PARAMETER = "public class Test { { try {} catch(Exception ie) {} } }";
|
||||
|
||||
@@ -101,6 +158,20 @@ public class VariableNameDeclarationTest extends STBBaseTst {
|
||||
+ PMD.EOL + " }" + PMD.EOL + "}";
|
||||
public static final String TEST5 = "public class Foo {" + PMD.EOL + " void foo(String x) {}" + PMD.EOL + "}";
|
||||
|
||||
public static final String TEST6 = "import java.util.ArrayList; public class Foo {" + PMD.EOL + " void foo() {" + PMD.EOL
|
||||
+ " var bar = new ArrayList<String>(\"param\");" + PMD.EOL + " }" + PMD.EOL + "}";
|
||||
|
||||
public static final String TEST7 = "public class Foo {" + PMD.EOL + " void foo() {" + PMD.EOL + " var bar = 42L;"
|
||||
+ PMD.EOL + " }" + PMD.EOL + "}";
|
||||
|
||||
public static final String TEST8 = "public class Foo {" + PMD.EOL + " void foo() {" + PMD.EOL
|
||||
+ " var bar = \"test\";" + PMD.EOL + " var foo = bar;" + PMD.EOL + " }" + PMD.EOL + "}";
|
||||
|
||||
public static final String TEST9 = "public class Foo {" + PMD.EOL + " void foo() {" + PMD.EOL
|
||||
+ " Map<String, Object> bar = new HashMap<>();" + PMD.EOL + " bar.forEach((key, value) -> {" + PMD.EOL
|
||||
+ " if (value instanceof String) {" + PMD.EOL + " var foo = 42L;" + PMD.EOL
|
||||
+ " System.out.println(value);" + PMD.EOL + " }" + PMD.EOL + " });" + PMD.EOL + " }" + PMD.EOL + "}";
|
||||
|
||||
public static junit.framework.Test suite() {
|
||||
return new junit.framework.JUnit4TestAdapter(VariableNameDeclarationTest.class);
|
||||
}
|
||||
|
||||
+65
@@ -429,6 +429,71 @@ class Style {
|
||||
public void moveOutOfBoundsFrom() {
|
||||
doSomething();
|
||||
}
|
||||
}]]></code>
|
||||
</test-code>
|
||||
<test-code>
|
||||
<description>#1435 Treat AssertJ soft assertions as assert expressions</description>
|
||||
<expected-problems>0</expected-problems>
|
||||
<code><![CDATA[
|
||||
import org.assertj.core.api.SoftAssertions;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
class FooTest {
|
||||
|
||||
@Test
|
||||
void testFoo() {
|
||||
var softly = new SoftAssertions();
|
||||
softly.assertThat("doesn't matter").isEqualTo("doesn't matter");
|
||||
softly.assertAll();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testBar() {
|
||||
SoftAssertions softly = new SoftAssertions();
|
||||
softly.assertThat("doesn't matter").isEqualTo("doesn't matter");
|
||||
softly.assertAll();
|
||||
}
|
||||
}]]></code>
|
||||
</test-code>
|
||||
<test-code>
|
||||
<description>#1435 Treat AssertJ soft assertions as assert expressions - missing assertAll</description>
|
||||
<expected-problems>2</expected-problems>
|
||||
<expected-linenumbers>7,13</expected-linenumbers>
|
||||
<code><![CDATA[
|
||||
import org.assertj.core.api.SoftAssertions;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
class FooTest {
|
||||
|
||||
@Test
|
||||
void testFoo() {
|
||||
var softly = new SoftAssertions();
|
||||
softly.assertThat("doesn't matter").isEqualTo("doesn't matter");
|
||||
}
|
||||
|
||||
@Test
|
||||
void testBar() {
|
||||
SoftAssertions softly = new SoftAssertions();
|
||||
softly.assertThat("doesn't matter").isEqualTo("doesn't matter");
|
||||
}
|
||||
}]]></code>
|
||||
</test-code>
|
||||
<test-code>
|
||||
<description>#1435 Treat AssertJ soft assertion rule for JUnit 4 as assert expressions</description>
|
||||
<expected-problems>0</expected-problems>
|
||||
<code><![CDATA[
|
||||
import org.assertj.core.api.JUnitSoftAssertions;
|
||||
import org.junit.Test;
|
||||
|
||||
public class FooTest {
|
||||
|
||||
@Rule
|
||||
public final JUnitSoftAssertions softly = new JUnitSoftAssertions();
|
||||
|
||||
@Test
|
||||
void testFoo() {
|
||||
softly.assertThat("doesn't matter").isEqualTo("doesn't matter");
|
||||
}
|
||||
}]]></code>
|
||||
</test-code>
|
||||
</test-data>
|
||||
|
||||
@@ -936,6 +936,11 @@ Additionally it includes CPD, the copy-paste-detector. CPD finds duplicated code
|
||||
<artifactId>system-rules</artifactId>
|
||||
<version>1.8.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.assertj</groupId>
|
||||
<artifactId>assertj-core</artifactId>
|
||||
<version>3.11.0</version>
|
||||
</dependency>
|
||||
|
||||
<!-- TEST DEPENDENCIES -->
|
||||
|
||||
|
||||
Reference in New Issue
Block a user