[java] Deprecate the old typeof function
- Have new functions typeIs() and typeIsExactly() with simpler syntaxes - Nag about the deprecated usage of the old method - Replace all internal usages with the new one - Have the functions use the TypeHelper to avoid multiple separate implementations of the same behavior - Tidy up a little the TypeHelper
This commit is contained in:
@@ -27,6 +27,8 @@ import net.sourceforge.pmd.lang.java.typeresolution.TypeResolutionFacade;
|
||||
import net.sourceforge.pmd.lang.java.xpath.GetCommentOnFunction;
|
||||
import net.sourceforge.pmd.lang.java.xpath.JavaFunctions;
|
||||
import net.sourceforge.pmd.lang.java.xpath.MetricFunction;
|
||||
import net.sourceforge.pmd.lang.java.xpath.TypeIsExactlyFunction;
|
||||
import net.sourceforge.pmd.lang.java.xpath.TypeIsFunction;
|
||||
import net.sourceforge.pmd.lang.java.xpath.TypeOfFunction;
|
||||
import net.sourceforge.pmd.lang.rule.RuleViolationFactory;
|
||||
|
||||
@@ -53,6 +55,8 @@ public abstract class AbstractJavaHandler extends AbstractLanguageVersionHandler
|
||||
TypeOfFunction.registerSelfInSimpleContext();
|
||||
GetCommentOnFunction.registerSelfInSimpleContext();
|
||||
MetricFunction.registerSelfInSimpleContext();
|
||||
TypeIsFunction.registerSelfInSimpleContext();
|
||||
TypeIsExactlyFunction.registerSelfInSimpleContext();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+1
-1
@@ -63,7 +63,7 @@ public class ForLoopCanBeForeachRule extends AbstractJavaRule {
|
||||
List<NameOccurrence> occurrences = indexDecl.getValue();
|
||||
VariableNameDeclaration index = indexDecl.getKey();
|
||||
|
||||
if (TypeHelper.isA(index, Iterator.class)) {
|
||||
if (TypeHelper.isExactlyAny(index, Iterator.class)) {
|
||||
Entry<VariableNameDeclaration, List<NameOccurrence>> iterableInfo = getIterableDeclOfIteratorLoop(index, node.getScope());
|
||||
|
||||
if (iterableInfo != null && isReplaceableIteratorLoop(indexDecl, guardCondition, iterableInfo, node)) {
|
||||
|
||||
+1
-1
@@ -50,7 +50,7 @@ public class StringInstantiationRule extends AbstractJavaRule {
|
||||
return data;
|
||||
}
|
||||
|
||||
if (nd instanceof TypedNameDeclaration && TypeHelper.isA((TypedNameDeclaration) nd, String.class)) {
|
||||
if (nd instanceof TypedNameDeclaration && TypeHelper.isExactlyAny((TypedNameDeclaration) nd, String.class)) {
|
||||
addViolation(data, node);
|
||||
}
|
||||
return data;
|
||||
|
||||
+2
-2
@@ -17,8 +17,8 @@ import net.sourceforge.pmd.lang.symboltable.ScopedNode;
|
||||
public class StringToStringRule extends AbstractJavaRule {
|
||||
|
||||
public Object visit(ASTVariableDeclaratorId node, Object data) {
|
||||
if (!TypeHelper.isA(node.getNameDeclaration(), String.class)
|
||||
&& !TypeHelper.isA(node.getNameDeclaration(), String[].class)) {
|
||||
if (!TypeHelper.isExactlyAny(node.getNameDeclaration(), String.class)
|
||||
&& !TypeHelper.isExactlyAny(node.getNameDeclaration(), String[].class)) {
|
||||
return data;
|
||||
}
|
||||
boolean isArray = node.isArray();
|
||||
|
||||
+65
-12
@@ -24,6 +24,34 @@ public final class TypeHelper {
|
||||
* @return <code>true</code> if type node n is of type clazzName or a subtype of clazzName
|
||||
*/
|
||||
public static boolean isA(final TypeNode n, final String clazzName) {
|
||||
final Class<?> clazz = loadClassWithNodeClassloader(n, clazzName);
|
||||
|
||||
if (clazz != null) {
|
||||
return isA(n, clazz);
|
||||
}
|
||||
|
||||
return clazzName.equals(n.getImage()) || clazzName.endsWith("." + n.getImage());
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the resolved type of the given {@link TypeNode} n is exactly of the type
|
||||
* given by the clazzName.
|
||||
*
|
||||
* @param n the type node to check
|
||||
* @param clazzName the class name to compare to
|
||||
* @return <code>true</code> if type node n is exactly of type clazzName.
|
||||
*/
|
||||
public static boolean isExactlyA(final TypeNode n, final String clazzName) {
|
||||
final Class<?> clazz = loadClassWithNodeClassloader(n, clazzName);
|
||||
|
||||
if (clazz != null) {
|
||||
return n.getType() == clazz;
|
||||
}
|
||||
|
||||
return clazzName.equals(n.getImage()) || clazzName.endsWith("." + n.getImage());
|
||||
}
|
||||
|
||||
private static Class<?> loadClassWithNodeClassloader(final TypeNode n, final String clazzName) {
|
||||
if (n.getType() != null) {
|
||||
try {
|
||||
ClassLoader classLoader = n.getType().getClassLoader();
|
||||
@@ -31,21 +59,20 @@ public final class TypeHelper {
|
||||
// Using the system classloader then
|
||||
classLoader = ClassLoader.getSystemClassLoader();
|
||||
}
|
||||
|
||||
|
||||
// If the requested type is in the classpath, using the same classloader should work
|
||||
final Class<?> clazz = classLoader.loadClass(clazzName);
|
||||
|
||||
if (clazz != null) {
|
||||
return isA(n, clazz);
|
||||
}
|
||||
return classLoader.loadClass(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 clazzName.equals(n.getImage()) || clazzName.endsWith("." + n.getImage());
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public static boolean isA(TypeNode n, Class<?> clazz) {
|
||||
@@ -56,16 +83,42 @@ public final class TypeHelper {
|
||||
return subclasses(n, class1) || subclasses(n, class2);
|
||||
}
|
||||
|
||||
public static boolean isA(TypedNameDeclaration vnd, Class<?> clazz) {
|
||||
public static boolean isExactlyAny(TypedNameDeclaration vnd, Class<?>... clazzes) {
|
||||
Class<?> type = vnd.getType();
|
||||
return type != null && type.equals(clazz) || type == null
|
||||
&& (clazz.getSimpleName().equals(vnd.getTypeImage()) || clazz.getName().equals(vnd.getTypeImage()));
|
||||
for (final Class<?> clazz : clazzes) {
|
||||
if (type != null && type.equals(clazz) || type == null
|
||||
&& (clazz.getSimpleName().equals(vnd.getTypeImage()) || clazz.getName().equals(vnd.getTypeImage()))) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static boolean isExactlyNone(TypedNameDeclaration vnd, Class<?>... clazzes) {
|
||||
return !isExactlyAny(vnd, clazzes);
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated use {@link #isExactlyAny(TypedNameDeclaration, Class...)}
|
||||
*/
|
||||
@Deprecated
|
||||
public static boolean isA(TypedNameDeclaration vnd, Class<?> clazz) {
|
||||
return isExactlyAny(vnd, clazz);
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated use {@link #isExactlyAny(TypedNameDeclaration, Class...)}
|
||||
*/
|
||||
@Deprecated
|
||||
public static boolean isEither(TypedNameDeclaration vnd, Class<?> class1, Class<?> class2) {
|
||||
return isA(vnd, class1) || isA(vnd, class2);
|
||||
return isExactlyAny(vnd, class1, class2);
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated use {@link #isExactlyNone(TypedNameDeclaration, Class...)}
|
||||
*/
|
||||
@Deprecated
|
||||
public static boolean isNeither(TypedNameDeclaration vnd, Class<?> class1, Class<?> class2) {
|
||||
return !isA(vnd, class1) && !isA(vnd, class2);
|
||||
}
|
||||
|
||||
@@ -18,16 +18,27 @@ public final class JavaFunctions {
|
||||
// utility class
|
||||
}
|
||||
|
||||
public static boolean typeof(XPathContext context, String nodeTypeName, String fullTypeName) {
|
||||
@Deprecated
|
||||
public static boolean typeof(final XPathContext context, final String nodeTypeName, final String fullTypeName) {
|
||||
return typeof(context, nodeTypeName, fullTypeName, null);
|
||||
}
|
||||
|
||||
public static boolean typeof(XPathContext context, String nodeTypeName, String fullTypeName, String shortTypeName) {
|
||||
@Deprecated
|
||||
public static boolean typeof(final XPathContext context, final String nodeTypeName,
|
||||
final String fullTypeName, final String shortTypeName) {
|
||||
return TypeOfFunction.typeof((Node) ((ElementNode) context.getContextItem()).getUnderlyingNode(), nodeTypeName,
|
||||
fullTypeName, shortTypeName);
|
||||
}
|
||||
|
||||
public static double metric(XPathContext context, String metricKeyName) {
|
||||
public static double metric(final XPathContext context, final String metricKeyName) {
|
||||
return MetricFunction.getMetric((Node) ((ElementNode) context.getContextItem()).getUnderlyingNode(), metricKeyName);
|
||||
}
|
||||
|
||||
public static boolean typeIs(final XPathContext context, final String fullTypeName) {
|
||||
return TypeIsFunction.typeIs((Node) ((ElementNode) context.getContextItem()).getUnderlyingNode(), fullTypeName);
|
||||
}
|
||||
|
||||
public static boolean typeIsExactly(final XPathContext context, final String fullTypeName) {
|
||||
return TypeIsExactlyFunction.typeIsExactly((Node) ((ElementNode) context.getContextItem()).getUnderlyingNode(), fullTypeName);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
/**
|
||||
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
|
||||
*/
|
||||
|
||||
package net.sourceforge.pmd.lang.java.xpath;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.jaxen.Context;
|
||||
import org.jaxen.Function;
|
||||
import org.jaxen.FunctionCallException;
|
||||
import org.jaxen.SimpleFunctionContext;
|
||||
import org.jaxen.XPathFunctionContext;
|
||||
|
||||
import net.sourceforge.pmd.lang.ast.Node;
|
||||
import net.sourceforge.pmd.lang.java.ast.TypeNode;
|
||||
import net.sourceforge.pmd.lang.java.typeresolution.TypeHelper;
|
||||
|
||||
public class TypeIsExactlyFunction implements Function {
|
||||
|
||||
public static void registerSelfInSimpleContext() {
|
||||
((SimpleFunctionContext) XPathFunctionContext.getInstance()).registerFunction(null, "typeIsExactly",
|
||||
new TypeIsExactlyFunction());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object call(final Context context, final List args) throws FunctionCallException {
|
||||
if (args.size() != 1) {
|
||||
throw new IllegalArgumentException(
|
||||
"typeIsExactly function takes a single String argument with the fully qualified type name to check against.");
|
||||
}
|
||||
final String fullTypeName = (String) args.get(0);
|
||||
final Node n = (Node) context.getNodeSet().get(0);
|
||||
|
||||
return typeIsExactly(n, fullTypeName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Example XPath 1.0: {@code //ClassOrInterfaceType[typeIsExactly('java.lang.String')]}
|
||||
* <p>
|
||||
* Example XPath 2.0: {@code //ClassOrInterfaceType[pmd-java:typeIsExactly('java.lang.String')]}
|
||||
*
|
||||
* @param n The node on which to check for types
|
||||
* @param fullTypeName The fully qualified name of the class or any supertype
|
||||
* @return True if the type of the node matches, false otherwise.
|
||||
*/
|
||||
public static boolean typeIsExactly(final Node n, final String fullTypeName) {
|
||||
if (n instanceof TypeNode) {
|
||||
return TypeHelper.isExactlyA((TypeNode) n, fullTypeName);
|
||||
} else {
|
||||
throw new IllegalArgumentException("typeIsExactly function may only be called on a TypeNode.");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
/**
|
||||
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
|
||||
*/
|
||||
|
||||
package net.sourceforge.pmd.lang.java.xpath;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.jaxen.Context;
|
||||
import org.jaxen.Function;
|
||||
import org.jaxen.FunctionCallException;
|
||||
import org.jaxen.SimpleFunctionContext;
|
||||
import org.jaxen.XPathFunctionContext;
|
||||
|
||||
import net.sourceforge.pmd.lang.ast.Node;
|
||||
import net.sourceforge.pmd.lang.java.ast.TypeNode;
|
||||
import net.sourceforge.pmd.lang.java.typeresolution.TypeHelper;
|
||||
|
||||
public class TypeIsFunction implements Function {
|
||||
|
||||
public static void registerSelfInSimpleContext() {
|
||||
((SimpleFunctionContext) XPathFunctionContext.getInstance()).registerFunction(null, "typeIs",
|
||||
new TypeIsFunction());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object call(final Context context, final List args) throws FunctionCallException {
|
||||
if (args.size() != 1) {
|
||||
throw new IllegalArgumentException(
|
||||
"typeIs function takes a single String argument with the fully qualified type name to check against.");
|
||||
}
|
||||
final String fullTypeName = (String) args.get(0);
|
||||
final Node n = (Node) context.getNodeSet().get(0);
|
||||
|
||||
return typeIs(n, fullTypeName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Example XPath 1.0: {@code //ClassOrInterfaceType[typeIs('java.lang.String')]}
|
||||
* <p>
|
||||
* Example XPath 2.0: {@code //ClassOrInterfaceType[pmd-java:typeIs('java.lang.String')]}
|
||||
*
|
||||
* @param n The node on which to check for types
|
||||
* @param fullTypeName The fully qualified name of the class or any supertype
|
||||
* @return True if the type of the node matches, false otherwise.
|
||||
*/
|
||||
public static boolean typeIs(final Node n, final String fullTypeName) {
|
||||
if (n instanceof TypeNode) {
|
||||
return TypeHelper.isA((TypeNode) n, fullTypeName);
|
||||
} else {
|
||||
throw new IllegalArgumentException("typeIs function may only be called on a TypeNode.");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -6,6 +6,7 @@ package net.sourceforge.pmd.lang.java.xpath;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import org.jaxen.Context;
|
||||
import org.jaxen.Function;
|
||||
@@ -13,19 +14,25 @@ import org.jaxen.FunctionCallException;
|
||||
import org.jaxen.SimpleFunctionContext;
|
||||
import org.jaxen.XPathFunctionContext;
|
||||
|
||||
import net.sourceforge.pmd.PMDVersion;
|
||||
import net.sourceforge.pmd.lang.ast.Node;
|
||||
import net.sourceforge.pmd.lang.ast.xpath.Attribute;
|
||||
import net.sourceforge.pmd.lang.java.ast.TypeNode;
|
||||
|
||||
@Deprecated
|
||||
public class TypeOfFunction implements Function {
|
||||
|
||||
private static final Logger LOG = Logger.getLogger(TypeOfFunction.class.getName());
|
||||
private static boolean deprecationWarned = false;
|
||||
|
||||
public static void registerSelfInSimpleContext() {
|
||||
((SimpleFunctionContext) XPathFunctionContext.getInstance()).registerFunction(null, "typeof",
|
||||
new TypeOfFunction());
|
||||
}
|
||||
|
||||
public Object call(Context context, List args) throws FunctionCallException {
|
||||
|
||||
nagDeprecatedFunction();
|
||||
|
||||
String nodeTypeName = null;
|
||||
String fullTypeName = null;
|
||||
String shortTypeName = null;
|
||||
@@ -57,6 +64,14 @@ public class TypeOfFunction implements Function {
|
||||
return typeof(n, nodeTypeName, fullTypeName, shortTypeName);
|
||||
}
|
||||
|
||||
private static void nagDeprecatedFunction() {
|
||||
if (!deprecationWarned) {
|
||||
deprecationWarned = true;
|
||||
LOG.warning("The XPath function typeof() is deprecated and will be removed in "
|
||||
+ PMDVersion.getNextMajorRelease() + ". Use typeIs() instead.");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Example XPath 1.0: {@code //ClassOrInterfaceType[typeof(@Image, 'java.lang.String', 'String')]}
|
||||
* <p>
|
||||
@@ -69,6 +84,8 @@ public class TypeOfFunction implements Function {
|
||||
* @return
|
||||
*/
|
||||
public static boolean typeof(Node n, String nodeTypeName, String fullTypeName, String shortTypeName) {
|
||||
nagDeprecatedFunction();
|
||||
|
||||
if (n instanceof TypeNode) {
|
||||
Class<?> type = ((TypeNode) n).getType();
|
||||
if (type == null) {
|
||||
|
||||
@@ -536,10 +536,10 @@ In JUnit 4, only methods annotated with the @Test annotation are executed.
|
||||
<![CDATA[
|
||||
//ClassOrInterfaceDeclaration[
|
||||
matches(@Image, $testClassPattern)
|
||||
or ExtendsList/ClassOrInterfaceType[pmd-java:typeof(@Image, 'junit.framework.TestCase', 'TestCase')]]
|
||||
or ExtendsList/ClassOrInterfaceType[pmd-java:typeIs('junit.framework.TestCase')]]
|
||||
|
||||
/ClassOrInterfaceBody/ClassOrInterfaceBodyDeclaration[MethodDeclaration[@Public=true()]/MethodDeclarator[starts-with(@Image, 'test')]]
|
||||
[not(Annotation//Name[pmd-java:typeof(@Image, 'org.junit.Test', 'Test')])]
|
||||
[not(Annotation//Name[pmd-java:typeIs('org.junit.Test')])]
|
||||
]]>
|
||||
</value>
|
||||
</property>
|
||||
@@ -1207,7 +1207,7 @@ This rule detects JUnit assertions in object equality. These assertions should b
|
||||
PrimarySuffix/Arguments/ArgumentList/Expression/PrimaryExpression/PrimaryPrefix/Name
|
||||
[ends-with(@Image, '.equals')]
|
||||
]
|
||||
[ancestor::ClassOrInterfaceDeclaration[//ClassOrInterfaceType[pmd-java:typeof(@Image, 'junit.framework.TestCase','TestCase')] or //MarkerAnnotation/Name[pmd-java:typeof(@Image, 'org.junit.Test', 'Test')]]]
|
||||
[ancestor::ClassOrInterfaceDeclaration[//ClassOrInterfaceType[pmd-java:typeIs('junit.framework.TestCase')] or //MarkerAnnotation/Name[pmd-java:typeIs('org.junit.Test')]]]
|
||||
]]>
|
||||
</value>
|
||||
</property>
|
||||
@@ -1247,7 +1247,7 @@ more specific methods, like assertNull, assertNotNull.
|
||||
Expression/EqualityExpression/PrimaryExpression/PrimaryPrefix/Literal/NullLiteral
|
||||
]
|
||||
]
|
||||
[ancestor::ClassOrInterfaceDeclaration[//ClassOrInterfaceType[pmd-java:typeof(@Image, 'junit.framework.TestCase','TestCase')] or //MarkerAnnotation/Name[pmd-java:typeof(@Image, 'org.junit.Test', 'Test')]]]
|
||||
[ancestor::ClassOrInterfaceDeclaration[//ClassOrInterfaceType[pmd-java:typeIs('junit.framework.TestCase')] or //MarkerAnnotation/Name[pmd-java:typeIs('org.junit.Test')]]]
|
||||
]]>
|
||||
</value>
|
||||
</property>
|
||||
@@ -1289,7 +1289,7 @@ by more specific methods, like assertSame, assertNotSame.
|
||||
[PrimarySuffix/Arguments
|
||||
/ArgumentList/Expression
|
||||
/EqualityExpression[count(.//NullLiteral) = 0]]
|
||||
[ancestor::ClassOrInterfaceDeclaration[//ClassOrInterfaceType[pmd-java:typeof(@Image, 'junit.framework.TestCase','TestCase')] or //MarkerAnnotation/Name[pmd-java:typeof(@Image, 'org.junit.Test', 'Test')]]]
|
||||
[ancestor::ClassOrInterfaceDeclaration[//ClassOrInterfaceType[pmd-java:typeIs('junit.framework.TestCase')] or //MarkerAnnotation/Name[pmd-java:typeIs('org.junit.Test')]]]
|
||||
]]>
|
||||
</value>
|
||||
</property>
|
||||
|
||||
@@ -29,7 +29,7 @@ protected constructor in order to prevent instantiation than make the class misl
|
||||
//ClassOrInterfaceDeclaration
|
||||
[@Abstract = 'true']
|
||||
[count(//MethodDeclaration) + count(//ConstructorDeclaration) = 0]
|
||||
[not(../Annotation/MarkerAnnotation/Name[typeof(@Image, 'com.google.auto.value.AutoValue', 'AutoValue')])]
|
||||
[not(../Annotation/MarkerAnnotation/Name[typeIs('com.google.auto.value.AutoValue')])]
|
||||
]]>
|
||||
</value>
|
||||
</property>
|
||||
@@ -267,13 +267,13 @@ Exception, or Error, use a subclassed exception or error instead.
|
||||
<![CDATA[
|
||||
//ThrowStatement//AllocationExpression
|
||||
/ClassOrInterfaceType[
|
||||
typeof(@Image, 'java.lang.Throwable', 'Throwable')
|
||||
typeIs('java.lang.Throwable')
|
||||
or
|
||||
typeof(@Image, 'java.lang.Exception', 'Exception')
|
||||
typeIs('java.lang.Exception')
|
||||
or
|
||||
typeof(@Image, 'java.lang.Error', 'Error')
|
||||
typeIs('java.lang.Error')
|
||||
or
|
||||
typeof(@Image, 'java.lang.RuntimeException', 'RuntimeException')
|
||||
typeIs('java.lang.RuntimeException')
|
||||
]
|
||||
]]>
|
||||
</value>
|
||||
@@ -503,7 +503,7 @@ Errors are system exceptions. Do not extend them.
|
||||
<value>
|
||||
<![CDATA[
|
||||
//ClassOrInterfaceDeclaration/ExtendsList/ClassOrInterfaceType
|
||||
[typeof(@Image,'java.lang.Error','Error')]
|
||||
[typeIs('java.lang.Error')]
|
||||
|
||||
|
||||
]]>
|
||||
@@ -1213,7 +1213,7 @@ PrimaryExpression/PrimarySuffix/Arguments/ArgumentList
|
||||
/Expression/UnaryExpressionNotPlusMinus[@Image='!']
|
||||
/PrimaryExpression/PrimaryPrefix
|
||||
]
|
||||
[ancestor::ClassOrInterfaceDeclaration[//ClassOrInterfaceType[pmd-java:typeof(@Image, 'junit.framework.TestCase','TestCase')] or //MarkerAnnotation/Name[pmd-java:typeof(@Image, 'org.junit.Test', 'Test')]]]
|
||||
[ancestor::ClassOrInterfaceDeclaration[//ClassOrInterfaceType[pmd-java:typeIs('junit.framework.TestCase')] or //MarkerAnnotation/Name[pmd-java:typeIs('org.junit.Test')]]]
|
||||
]]>
|
||||
</value>
|
||||
</property>
|
||||
|
||||
@@ -96,7 +96,7 @@ and unintentional empty constructors.
|
||||
<![CDATA[
|
||||
//ConstructorDeclaration[@Private='false']
|
||||
[count(BlockStatement) = 0 and ($ignoreExplicitConstructorInvocation = 'true' or not(ExplicitConstructorInvocation)) and @containsComment = 'false']
|
||||
[not(../Annotation/MarkerAnnotation/Name[typeof(@Image, 'javax.inject.Inject', 'Inject')])]
|
||||
[not(../Annotation/MarkerAnnotation/Name[typeIs('javax.inject.Inject')])]
|
||||
]]>
|
||||
</value>
|
||||
</property>
|
||||
|
||||
@@ -707,9 +707,9 @@ public String bar(String string) {
|
||||
/Block[not(
|
||||
(BlockStatement[1]/Statement/StatementExpression/PrimaryExpression[./PrimaryPrefix[@SuperModifier='true']]/PrimarySuffix[@Image= ancestor::MethodDeclaration/MethodDeclarator/@Image]))]
|
||||
[ancestor::ClassOrInterfaceDeclaration[ExtendsList/ClassOrInterfaceType[
|
||||
typeof(@Image, 'android.app.Activity', 'Activity') or
|
||||
typeof(@Image, 'android.app.Application', 'Application') or
|
||||
typeof(@Image, 'android.app.Service', 'Service')
|
||||
typeIs('android.app.Activity') or
|
||||
typeIs('android.app.Application') or
|
||||
typeIs('android.app.Service')
|
||||
]]]
|
||||
]]>
|
||||
</value>
|
||||
@@ -752,9 +752,9 @@ Super should be called at the end of the method
|
||||
/Block/BlockStatement[last()]
|
||||
[not(Statement/StatementExpression/PrimaryExpression[./PrimaryPrefix[@SuperModifier='true']]/PrimarySuffix[@Image= ancestor::MethodDeclaration/MethodDeclarator/@Image])]
|
||||
[ancestor::ClassOrInterfaceDeclaration[ExtendsList/ClassOrInterfaceType[
|
||||
typeof(@Image, 'android.app.Activity', 'Activity') or
|
||||
typeof(@Image, 'android.app.Application', 'Application') or
|
||||
typeof(@Image, 'android.app.Service', 'Service')
|
||||
typeIs('android.app.Activity') or
|
||||
typeIs('android.app.Application') or
|
||||
typeIs('android.app.Service')
|
||||
]]]
|
||||
]]>
|
||||
</value>
|
||||
@@ -2058,7 +2058,7 @@ Some JUnit framework methods are easy to misspell.
|
||||
or (not(@Image = 'tearDown')
|
||||
and translate(@Image, 'TEARdOWN', 'tearDown') = 'tearDown')]
|
||||
[FormalParameters[count(*) = 0]]
|
||||
[ancestor::ClassOrInterfaceDeclaration[//ClassOrInterfaceType[pmd-java:typeof(@Image, 'junit.framework.TestCase','TestCase')] or //MarkerAnnotation/Name[pmd-java:typeof(@Image, 'org.junit.Test', 'Test')]]]
|
||||
[ancestor::ClassOrInterfaceDeclaration[//ClassOrInterfaceType[pmd-java:typeIs('junit.framework.TestCase')] or //MarkerAnnotation/Name[pmd-java:typeIs('org.junit.Test')]]]
|
||||
]]>
|
||||
</value>
|
||||
</property>
|
||||
@@ -2092,7 +2092,7 @@ The suite() method in a JUnit test needs to be both public and static.
|
||||
//MethodDeclaration[not(@Static='true') or not(@Public='true')]
|
||||
[MethodDeclarator/@Image='suite']
|
||||
[MethodDeclarator/FormalParameters/@ParameterCount=0]
|
||||
[ancestor::ClassOrInterfaceDeclaration[//ClassOrInterfaceType[pmd-java:typeof(@Image, 'junit.framework.TestCase','TestCase')] or //MarkerAnnotation/Name[pmd-java:typeof(@Image, 'org.junit.Test', 'Test')]]]
|
||||
[ancestor::ClassOrInterfaceDeclaration[//ClassOrInterfaceType[pmd-java:typeIs('junit.framework.TestCase')] or //MarkerAnnotation/Name[pmd-java:typeIs('org.junit.Test')]]]
|
||||
]]>
|
||||
</value>
|
||||
</property>
|
||||
@@ -3059,7 +3059,7 @@ or
|
||||
UnaryExpressionNotPlusMinus[@Image='!']
|
||||
/PrimaryExpression/PrimaryPrefix[Literal/BooleanLiteral or Name[count(../../*)=1]]]
|
||||
]
|
||||
[ancestor::ClassOrInterfaceDeclaration[//ClassOrInterfaceType[pmd-java:typeof(@Image, 'junit.framework.TestCase','TestCase')] or //MarkerAnnotation/Name[pmd-java:typeof(@Image, 'org.junit.Test', 'Test')]]]
|
||||
[ancestor::ClassOrInterfaceDeclaration[//ClassOrInterfaceType[pmd-java:typeIs('junit.framework.TestCase')] or //MarkerAnnotation/Name[pmd-java:typeIs('org.junit.Test')]]]
|
||||
]]>
|
||||
</value>
|
||||
</property>
|
||||
|
||||
@@ -68,7 +68,7 @@ it contains methods that are not thread-safe.
|
||||
<property name="xpath">
|
||||
<value>
|
||||
<![CDATA[
|
||||
//AllocationExpression/ClassOrInterfaceType[pmd-java:typeof(@Image, 'java.lang.ThreadGroup')]|
|
||||
//AllocationExpression/ClassOrInterfaceType[pmd-java:typeIs('java.lang.ThreadGroup')]|
|
||||
//PrimarySuffix[contains(@Image, 'getThreadGroup')]
|
||||
]]>
|
||||
</value>
|
||||
@@ -169,8 +169,8 @@ Explicitly calling Thread.run() method will execute in the caller's thread of co
|
||||
[
|
||||
./Name[ends-with(@Image, '.run') or @Image = 'run']
|
||||
and substring-before(Name/@Image, '.') =//VariableDeclarator/VariableDeclaratorId/@Image
|
||||
[../../../Type/ReferenceType/ClassOrInterfaceType[typeof(@Image, 'java.lang.Thread', 'Thread')]]
|
||||
or (./AllocationExpression/ClassOrInterfaceType[typeof(@Image, 'java.lang.Thread', 'Thread')]
|
||||
[../../../Type/ReferenceType/ClassOrInterfaceType[typeIs('java.lang.Thread')]]
|
||||
or (./AllocationExpression/ClassOrInterfaceType[typeIs('java.lang.Thread')]
|
||||
and ../PrimarySuffix[@Image = 'run'])
|
||||
]
|
||||
]
|
||||
|
||||
@@ -135,10 +135,10 @@ The FileReader and FileWriter constructors instantiate FileInputStream and FileO
|
||||
<value>
|
||||
<![CDATA[
|
||||
//PrimaryPrefix/AllocationExpression/ClassOrInterfaceType[
|
||||
typeof(@Image, 'java.io.FileInputStream', 'FileInputStream')
|
||||
or typeof(@Image, 'java.io.FileOutputStream', 'FileOutputStream')
|
||||
or typeof(@Image, 'java.io.FileReader', 'FileReader')
|
||||
or typeof(@Image, 'java.io.FileWriter', 'FileWriter')
|
||||
typeIs('java.io.FileInputStream')
|
||||
or typeIs('java.io.FileOutputStream')
|
||||
or typeIs('java.io.FileReader')
|
||||
or typeIs('java.io.FileWriter')
|
||||
]
|
||||
]]>
|
||||
</value>
|
||||
@@ -209,10 +209,10 @@ adverse impacts on performance.
|
||||
<![CDATA[
|
||||
//FieldDeclaration/Type/PrimitiveType[@Image = 'short']
|
||||
|
|
||||
//ClassOrInterfaceBodyDeclaration[not(Annotation/MarkerAnnotation/Name[typeof(@Image, 'java.lang.Override', 'Override')])]
|
||||
//ClassOrInterfaceBodyDeclaration[not(Annotation/MarkerAnnotation/Name[typeIs('java.lang.Override')])]
|
||||
/MethodDeclaration/ResultType/Type/PrimitiveType[@Image = 'short']
|
||||
|
|
||||
//ClassOrInterfaceBodyDeclaration[not(Annotation/MarkerAnnotation/Name[typeof(@Image, 'java.lang.Override', 'Override')])]
|
||||
//ClassOrInterfaceBodyDeclaration[not(Annotation/MarkerAnnotation/Name[typeIs('java.lang.Override')])]
|
||||
/MethodDeclaration/MethodDeclarator/FormalParameters/FormalParameter/Type/PrimitiveType[@Image = 'short']
|
||||
|
|
||||
//LocalVariableDeclaration/Type/PrimitiveType[@Image = 'short']
|
||||
@@ -294,7 +294,7 @@ Note that new Byte() is deprecated since JDK 9 for that reason.
|
||||
<![CDATA[
|
||||
//AllocationExpression
|
||||
[not (ArrayDimsAndInits)
|
||||
and ClassOrInterfaceType[typeof(@Image, 'java.lang.Byte', 'Byte')]]
|
||||
and ClassOrInterfaceType[typeIs('java.lang.Byte')]]
|
||||
]]>
|
||||
</value>
|
||||
</property>
|
||||
@@ -467,7 +467,7 @@ Note that new Integer() is deprecated since JDK 9 for that reason.
|
||||
<![CDATA[
|
||||
//AllocationExpression
|
||||
[not (ArrayDimsAndInits)
|
||||
and ClassOrInterfaceType[typeof(@Image, 'java.lang.Integer', 'Integer')]]
|
||||
and ClassOrInterfaceType[typeIs('java.lang.Integer')]]
|
||||
]]>
|
||||
</value>
|
||||
</property>
|
||||
@@ -500,7 +500,7 @@ Note that new Long() is deprecated since JDK 9 for that reason.
|
||||
<![CDATA[
|
||||
//AllocationExpression
|
||||
[not (ArrayDimsAndInits)
|
||||
and ClassOrInterfaceType[typeof(@Image, 'java.lang.Long', 'Long')]]
|
||||
and ClassOrInterfaceType[typeIs('java.lang.Long')]]
|
||||
]]>
|
||||
</value>
|
||||
</property>
|
||||
@@ -664,7 +664,7 @@ Note that new Short() is deprecated since JDK 9 for that reason.
|
||||
<![CDATA[
|
||||
//AllocationExpression
|
||||
[not (ArrayDimsAndInits)
|
||||
and ClassOrInterfaceType[typeof(@Image, 'java.lang.Short', 'Short')]]
|
||||
and ClassOrInterfaceType[typeIs('java.lang.Short')]]
|
||||
]]>
|
||||
</value>
|
||||
</property>
|
||||
|
||||
+5
@@ -34,4 +34,9 @@ public class MultithreadingRulesTest extends SimpleAggregatorTst {
|
||||
System.out.println("test");
|
||||
}
|
||||
}
|
||||
|
||||
// Used by AvoidThreadGroup test cases
|
||||
public static class ThreadGroup {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
Vendored
+2
-2
@@ -24,10 +24,10 @@ public class ArrayVariableDeclaration {
|
||||
| + PrimitiveType
|
||||
|
|
||||
|+ VariableDeclarator
|
||||
| + VariableDeclaratorId[@Image="a" and @Array=false() and ArrayDims=0 and typeof(.)='int[].class']
|
||||
| + VariableDeclaratorId[@Image="a" and @Array=false() and ArrayDims=0 and typeIs(.)='int[].class']
|
||||
|
|
||||
|+ VariableDeclarator
|
||||
| + VariableDeclaratorId[@Image="b" and @Array=true() and ArrayDims=1 and typeof(.)='int[][].class']
|
||||
| + VariableDeclaratorId[@Image="b" and @Array=true() and ArrayDims=1 and typeIs(.)='int[][].class']
|
||||
*/
|
||||
public int[] a, b[]; // SUPPRESS CHECKSTYLE now
|
||||
public String[] c, d[]; // SUPPRESS CHECKSTYLE now
|
||||
|
||||
+1
-1
@@ -236,7 +236,7 @@ class Foo {
|
||||
violation suppression xpath works, by type
|
||||
]]>
|
||||
</description>
|
||||
<rule-property name="violationSuppressXPath">.[typeof('java.lang.String')]</rule-property>
|
||||
<rule-property name="violationSuppressXPath">.[typeIs('java.lang.String')]</rule-property>
|
||||
<expected-problems>0</expected-problems>
|
||||
<code>
|
||||
<![CDATA[
|
||||
|
||||
+2
-1
@@ -61,7 +61,8 @@ ThreadGroup() but not java.lang.ThreadGroup
|
||||
]]></description>
|
||||
<expected-problems>0</expected-problems>
|
||||
<code><![CDATA[
|
||||
import some.pkg.ThreadGroup;
|
||||
import net.sourceforge.pmd.lang.java.rule.multithreading.MultithreadingRulesTest.ThreadGroup;
|
||||
|
||||
public class Foo {
|
||||
void bar() {
|
||||
ThreadGroup t = new ThreadGroup();
|
||||
|
||||
Reference in New Issue
Block a user