|
1 | 1 | # Custom Linting Rule: Flip Comparison Operators |
2 | 2 |
|
3 | | -A custom rule that detects `>` (greater than) and `>=` (greater than or equal) operators in Java code and suggests flipping them to `<` and `<=` respectively. |
| 3 | +A custom rule that detects `>` (greater than) and `>=` (greater than or equal) operators in Java code and refactors them by flipping both the operator AND operands to their `<` and `<=` equivalents. |
4 | 4 |
|
5 | 5 | ## Quick Start |
6 | 6 |
|
7 | | -### Find operators with bash script |
| 7 | +### Scan for operators (default) |
8 | 8 |
|
9 | 9 | ```bash |
10 | | -./find-comparisons.sh /path/to/java/source |
| 10 | +./find-comparisons.sh |
11 | 11 | ``` |
12 | 12 |
|
13 | | -Example: |
| 13 | +Scans all `src/main/java` and `src/test/java` directories in the project. |
| 14 | + |
| 15 | +Or scan a specific directory: |
14 | 16 | ```bash |
15 | | -./find-comparisons.sh ../approvaltests/src/main/java |
| 17 | +./find-comparisons.sh custom-pmd-rule/example |
16 | 18 | ``` |
17 | 19 |
|
18 | | -This will display all `>` and `>=` operators with line numbers and file paths. |
19 | | - |
20 | | -### Example Output |
| 20 | +### Refactor with `--fix` |
21 | 21 |
|
| 22 | +```bash |
| 23 | +./find-comparisons.sh --fix |
22 | 24 | ``` |
23 | | -example/TestComparison.java:7: if (x > y) { |
24 | | -example/TestComparison.java:11: if (x >= y) { |
25 | | -example/TestComparison.java:25: if (x > 0 && x < 100) { |
26 | | -example/TestComparison.java:30: while (x > 0) { |
27 | | -``` |
| 25 | + |
| 26 | +Automatically refactors all comparison operators with proper operand swapping. |
28 | 27 |
|
29 | 28 | ## What the Rule Does |
30 | 29 |
|
31 | | -- **Detects** `>` operators and suggests flipping to `<` |
32 | | -- **Detects** `>=` operators and suggests flipping to `<=` |
33 | | -- **Warnings only** — does not auto-fix (to prevent accidentally inverting logic) |
34 | | -- Works as a standalone CLI tool |
| 30 | +### Refactoring Behavior |
| 31 | + |
| 32 | +This is a **pure refactoring** that preserves logic by swapping operands: |
| 33 | + |
| 34 | +| Original | Refactored | Logic | |
| 35 | +|----------|-----------|-------| |
| 36 | +| `x > y` | `y < x` | Equivalent ✓ | |
| 37 | +| `x >= y` | `y <= x` | Equivalent ✓ | |
| 38 | +| `this.getValue() > 5` | `5 < this.getValue()` | Equivalent ✓ | |
| 39 | +| `items.length >= 1` | `1 <= items.length` | Equivalent ✓ | |
| 40 | +| `getList().size() > 0` | `0 < getList().size()` | Equivalent ✓ | |
| 41 | + |
| 42 | +### Protected Cases |
| 43 | + |
| 44 | +The script intelligently handles: |
| 45 | +- ✅ **Simple comparisons** — `x > y` |
| 46 | +- ✅ **Method calls** — `obj.getValue() > 5` |
| 47 | +- ✅ **Chained calls** — `obj.getList().size() > 0` |
| 48 | +- ✅ **Property access** — `items.length >= 1` |
| 49 | +- ✅ **Complex expressions** — `getParameterTypes().length >= 1` |
| 50 | +- ✅ **Preserves generics** — `List<Integer>` unchanged |
| 51 | +- ✅ **Mixed code** — Generics and comparisons on same line |
| 52 | + |
| 53 | +## Test Cases |
| 54 | + |
| 55 | +Comprehensive test file included: `example/ComparisonTest.java` |
| 56 | + |
| 57 | +Tests verify: |
| 58 | +- Simple variable comparisons |
| 59 | +- Method calls and chained calls |
| 60 | +- Property access patterns (like `array.length`) |
| 61 | +- Complex expressions with multiple dots and parentheses |
| 62 | +- Generic type preservation |
| 63 | +- Mixed generics and comparisons on same line |
| 64 | + |
| 65 | +Run the test: |
| 66 | +```bash |
| 67 | +./find-comparisons.sh --fix custom-pmd-rule/example |
| 68 | +``` |
35 | 69 |
|
36 | 70 | ## Files |
37 | 71 |
|
38 | | -- `find-comparisons.sh` — Main script to find comparison operators |
39 | | -- `flip-comparison.xml` — PMD configuration file |
40 | | -- `example/TestComparison.java` — Example Java file with violations |
41 | | -- `SETUP.md` — Detailed setup and PMD integration instructions |
| 72 | +- `find-comparisons.sh` — Main script to scan and refactor comparison operators |
| 73 | +- `example/TestComparison.java` — Example with simple comparisons and generics |
| 74 | +- `example/ComparisonTest.java` — Comprehensive test cases |
| 75 | +- `flip-comparison.xml` — PMD configuration (reference) |
| 76 | +- `SETUP.md` — Additional setup and integration instructions |
| 77 | + |
| 78 | +## Logic Preservation |
42 | 79 |
|
43 | | -## Why "Flip"? |
| 80 | +The refactoring swaps both the operator AND the operands, so the logical meaning is preserved: |
44 | 81 |
|
45 | | -If you flip comparison operators, you reverse the logic: |
46 | | -- `x > y` becomes `x < y` (opposite condition) |
47 | | -- `x >= y` becomes `x <= y` (opposite condition) |
| 82 | +**Before:** `if (x > y) { ... }` |
| 83 | +**After:** `if (y < x) { ... }` |
| 84 | +**Result:** Same condition, just expressed differently |
48 | 85 |
|
49 | | -The rule is useful for: |
50 | | -- Finding all comparison operators in your codebase |
51 | | -- Code analysis and style enforcement |
52 | | -- Testing/educational purposes |
| 86 | +This makes it a safe refactoring—no behavior changes, only code rearrangement. |
53 | 87 |
|
54 | | -## For PMD Integration |
| 88 | +## Usage |
55 | 89 |
|
56 | | -See `SETUP.md` for instructions on using this with PMD directly. |
| 90 | +```bash |
| 91 | +# Scan all src directories |
| 92 | +./find-comparisons.sh |
| 93 | + |
| 94 | +# Scan specific directory |
| 95 | +./find-comparisons.sh /path/to/src |
| 96 | + |
| 97 | +# Refactor all operators |
| 98 | +./find-comparisons.sh --fix |
| 99 | + |
| 100 | +# Refactor specific directory |
| 101 | +./find-comparisons.sh --fix /path/to/src |
| 102 | + |
| 103 | +# Review changes before committing |
| 104 | +git diff |
| 105 | +``` |
0 commit comments