PageRenderTime 38ms CodeModel.GetById 13ms RepoModel.GetById 0ms app.codeStats 0ms

/projects/pmd-4.2.5/src/net/sourceforge/pmd/rules/design/SingularField.java

https://gitlab.com/essere.lab.public/qualitas.class-corpus
Java | 148 lines | 111 code | 18 blank | 19 comment | 38 complexity | 1dabaabfe27560ddbfa6ebff773a2739 MD5 | raw file
  1. /*
  2. * SingularField.java
  3. *
  4. * Created on April 17, 2005, 9:49 PM
  5. */
  6. package net.sourceforge.pmd.rules.design;
  7. import java.util.ArrayList;
  8. import java.util.List;
  9. import net.sourceforge.pmd.AbstractRule;
  10. import net.sourceforge.pmd.PropertyDescriptor;
  11. import net.sourceforge.pmd.ast.ASTAssignmentOperator;
  12. import net.sourceforge.pmd.ast.ASTClassOrInterfaceDeclaration;
  13. import net.sourceforge.pmd.ast.ASTConstructorDeclaration;
  14. import net.sourceforge.pmd.ast.ASTFieldDeclaration;
  15. import net.sourceforge.pmd.ast.ASTIfStatement;
  16. import net.sourceforge.pmd.ast.ASTInitializer;
  17. import net.sourceforge.pmd.ast.ASTMethodDeclaration;
  18. import net.sourceforge.pmd.ast.ASTPrimaryExpression;
  19. import net.sourceforge.pmd.ast.ASTStatementExpression;
  20. import net.sourceforge.pmd.ast.ASTSynchronizedStatement;
  21. import net.sourceforge.pmd.ast.ASTVariableDeclaratorId;
  22. import net.sourceforge.pmd.ast.Node;
  23. import net.sourceforge.pmd.ast.SimpleNode;
  24. import net.sourceforge.pmd.properties.BooleanProperty;
  25. import net.sourceforge.pmd.symboltable.NameOccurrence;
  26. /**
  27. * @author Eric Olander
  28. * @author Wouter Zelle
  29. */
  30. public class SingularField extends AbstractRule {
  31. /**
  32. * Restore old behaviour by setting both properties to true, which will result in many false positives
  33. */
  34. private static final PropertyDescriptor CHECK_INNER_CLASSES = new BooleanProperty(
  35. "CheckInnerClasses", "Check inner classes", false, 1.0f);
  36. private static final PropertyDescriptor DISALLOW_NOT_ASSIGNMENT = new BooleanProperty(
  37. "DisallowNotAssignment", "Disallow violations where the first usage is not an assignment", false, 1.0f);
  38. public Object visit(ASTFieldDeclaration node, Object data) {
  39. boolean checkInnerClasses = getBooleanProperty(CHECK_INNER_CLASSES);
  40. boolean disallowNotAssignment = getBooleanProperty(DISALLOW_NOT_ASSIGNMENT);
  41. if (node.isPrivate() && !node.isStatic()) {
  42. List<ASTVariableDeclaratorId> list = node.findChildrenOfType(ASTVariableDeclaratorId.class);
  43. ASTVariableDeclaratorId declaration = list.get(0);
  44. List<NameOccurrence> usages = declaration.getUsages();
  45. SimpleNode decl = null;
  46. boolean violation = true;
  47. for (int ix = 0; ix < usages.size(); ix++) {
  48. NameOccurrence no = usages.get(ix);
  49. SimpleNode location = no.getLocation();
  50. ASTPrimaryExpression primaryExpressionParent = location.getFirstParentOfType(ASTPrimaryExpression.class);
  51. if (ix==0 && !disallowNotAssignment) {
  52. if (primaryExpressionParent.getFirstParentOfType(ASTIfStatement.class) != null) {
  53. //the first usage is in an if, so it may be skipped on
  54. //later calls to the method. So this might be legit code
  55. //that simply stores an object for later use.
  56. violation = false;
  57. break; //Optimization
  58. }
  59. //Is the first usage in an assignment?
  60. Node potentialStatement = primaryExpressionParent.jjtGetParent();
  61. boolean assignmentToField = no.getImage().equals(location.getImage()); //Check the the assignment is not to a field inside the field object
  62. if (!assignmentToField || !isInAssignment(potentialStatement)) {
  63. violation = false;
  64. break; //Optimization
  65. } else {
  66. if (usages.size() > ix + 1) {
  67. SimpleNode secondUsageLocation = usages.get(ix + 1).getLocation();
  68. List<ASTStatementExpression> parentStatements = secondUsageLocation.getParentsOfType(ASTStatementExpression.class);
  69. for (ASTStatementExpression statementExpression : parentStatements) {
  70. if (statementExpression != null && statementExpression.equals(potentialStatement)) {
  71. //The second usage is in the assignment of the first usage, which is allowed
  72. violation = false;
  73. break; //Optimization
  74. }
  75. }
  76. }
  77. }
  78. }
  79. if (!checkInnerClasses) {
  80. //Skip inner classes because the field can be used in the outer class and checking this is too difficult
  81. ASTClassOrInterfaceDeclaration clazz = location.getFirstParentOfType(ASTClassOrInterfaceDeclaration.class);
  82. if (clazz!= null && clazz.getFirstParentOfType(ASTClassOrInterfaceDeclaration.class) != null) {
  83. violation = false;
  84. break; //Optimization
  85. }
  86. }
  87. if (primaryExpressionParent.jjtGetParent() instanceof ASTSynchronizedStatement) {
  88. //This usage is directly in an expression of a synchronized block
  89. violation = false;
  90. break; //Optimization
  91. }
  92. SimpleNode method = location.getFirstParentOfType(ASTMethodDeclaration.class);
  93. if (method == null) {
  94. method = location.getFirstParentOfType(ASTConstructorDeclaration.class);
  95. if (method == null) {
  96. method = location.getFirstParentOfType(ASTInitializer.class);
  97. if (method == null) {
  98. continue;
  99. }
  100. }
  101. }
  102. if (decl == null) {
  103. decl = method;
  104. continue;
  105. } else if (decl != method) {
  106. violation = false;
  107. break; //Optimization
  108. }
  109. }
  110. if (violation && !usages.isEmpty()) {
  111. addViolation(data, node, new Object[] { declaration.getImage() });
  112. }
  113. }
  114. return data;
  115. }
  116. private boolean isInAssignment(Node potentialStatement) {
  117. if (potentialStatement instanceof ASTStatementExpression) {
  118. ASTStatementExpression statement = (ASTStatementExpression)potentialStatement;
  119. List<ASTAssignmentOperator> assignments = new ArrayList<ASTAssignmentOperator>();
  120. statement.findChildrenOfType(ASTAssignmentOperator.class, assignments, false);
  121. if (assignments.isEmpty() || !"=".equals(assignments.get(0).getImage())) {
  122. return false;
  123. } else {
  124. return true;
  125. }
  126. } else {
  127. return false;
  128. }
  129. }
  130. }