Skip to content

Commit

Permalink
Merge branch '__rultor'
Browse files Browse the repository at this point in the history
  • Loading branch information
rultor committed May 1, 2019
2 parents cfa32b6 + a57c230 commit 259b642
Show file tree
Hide file tree
Showing 18 changed files with 286 additions and 377 deletions.
6 changes: 6 additions & 0 deletions pom.xml
Expand Up @@ -151,6 +151,12 @@
<version>5.3.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-params</artifactId>
<version>5.3.1</version>
<scope>test</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
Expand Down
4 changes: 4 additions & 0 deletions qulice-pmd/pom.xml
Expand Up @@ -94,6 +94,10 @@
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-params</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
Expand Down
Expand Up @@ -33,31 +33,25 @@
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceType;
import net.sourceforge.pmd.lang.ast.Node;
import net.sourceforge.pmd.lang.java.ast.ASTExpression;
import net.sourceforge.pmd.lang.java.ast.ASTMethodDeclaration;
import net.sourceforge.pmd.lang.java.ast.ASTName;
import net.sourceforge.pmd.lang.java.ast.ASTPrimaryPrefix;
import net.sourceforge.pmd.lang.java.ast.ASTPrimarySuffix;
import net.sourceforge.pmd.lang.java.ast.ASTResultType;
import net.sourceforge.pmd.lang.java.ast.ASTType;
import net.sourceforge.pmd.lang.java.ast.ASTVariableDeclaratorId;
import net.sourceforge.pmd.lang.java.ast.JavaNode;
import net.sourceforge.pmd.lang.java.rule.AbstractInefficientZeroCheck;
import net.sourceforge.pmd.lang.java.symboltable.ClassScope;
import net.sourceforge.pmd.lang.java.symboltable.JavaNameOccurrence;
import net.sourceforge.pmd.lang.java.symboltable.MethodNameDeclaration;
import net.sourceforge.pmd.lang.symboltable.NameOccurrence;
import net.sourceforge.pmd.lang.symboltable.Scope;
import net.sourceforge.pmd.util.StringUtil;

/**
* Rule to prohibit use of String.length() when checking for empty string.
* String.isEmpty() should be used instead.
* @since 0.18
* @todo #950:30min Correct this class so it complains if the string is
* prefixed with this when length is called (e.g. somestring.length() works
* but this.somestring.length() does not). The same happens in with a method
* call (this.method().length() does not work). More about how to write PMD
* rules here: http://pmd.sourceforge.net/pmd-4.3/howtowritearule.html. Then
* ignore the tests on UseStringIsEmptyRuleTest.
*/
@SuppressWarnings("PMD.AvoidDuplicateLiterals")
public final class UseStringIsEmptyRule extends AbstractInefficientZeroCheck {

@Override
Expand All @@ -79,75 +73,62 @@ public Map<String, List<String>> getComparisonTargets() {

@Override
public boolean isTargetMethod(final JavaNameOccurrence occ) {
boolean target = false;
if (occ.getNameForWhichThisIsAQualifier() != null
&& occ.getLocation().getImage().endsWith(".length")
final NameOccurrence name = occ.getNameForWhichThisIsAQualifier();
return name != null && "length".equals(name.getImage());
}

@Override
public Object visit(final ASTVariableDeclaratorId node, final Object data) {
final Node type = node.getTypeNameNode();
if (type != null
|| this.appliesToClassName(node.getNameDeclaration().getTypeImage())
) {
target = true;
final List<NameOccurrence> declarations = node.getUsages();
this.checkDeclarations(declarations, data);
}
return target;
node.childrenAccept(this, data);
return data;
}

@Override
public Object visit(final ASTPrimarySuffix node, final Object data) {
if (node.getImage() != null && node.getImage().endsWith("length")) {
ASTClassOrInterfaceType type = getTypeOfPrimaryPrefix(node);
if (type == null) {
type = getTypeOfMethodCall(node);
}
if (type != null
&& this.appliesToClassName(type.getType().getSimpleName())
) {
checkNodeAndReport(
data, node, node.jjtGetParent().jjtGetParent()
public Object visit(final ASTMethodDeclaration node, final Object data) {
final ASTResultType result = node.getResultType();
if (!result.isVoid()) {
final ASTType type = (ASTType) result.jjtGetChild(0);
if (this.appliesToClassName(type.getTypeImage())) {
final Scope scope = node.getScope().getParent();
final MethodNameDeclaration method = new MethodNameDeclaration(
node.getMethodDeclarator()
);
final List<NameOccurrence> declarations = scope
.getDeclarations(MethodNameDeclaration.class)
.get(method);
this.checkDeclarations(declarations, data);
}
}
node.childrenAccept(this, data);
return data;
}

/**
* Get the type returned by the method call.
* @param node Node suffix
* @return The type or null if it's not found
* Checks all uses of a variable or method with a String type.
* @param occurrences Variable or method occurrences.
* @param data Rule context.
*/
private static ASTClassOrInterfaceType getTypeOfMethodCall(
final ASTPrimarySuffix node) {
ASTClassOrInterfaceType type = null;
final ASTName method = node.jjtGetParent()
.getFirstChildOfType(ASTPrimaryPrefix.class)
.getFirstChildOfType(ASTName.class);
if (method != null) {
final ClassScope scope = node.getScope()
.getEnclosingScope(ClassScope.class);
final Map<MethodNameDeclaration, List<NameOccurrence>> methods =
scope.getMethodDeclarations();
//@checkstyle LineLengthCheck (1 line)
for (final Map.Entry<MethodNameDeclaration, List<NameOccurrence>> entry
: methods.entrySet()) {
if (entry.getKey().getName().equals(method.getImage())) {
type = entry.getKey().getNode()
.getFirstParentOfType(ASTMethodDeclaration.class)
.getFirstChildOfType(ASTResultType.class)
.getFirstDescendantOfType(
ASTClassOrInterfaceType.class
);
break;
}
private void checkDeclarations(
final Iterable<NameOccurrence> occurrences, final Object data
) {
for (final NameOccurrence occurrence : occurrences) {
final JavaNameOccurrence jocc = (JavaNameOccurrence) occurrence;
if (this.isTargetMethod(jocc)) {
final JavaNode location = jocc.getLocation();
final Node expr = location.getFirstParentOfType(
ASTExpression.class
);
this.checkNodeAndReport(
data, occurrence.getLocation(), expr.jjtGetChild(0)
);
}
}
return type;
}

/**
* Get the type of the primary prefix.
* @param node Node suffix
* @return The type or null if it's not found.
*/
private static ASTClassOrInterfaceType getTypeOfPrimaryPrefix(
final ASTPrimarySuffix node) {
return node.jjtGetParent()
.getFirstChildOfType(ASTPrimaryPrefix.class)
.getFirstDescendantOfType(ASTClassOrInterfaceType.class);
}
}

2 comments on commit 259b642

@0pdd
Copy link
Collaborator

@0pdd 0pdd commented on 259b642 May 1, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Puzzle 950-157b8116 disappeared from qulice-pmd/src/main/java/com/qulice/pmd/rules/UseStringIsEmptyRule.java, that's why I closed #999. Please, remember that the puzzle was not necessarily removed in this particular commit. Maybe it happened earlier, but we discovered this fact only now.

@0pdd
Copy link
Collaborator

@0pdd 0pdd commented on 259b642 May 1, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Puzzle 1000-db538e24 disappeared from qulice-pmd/src/test/java/com/qulice/pmd/UseStringIsEmptyRuleTest.java, that's why I closed #1016. Please, remember that the puzzle was not necessarily removed in this particular commit. Maybe it happened earlier, but we discovered this fact only now.

Please sign in to comment.