debtmap 0.16.7

Code complexity and technical debt analyzer
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
# Suppression Patterns

Debtmap provides flexible suppression mechanisms to help you focus on the technical debt that matters most. You can suppress specific debt items inline with comments, or exclude entire files and functions through configuration.

## Why Use Suppressions?

Not all detected technical debt requires immediate action. Suppressions allow you to:

- **Focus on priorities**: Hide known, accepted debt to see new issues clearly
- **Handle false positives**: Suppress patterns that don't apply to your context
- **Document decisions**: Explain why certain debt is acceptable using reason annotations
- **Exclude test code**: Ignore complexity in test fixtures and setup functions

## Inline Comment Suppression

Debtmap supports four inline comment formats that work with your language's comment syntax:

### Single-Line Suppression

Suppress debt on the same line as the comment:

```rust
// debtmap:ignore
// TODO: Implement caching later - performance is acceptable for now
```

```python
# debtmap:ignore
# FIXME: Refactor this after the Q2 release
```

The suppression applies to debt detected on the same line as the comment.

### Next-Line Suppression

Suppress debt on the line immediately following the comment:

```rust
// debtmap:ignore-next-line
fn complex_algorithm() {
    // ...20 lines of complex code...
}
```

```typescript
// debtmap:ignore-next-line
function calculateMetrics(data: DataPoint[]): Metrics {
    // ...complex implementation...
}
```

This format is useful when you want the suppression comment to appear before the code it affects.

### Block Suppression

Suppress multiple lines of code between start and end markers:

```rust
// debtmap:ignore-start
fn setup_test_environment() {
    // TODO: Add more test cases
    // FIXME: Handle edge cases
    // Complex test setup code...
}
// debtmap:ignore-end
```

```python
# debtmap:ignore-start
def mock_api_responses():
    # TODO: Add more mock scenarios
    # Multiple lines of mock setup
    pass
# debtmap:ignore-end
```

**Important**: Every `ignore-start` must have a matching `ignore-end`. Debtmap tracks unclosed blocks and can warn you about them.

## Type-Specific Suppression

You can suppress specific types of debt using bracket notation instead of suppressing everything:

### Quick Reference: Debt Type Suppression

| Debt Type | Bracket Name(s) | Example | Notes |
|-----------|-----------------|---------|-------|
| TODO comments | `[todo]` | `// debtmap:ignore[todo]` | Also suppresses TestTodo |
| FIXME comments | `[fixme]` | `// debtmap:ignore[fixme]` | |
| Code smells | `[smell]` or `[codesmell]` | `// debtmap:ignore[smell]` | |
| High complexity | `[complexity]` | `// debtmap:ignore[complexity]` | Also suppresses TestComplexity |
| Code duplication | `[duplication]` or `[duplicate]` | `// debtmap:ignore[duplication]` | Also suppresses TestDuplication |
| Dependency issues | `[dependency]` | `// debtmap:ignore[dependency]` | |
| Error swallowing | ❌ Not supported | `// debtmap:ignore` | Use general suppression only |
| Resource management | ❌ Not supported | `// debtmap:ignore` | Use general suppression only |
| Code organization | ❌ Not supported | `// debtmap:ignore` | Use general suppression only |
| Test quality | ❌ Not supported | `// debtmap:ignore` | Use general suppression only |
| All types | `[*]` | `// debtmap:ignore[*]` | Wildcard matches everything |

### Suppress Specific Types

```rust
// debtmap:ignore[todo]
// TODO: This TODO is ignored, but FIXMEs and complexity are still reported
```

```rust
// debtmap:ignore[todo,fixme]
// TODO: Both TODOs and FIXMEs are ignored here
// FIXME: But complexity issues would still be detected
```

### Supported Debt Types

You can suppress the following debt types by name in bracket notation:

**Currently Supported:**
- `todo` - TODO comments (also detects test-specific TODOs)
- `fixme` - FIXME comments
- `smell` or `codesmell` - Code smell patterns
- `complexity` - High cognitive complexity (also detects test complexity)
- `duplication` or `duplicate` - Code duplication (also detects test duplication)
- `dependency` - Dependency issues
- `*` - All types (wildcard)

**Auto-Detected Types** (cannot be suppressed by name):

The following debt types are detected by code analysis rather than comment scanning. These types **cannot** be suppressed using bracket notation like `[error_swallowing]` because they are not included in the suppression parser's type mapping.

**Why bracket notation doesn't work**: The suppression parser only recognizes specific type names in its internal mapping (`DEBT_TYPE_MAP`): `todo`, `fixme`, `smell`/`codesmell`, `complexity`, `duplication`/`duplicate`, and `dependency`. Types detected through AST analysis (like error swallowing and resource management) don't have string identifiers in the parser. To suppress these, use the general `debtmap:ignore` marker without brackets:

- `error_swallowing` - Error handling issues (empty catch blocks, ignored errors)
- `resource_management` - Resource cleanup issues (file handles, connections)
- `code_organization` - Structural issues (god objects, large classes)

**Example:**
```rust
// ✅ Correct: General suppression without brackets
// debtmap:ignore -- Intentional empty catch for cleanup
match result {
    Err(_) => {} // Empty catch block
    Ok(v) => process(v)
}

// ❌ Wrong: Bracket notation not supported for auto-detected types
// debtmap:ignore[error_swallowing]
```

**Test-Specific Debt Types:**

Test-specific variants like `TestComplexity`, `TestTodo`, `TestDuplication`, and `TestQuality` are suppressed through their base types:

- `TestComplexity` → suppressed with `[complexity]`
- `TestTodo` → suppressed with `[todo]`
- `TestDuplication` → suppressed with `[duplication]`
- `TestQuality` → suppressed with general `debtmap:ignore` (no bracket notation)

**Example:**
```rust
#[cfg(test)]
mod tests {
    // Suppresses both Complexity and TestComplexity
    // debtmap:ignore[complexity] -- Complex test setup acceptable
    fn setup_test_environment() {
        // Complex test initialization
    }

    // debtmap:ignore[todo] -- Suppresses both Todo and TestTodo
    // TODO: Add more test cases
    fn test_feature() { }
}
```

### Wildcard Suppression

Use `[*]` to explicitly suppress all types (equivalent to no bracket notation):

```rust
// debtmap:ignore[*]
// Suppresses all debt types
```

### Type-Specific Blocks

Block suppressions also support type filtering:

```rust
// debtmap:ignore-start[complexity]
fn intentionally_complex_for_performance() {
    // Complex nested logic is intentional here
    // Complexity warnings suppressed, but TODOs still detected
}
// debtmap:ignore-end
```

## Suppression Reasons

Document why you're suppressing debt using the `--` separator:

```rust
// debtmap:ignore -- Intentional for backward compatibility
// TODO: Remove this after all clients upgrade to v2.0
```

```python
# debtmap:ignore[complexity] -- Performance-critical hot path
def optimize_query(params):
    # Complex but necessary for performance
    pass
```

```typescript
// debtmap:ignore-next-line -- Waiting on upstream library fix
function workaroundBug() {
    // FIXME: Remove when library v3.0 is released
}
```

**Best Practice**: Always include reasons for suppressions. This helps future maintainers understand the context and know when suppressions can be removed.

## Config File Exclusions

For broader exclusions, use the `[ignore]` section in `.debtmap.toml`:

### File Pattern Exclusions

```toml
[ignore]
patterns = [
    "target/**",              # Build artifacts
    "node_modules/**",        # Dependencies
    "**/*_test.rs",           # Test files with _test suffix
    "tests/**",               # All test directories
    "**/fixtures/**",         # Test fixtures
    "**/mocks/**",            # Mock implementations
    "**/*.min.js",            # Minified files
    "**/demo/**",             # Demo code
    "**/*.generated.rs",      # Generated files
    "vendor/**",              # Vendor code
    "third_party/**",         # Third-party code
]
```

### Function Name Exclusions (Planned)

> **Note:** Function-level exclusions by name pattern are not yet implemented. This is a planned feature for a future release.

When implemented, you will be able to exclude entire function families by name pattern:

```toml
# Planned feature - not yet available
[ignore.functions]
patterns = [
    # Test setup functions
    "setup_test_*",
    "teardown_test_*",
    "create_test_*",
    "mock_*",

    # Generated code
    "derive_*",
    "__*",                    # Python dunder methods

    # CLI parsing (naturally complex)
    "parse_args",
    "parse_cli",
    "build_cli",

    # Serialization (naturally complex pattern matching)
    "serialize_*",
    "deserialize_*",
    "to_json",
    "from_json",
]
```

**Current workaround:** Use inline suppression comments (`debtmap:ignore`) for specific functions, or use file pattern exclusions to exclude entire test files.

## Glob Pattern Syntax

File patterns use standard glob syntax:

| Pattern | Matches | Example |
|---------|---------|---------|
| `*` | Any characters within a path component | `*.rs` matches `main.rs` |
| `**` | Any directories (recursive) | `tests/**` matches `tests/unit/foo.rs` |
| `?` | Single character | `test?.rs` matches `test1.rs` |
| `[abc]` | Character class | `test[123].rs` matches `test1.rs` |
| `[!abc]` | Negated class | `test[!0].rs` matches `test1.rs` but not `test0.rs` |

### Glob Pattern Examples

```toml
[ignore]
patterns = [
    "src/**/*_generated.rs",  # Generated files in any subdirectory
    "**/test_*.py",           # Python test files anywhere
    "legacy/**/[!i]*.js",     # Legacy JS files not starting with 'i'
    "**/*.min.js",            # Minified JavaScript
    "**/*.min.css",           # Minified CSS
]
```

> **Note:** Brace expansion (e.g., `*.{js,css}`) is not supported. Use separate patterns for each file extension.

## Language-Specific Comment Syntax

Debtmap automatically uses the correct comment syntax for each language:

| Language | Comment Prefix | Example |
|----------|---------------|---------|
| Rust | `//` | `// debtmap:ignore` |
| JavaScript* | `//` | `// debtmap:ignore` |
| TypeScript* | `//` | `// debtmap:ignore` |
| Python | `#` | `# debtmap:ignore` |
| Other languages | `//` | `// debtmap:ignore` |

**Note**: Languages not explicitly listed use `//` as the default comment prefix.

*\*JavaScript and TypeScript*: Debtmap analyzes JS/TS files and recognizes suppression comments using `//` syntax.

You don't need to configure this—Debtmap detects the language and uses the appropriate syntax.

## Explicitly Specified Files

**Important behavior**: When you analyze a specific file directly, ignore patterns are bypassed:

```bash
# Respects [ignore] patterns in .debtmap.toml
debtmap analyze .
debtmap analyze src/

# Bypasses ignore patterns - analyzes the file even if patterns would exclude it
debtmap analyze src/test_helper.rs
```

This ensures you can always analyze specific files when needed, even if they match an ignore pattern.

## Suppression Statistics

Debtmap internally tracks suppression usage during analysis:

- **Total suppressions**: Count of active suppressions across all files
- **Suppressions by type**: How many of each debt type are suppressed
- **Unclosed blocks**: Detection of `ignore-start` without matching `ignore-end`

**Current Status**: These statistics are computed during analysis (via the `SuppressionContext::get_stats()` method) but are not currently displayed in any output format. The `SuppressionStats` struct exists and tracks all metrics, but there is no user-facing command or report format that exposes them. Future releases may add a dedicated command to view suppression metrics.

**Auditing Suppressions Now**: You can audit your suppressions using standard tools:

```bash
# Find all suppressions in Rust code
rg "debtmap:ignore" --type rust

# Count suppressions by type
rg "debtmap:ignore\[" --type rust | grep -o "\[.*\]" | sort | uniq -c

# Find unclosed blocks
rg "debtmap:ignore-start" --type rust -A 100 | grep -v "debtmap:ignore-end"

# List files with suppressions
rg "debtmap:ignore" --files-with-matches
```

## Best Practices

### Use Suppressions Sparingly

Suppressions hide information, so use them intentionally:

✅ **Good use cases:**
- Test fixtures and mock data
- Known technical debt with an accepted timeline
- Intentional complexity for performance
- False positives specific to your domain

❌ **Poor use cases:**
- Hiding all debt to make reports look clean
- Suppressing instead of fixing simple issues
- Using wildcards when specific types would work

### Always Include Reasons

```rust
// ✅ Good: Clear reason and timeline
// debtmap:ignore[complexity] -- Hot path optimization, profiled and necessary
fn fast_algorithm() { }

// ❌ Bad: No context for future maintainers
// debtmap:ignore
fn fast_algorithm() { }
```

### Prefer Specific Over Broad

```rust
// ✅ Good: Only suppress the specific debt type
// debtmap:ignore[todo] -- Remove after v2.0 migration
// TODO: Migrate to new API

// ❌ Bad: Suppresses everything, including real issues
// debtmap:ignore
// TODO: Migrate to new API
```

### Use Config for Systematic Exclusions

For patterns that apply project-wide, use `.debtmap.toml` instead of inline comments:

```toml
# ✅ Good: One config applies to all test files
[ignore]
patterns = ["tests/**"]

# ❌ Bad: Repetitive inline suppressions in every test file
```

### Review Suppressions Periodically

Suppressions can become outdated:

- Remove suppressions when the reason no longer applies
- Check if suppressed debt can now be fixed
- Verify reasons are still accurate after refactoring

**Solution:** Periodically search for suppressions:
```bash
rg "debtmap:ignore" --type rust
```

### Ensure Blocks Are Closed

```rust
// ✅ Good: Properly closed block
// debtmap:ignore-start
fn test_setup() { }
// debtmap:ignore-end

// ❌ Bad: Unclosed block affects all subsequent code
// debtmap:ignore-start
fn test_setup() { }
// (missing ignore-end)
```

Debtmap detects unclosed blocks and can warn you about them.

## Common Patterns

### Suppressing Test Code

```toml
# In .debtmap.toml
[ignore]
patterns = [
    "tests/**/*",
    "**/*_test.rs",
    "**/test_*.py",
    "**/fixtures/**",
]
```

For test functions within production files, use inline suppressions:

```rust
#[cfg(test)]
mod tests {
    // debtmap:ignore-start -- Test code
    fn setup_test_environment() { }
    // debtmap:ignore-end
}
```

### Suppressing Generated Code

```toml
[ignore]
patterns = [
    "**/*_generated.*",
    "**/proto/**",
    "**/bindings/**",
]
```

### Temporary Suppressions with Timeline

```rust
// debtmap:ignore[complexity] -- TODO: Refactor during Q2 2025 sprint
fn legacy_payment_processor() {
    // Complex legacy code scheduled for refactoring
}
```

### Suppressing False Positives

```python
# debtmap:ignore[duplication] -- Similar but semantically different
def calculate_tax_us():
    # US tax calculation
    pass

# debtmap:ignore[duplication] -- Similar but semantically different
def calculate_tax_eu():
    # EU tax calculation with different rules
    pass
```

### Conditional Suppression

```rust
#[cfg(test)]
// debtmap:ignore[complexity]
fn test_helper() {
    // Complex test setup is acceptable
}
```

### Suppression with Detailed Justification

```rust
// debtmap:ignore[complexity] -- Required by specification XYZ-123
// This function implements the state machine defined in spec XYZ-123.
// Complexity is inherent to the specification and cannot be reduced
// without violating requirements.
fn state_machine() { ... }
```

## Troubleshooting

### Suppression Not Working

1. **Check comment syntax**: Ensure you're using the correct comment prefix for your language (`//` for Rust/JS/TS, `#` for Python)
2. **Verify spelling**: It's `debtmap:ignore`, not `debtmap-ignore` or `debtmap_ignore`
3. **Check line matching**: For same-line suppressions, ensure the debt is on the same line as the comment
4. **Verify type names**: Use `todo`, `fixme`, `complexity`, etc. (lowercase)

**Common syntax errors:**
```rust
// Wrong: debtmap: ignore (space after colon)
// Right: debtmap:ignore

// Wrong: debtmap:ignore[Complexity] (capital C)
// Right: debtmap:ignore[complexity]
```

**Check placement:**
```rust
// Wrong: comment after code
fn function() { } // debtmap:ignore

// Right: comment before code
// debtmap:ignore
fn function() { }
```

### Unclosed Block Warning

If you see warnings about unclosed blocks:

```rust
// Problem: Missing ignore-end
// debtmap:ignore-start
fn test_helper() { }
// (Should have debtmap:ignore-end here)

// Solution: Add the closing marker
// debtmap:ignore-start
fn test_helper() { }
// debtmap:ignore-end
```

### File Still Being Analyzed

If a file in your ignore patterns is still being analyzed:

1. Check if you're analyzing the specific file directly (bypasses ignore patterns)
2. Verify the glob pattern matches the file path
3. Check for typos in the pattern
4. Test the pattern in isolation

**Test pattern with find:**
```bash
find . -path "tests/**/*" -type f
```

**Use double asterisk for subdirectories:**
```toml
# Wrong: "tests/*" (only direct children)
# Right: "tests/**/*" (all descendants)
```

**Check relative paths:**
```toml
# Patterns are relative to project root
patterns = [
    "src/legacy/**",  # ✓ Correct
    "/src/legacy/**", # ✗ Wrong (absolute path)
]
```

### Function Suppression Not Working

Function-level exclusions by name pattern are not yet implemented. To suppress specific functions:

1. Use inline suppressions: `// debtmap:ignore` before the function
2. Use block suppressions: `// debtmap:ignore-start` ... `// debtmap:ignore-end`
3. Exclude entire files using `[ignore]` patterns if the functions are in dedicated files

## Related Topics

- [Configuration]configuration.md - Full `.debtmap.toml` reference
- [CLI Reference]cli-reference.md - Command-line analysis options
- [Analysis Guide]analysis-guide/index.md - Understanding debt detection
- [Output Formats]output-formats.md - Viewing suppressed items in reports

## Summary

Suppressions help you focus on actionable technical debt:

- **Inline comments**: `debtmap:ignore`, `ignore-next-line`, `ignore-start/end`
- **Type-specific**: Use `[type1,type2]` to suppress selectively
- **Reasons**: Always use `-- reason` to document why
- **Config patterns**: Use `.debtmap.toml` for systematic file exclusions
- **Best practices**: Use sparingly, prefer specific over broad, review periodically

With proper use of suppressions, your Debtmap reports show only the debt that matters to your team.