1
2
3
4
5 package com.qulice.pmd.rules;
6
7 import java.util.Arrays;
8 import java.util.HashMap;
9 import java.util.List;
10 import java.util.Map;
11 import net.sourceforge.pmd.lang.ast.Node;
12 import net.sourceforge.pmd.lang.java.ast.ASTExpression;
13 import net.sourceforge.pmd.lang.java.ast.ASTMethodDeclaration;
14 import net.sourceforge.pmd.lang.java.ast.ASTReferenceType;
15 import net.sourceforge.pmd.lang.java.ast.ASTResultType;
16 import net.sourceforge.pmd.lang.java.ast.ASTType;
17 import net.sourceforge.pmd.lang.java.ast.ASTVariableDeclaratorId;
18 import net.sourceforge.pmd.lang.java.ast.JavaNode;
19 import net.sourceforge.pmd.lang.java.symboltable.JavaNameOccurrence;
20 import net.sourceforge.pmd.lang.java.symboltable.MethodNameDeclaration;
21 import net.sourceforge.pmd.lang.symboltable.NameOccurrence;
22 import net.sourceforge.pmd.lang.symboltable.Scope;
23
24
25
26
27
28
29 @SuppressWarnings("deprecation")
30 public final class UseStringIsEmptyRule
31 extends net.sourceforge.pmd.lang.java.rule.AbstractInefficientZeroCheck {
32
33 @Override
34 public boolean appliesToClassName(final String name) {
35 return net.sourceforge.pmd.util.StringUtil.isSame(
36 name, "String", true, true, true
37 );
38 }
39
40 @Override
41 public Map<String, List<String>> getComparisonTargets() {
42 final Map<String, List<String>> rules = new HashMap<>();
43 rules.put("<", Arrays.asList("1"));
44 rules.put(">", Arrays.asList("0"));
45 rules.put("==", Arrays.asList("0"));
46 rules.put("!=", Arrays.asList("0"));
47 rules.put(">=", Arrays.asList("0", "1"));
48 rules.put("<=", Arrays.asList("0"));
49 return rules;
50 }
51
52 @Override
53 public boolean isTargetMethod(final JavaNameOccurrence occ) {
54 final NameOccurrence name = occ.getNameForWhichThisIsAQualifier();
55 return name != null && "length".equals(name.getImage());
56 }
57
58 @Override
59 public Object visit(
60 final ASTVariableDeclaratorId variable, final Object data
61 ) {
62 final Node node = variable.getTypeNameNode();
63 if (node instanceof ASTReferenceType) {
64 final Class<?> clazz = variable.getType();
65 final String type = variable.getNameDeclaration().getTypeImage();
66 if (clazz != null && !clazz.isArray()
67 && this.appliesToClassName(type)
68 ) {
69 final List<NameOccurrence> declarations = variable.getUsages();
70 this.checkDeclarations(declarations, data);
71 }
72 }
73 variable.childrenAccept(this, data);
74 return data;
75 }
76
77 @Override
78 public Object visit(
79 final ASTMethodDeclaration declaration, final Object data
80 ) {
81 final ASTResultType result = declaration.getResultType();
82 if (!result.isVoid()) {
83 final ASTType node = (ASTType) result.jjtGetChild(0);
84 final Class<?> clazz = node.getType();
85 final String type = node.getTypeImage();
86 if (clazz != null && !clazz.isArray()
87 && this.appliesToClassName(type)
88 ) {
89 final Scope scope = declaration.getScope().getParent();
90 final MethodNameDeclaration method = new MethodNameDeclaration(
91 declaration.getMethodDeclarator()
92 );
93 final List<NameOccurrence> declarations = scope
94 .getDeclarations(MethodNameDeclaration.class)
95 .get(method);
96 this.checkDeclarations(declarations, data);
97 }
98 }
99 declaration.childrenAccept(this, data);
100 return data;
101 }
102
103
104
105
106
107
108 private void checkDeclarations(
109 final Iterable<NameOccurrence> occurrences, final Object data
110 ) {
111 for (final NameOccurrence occurrence : occurrences) {
112 final JavaNameOccurrence jocc = (JavaNameOccurrence) occurrence;
113 if (this.isTargetMethod(jocc)) {
114 final JavaNode location = jocc.getLocation();
115 final Node expr = location.getFirstParentOfType(
116 ASTExpression.class
117 );
118 this.checkNodeAndReport(
119 data, occurrence.getLocation(), expr.jjtGetChild(0)
120 );
121 }
122 }
123 }
124 }