Clover coverage report - PMD - 3.7 Coverage timestamp: Wed May 31 2006 09:25:59 EDT FRAMES NO FRAMES |
file stats: | LOC: | 102 |  | Methods: | 3
| NCLOC: | 79 |  | Classes: | 1
Source file | Conditionals | Statements | Methods | TOTAL
SuspiciousOctalEscape.java | 41.7% | 51.9% | 100% | 50.6% |

1 |  | package net.sourceforge.pmd.rules;
2 |  |
3 |  | import net.sourceforge.pmd.AbstractRule;
4 |  | import net.sourceforge.pmd.ast.ASTLiteral;
5 |  |
6 |  | public class SuspiciousOctalEscape extends AbstractRule {
7 |  |
8 | 2 | public Object visit(ASTLiteral node, Object data) {
9 | 2 | String image = node.getImage();
10 | 2 | if (image != null && image.startsWith("\"")) // make sure it's a string literal
11 |  | {
12 |  | // trim quotes
13 | 1 | String s = image.substring(1, image.length() - 1);
14 |  |
15 |  | // process escape sequences
16 | 1 | int offset = 0;
17 | 1 | for (int slash = s.indexOf('\\', offset);
18 | 2 | slash != -1 && slash < s.length() - 1;
19 |  | slash = s.indexOf('\\', offset)) {
20 | 1 | String escapeSequence = s.substring(slash + 1);
21 | 1 | char first = escapeSequence.charAt(0);
22 | 1 | if (isOctal(first)) {
23 | 1 | if (escapeSequence.length() > 1) {
24 | 1 | char second = escapeSequence.charAt(1);
25 | 1 | if (isOctal(second)) {
26 | 1 | if (escapeSequence.length() > 2) {
27 | 1 | char third = escapeSequence.charAt(2);
28 | 1 | if (isOctal(third)) {
29 |  | // this is either a three digit octal escape or a two-digit
30 |  | // octal escape followed by an octal digit. the value of
31 |  | // the first digit in the sequence determines which is the
32 |  | // case
33 | 0 | if (first != '0' && first != '1' && first != '2' && first != '3') {
34 |  | // VIOLATION: it's a two-digit octal escape followed by
35 |  | // an octal digit -- legal but very confusing!
36 | 0 | addViolation(data, node);
37 |  | } else {
38 |  | // if there is a 4th decimal digit, it could never be part of
39 |  | // the escape sequence, which is confusing
40 | 0 | if (escapeSequence.length() > 3) {
41 | 0 | char fourth = escapeSequence.charAt(3);
42 | 0 | if (isDecimal(fourth)) {
43 | 0 | addViolation(data, node);
44 |  | }
45 |  | }
46 |  | }
47 |  |
48 | 1 | } else if (isDecimal(third)) {
49 |  | // this is a two-digit octal escape followed by a decimal digit
50 |  | // legal but very confusing
51 | 1 | addViolation(data, node);
52 |  | }
53 |  | }
54 | 0 | } else if (isDecimal(second)) {
55 |  | // this is a one-digit octal escape followed by a decimal digit
56 |  | // legal but very confusing
57 | 0 | addViolation(data, node);
58 |  | }
59 |  | }
60 |  | }
61 |  |
62 | 1 | offset = slash + 1;
63 |  | }
64 |  | }
65 |  |
66 | 2 | return super.visit(node, data);
67 |  | }
68 |  |
69 | 3 | private boolean isOctal(char c) {
70 | 3 | switch (c) {
71 | 0 | case '0':
72 | 1 | case '1':
73 | 1 | case '2':
74 | 0 | case '3':
75 | 0 | case '4':
76 | 0 | case '5':
77 | 0 | case '6':
78 | 0 | case '7':
79 | 2 | return true;
80 | 1 | default:
81 | 1 | return false;
82 |  | }
83 |  | }
84 |  |
85 | 1 | private boolean isDecimal(char c) {
86 | 1 | switch (c) {
87 | 0 | case '0':
88 | 0 | case '1':
89 | 0 | case '2':
90 | 0 | case '3':
91 | 0 | case '4':
92 | 0 | case '5':
93 | 0 | case '6':
94 | 0 | case '7':
95 | 1 | case '8':
96 | 0 | case '9':
97 | 1 | return true;
98 | 0 | default:
99 | 0 | return false;
100 |  | }
101 |  | }
102 |  | }