[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:
Juan Martín Sotuyo Dodero
2018-05-26 06:01:56 -03:00
parent 72f5539a8b
commit 7572a49d35
20 changed files with 259 additions and 60 deletions
@@ -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
@@ -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)) {
@@ -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;
@@ -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();
@@ -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>
@@ -34,4 +34,9 @@ public class MultithreadingRulesTest extends SimpleAggregatorTst {
System.out.println("test");
}
}
// Used by AvoidThreadGroup test cases
public static class ThreadGroup {
}
}
@@ -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
@@ -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[
@@ -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();