# Solidity Support — Remaining Work
This document tracks what is **done**, what is **partially implemented**, and what remains to bring Solidity analysis in debtmap to parity with mature language support (Rust/TypeScript) and the original implementation plan.
**Status as of MVP delivery:** Solidity is usable for single-file and project analysis via `--languages sol`. The analyzer produces `FunctionMetrics`, `FileMetrics`, complexity debt, generic smells, and heuristic security advisories. Everything below builds on that foundation.
---
## Current State Summary
### Implemented
| Language routing | `src/core/mod.rs`, `src/utils/language_parser.rs`, `src/io/walker.rs` | `.sol` extension, CLI aliases `solidity` / `sol` |
| Parser | `src/analyzers/solidity/parser.rs` | `tree-sitter-solidity` 1.2.13, `tree-sitter` 0.25 |
| Analyzer trait | `src/analyzers/solidity/analyzer.rs` | Registered in `get_analyzer()` |
| Complexity | `src/analyzers/solidity/complexity.rs`, `visitor.rs` | Cyclomatic, cognitive, nesting, function length |
| Callable extraction | `src/analyzers/solidity/visitor.rs` | Functions, modifiers, constructor, fallback, receive |
| Generic debt | `src/analyzers/solidity/debt/mod.rs` | Threshold complexity, nesting, length, TODO/FIXME, smells |
| Security advisories | `src/analyzers/solidity/debt/security_patterns.rs` | 11 heuristic patterns (see below) |
| Dependencies | `src/analyzers/solidity/dependencies.rs` | Imports + inheritance (`DependencyKind::Inheritance`) |
| Test detection | `src/analyzers/solidity/test_detection.rs` | Foundry `*.t.sol`, `forge-std/Test.sol` |
| Batch / validation | `src/analyzers/batch.rs`, `src/builders/validated_analysis.rs` | Parse validation wired |
| Config schema | `src/config/languages.rs` | `SolidityLanguageConfig`, `SoliditySecurityConfig` (schema only) |
| LOC counting | `src/metrics/loc_counter.rs` | `LocLanguage::Solidity` |
| Tests | `src/analyzers/solidity/*`, `tests/solidity_analyzer_tests.rs` | 15 unit + 10 integration tests |
| Book docs | `book/src/configuration/languages.md`, etc. | Partial updates |
### Security patterns currently detected
| `tx-origin-usage` | High |
| `unchecked-low-level-call` | High |
| `external-call-before-state-update` | High |
| `delegatecall-usage` | Medium |
| `selfdestruct-usage` | Medium |
| `assembly-block` | Medium |
| `unbounded-loop` | Medium |
| `missing-access-control` | Medium |
| `large-contract` | Medium |
| `hardcoded-address` | Low |
| `floating-pragma` | Low |
All advisories use “review recommended” wording — not formal verification.
---
## Gap Overview
```mermaid
flowchart TB
subgraph done [MVP Complete]
Parse[Parse and route .sol files]
Complexity[Complexity metrics]
GenericDebt[Generic debt]
Heuristics[Security heuristics]
end
subgraph phase1 [Phase 1 — Config and polish]
ConfigWire[Wire config to analyzer]
DocsUX[README init template]
SecurityTests[Security fixture coverage]
end
subgraph phase2 [Phase 2 — Analysis depth]
Entropy[Entropy dampening]
AdvancedDebt[Advanced advisory signals]
Suppression[Suppression verification]
VendorCode[Vendor/generated handling]
end
subgraph phase3 [Phase 3 — Cross-file]
CallGraph[Cross-contract call graph]
ImportResolve[Import path resolution]
ProjectCtx[Project-level Solidity context]
end
subgraph phase4 [Phase 4 — Ecosystem]
NatSpec[NatSpec analysis]
LangSpecific[LanguageSpecificData]
Benchmarks[Parsing benchmarks]
GrammarBump[Grammar version alignment]
end
done --> phase1
phase1 --> phase2
phase2 --> phase3
phase3 --> phase4
```
---
## Phase 1: Config Wiring and User-Facing Polish
**Goal:** Make existing behavior configurable and visible. Low risk, high user value.
### 1.1 Wire `SolidityLanguageConfig` into the analyzer
**Problem:** Config structs exist in [`src/config/languages.rs`](../src/config/languages.rs) but [`SolidityAnalyzer`](../src/analyzers/solidity/analyzer.rs) ignores them. Security checks are always on; `large_contract_threshold` is hardcoded to `20` in [`security_patterns.rs`](../src/analyzers/solidity/debt/security_patterns.rs).
**Tasks:**
1. Add config accessor in [`src/config/accessors.rs`](../src/config/accessors.rs):
```rust
pub fn get_solidity_config() -> SolidityLanguageConfig
```
2. Extend `SolidityAnalyzer` (mirror [`GoAnalyzer`](../src/analyzers/go/analyzer.rs)):
- `with_config(SolidityLanguageConfig)` or load from `get_solidity_config()` in `new()`
- Pass config through `orchestration.rs` → `debt/` → `security_patterns.rs`
3. Gate each security pattern on its config flag:
- Extend `SoliditySecurityConfig` with toggles for **all** patterns (today only 4 flags exist; add the rest or group them logically)
- Respect `detect_complexity`, `detect_duplication`, `detect_dead_code` from flattened `LanguageFeatures`
4. Pass `large_contract_threshold` into `detect_contract_patterns()` instead of literal `20`.
5. Wire batch analysis in [`src/analyzers/batch.rs`](../src/analyzers/batch.rs):
- Add `solidity_config_from_debtmap(config)` similar to `go_generated_code_mode()`
- Optionally pass global complexity threshold from `DebtmapConfig` (today hardcoded default `10`)
**Files to touch:**
- `src/config/accessors.rs`
- `src/analyzers/solidity/analyzer.rs`
- `src/analyzers/solidity/orchestration.rs`
- `src/analyzers/solidity/debt/mod.rs`
- `src/analyzers/solidity/debt/security_patterns.rs`
- `src/analyzers/batch.rs`
- `src/config/languages.rs` (expand `SoliditySecurityConfig` if needed)
**Tests:**
- Config disables `tx_origin` → no `tx-origin-usage` debt
- `large_contract_threshold = 5` triggers advisory on smaller contract
- Config test in `src/config/mod.rs` (follow Go config test pattern)
**Estimated effort:** 1–2 days
---
### 1.2 README and init template
**Problem:** User-facing entry points still list five languages.
**Tasks:**
1. Update [`README.md`](../README.md):
- Supported languages list
- Example: `debtmap analyze ./contracts --languages sol`
- Roadmap checkbox for Solidity
2. Update [`src/commands/init.rs`](../src/commands/init.rs) default template:
```toml
enabled = ["rust", "python", "solidity"]
# or include all six — decide product default
[languages.solidity]
detect_complexity = true
```
3. Align [`book/src/configuration/languages.md`](../book/src/configuration/languages.md) — ensure all `enabled` examples include `solidity` consistently.
**Estimated effort:** 0.5 day
---
### 1.3 Security pattern test coverage
**Problem:** Only `tx-origin-usage` has a dedicated positive test. Plan called for positive + negative fixture per pattern.
**Tasks:**
1. Expand `tests/fixtures/solidity/security/`:
```
security/
├── tx_origin_positive.sol / tx_origin_negative.sol
├── unchecked_call_positive.sol / unchecked_call_negative.sol
├── reentrancy_positive.sol / reentrancy_negative.sol
├── assembly_positive.sol / assembly_negative.sol
├── access_control_positive.sol / access_control_negative.sol
└── ...
```
2. Add parametrized integration tests in `tests/solidity_analyzer_tests.rs` asserting pattern presence/absence.
3. Add unit tests in `security_patterns.rs` for edge cases (nested assembly, `require` wrapping calls, etc.).
**Estimated effort:** 1–2 days
---
## Phase 2: Analysis Depth
**Goal:** Reduce false positives and add signals comparable to Go’s `advanced.rs`.
### 2.1 Entropy dampening
**Problem:** Repetitive Solidity patterns (similar `require` chains, boilerplate ERC hooks) inflate cognitive scores. Rust/JS/TS use [`LanguageEntropyAnalyzer`](../src/complexity/entropy_core.rs).
**Tasks:**
1. Create `src/analyzers/solidity/entropy/`:
- `token.rs` — `SolidityEntropyToken` implementing `EntropyToken`
- `analyzer.rs` — `SolidityEntropyAnalyzer` implementing `LanguageEntropyAnalyzer`
- Classify: keywords, identifiers, literals, operators, `require`/`assert`/`revert`
2. Integrate in `visitor.rs` / `metrics.rs`:
- Populate `FunctionMetrics.entropy_analysis`, `entropy_score`, `adjusted_complexity`
3. Follow [`src/analyzers/typescript/entropy/`](../src/analyzers/typescript/entropy/) as template (tree-sitter token walk).
**Tests:** Property tests for dampening on repetitive require chains vs genuinely complex control flow.
**Estimated effort:** 3–5 days
---
### 2.2 Advanced advisory signals (`advanced.rs`)
**Problem:** Go detects swallowed errors, goroutines, defer-in-loop, etc. Solidity lacks equivalent depth.
**Candidate signals:**
| `unchecked-arithmetic` | Pre-0.8.0 style or missing `SafeMath`/checked blocks |
| `unsafe-erc20-transfer` | `transfer`/`transferFrom` without return check (non-standard tokens) |
| `push-without-length-cap` | `.push()` in loop without max length |
| `self-assign-reentrancy` | State read after external call in same function |
| `block-timestamp-dependency` | `block.timestamp` in critical logic |
| `tx-gas-price-dependency` | `tx.gasprice` usage |
| `encode-packed-collision` | `abi.encodePacked` with dynamic types |
| `delegatecall-in-constructor` | Proxy misconfiguration heuristic |
**Tasks:**
1. Add `src/analyzers/solidity/advanced.rs` with pure detection functions
2. Merge patterns into `SolidityFunction.advisory_patterns` in visitor
3. Map to debt items in `debt/mod.rs` (reuse Go advisory pattern)
**Estimated effort:** 3–4 days
---
### 2.3 Suppression support verification
**Problem:** [`get_comment_prefix_pattern`](../src/debt/suppression.rs) maps unknown languages to `//`, which should work for Solidity — but this is **untested**.
**Tasks:**
1. Add suppression tests with `Language::Solidity` and `// debtmap:ignore` comments
2. Verify block and line suppressions filter complexity/security debt correctly
3. Document Solidity suppression syntax in book
**Estimated effort:** 0.5–1 day
---
### 2.4 Vendor and generated contract handling
**Problem:** Go suppresses `*.pb.go`, mockgen output. Solidity projects include OpenZeppelin, Foundry `out/`, Hardhat `artifacts/`.
**Tasks:**
1. Add `src/analyzers/solidity/generated.rs`:
- Detect `@openzeppelin/contracts` imports-only vendor files (optional exclude)
- Skip `out/`, `cache/`, `artifacts/`, `node_modules/` via existing walker ignore patterns
- SPDX + “Automatically generated” header detection
2. Optional config (mirror Go):
```toml
[languages.solidity]
vendor_code = "suppress_debt" # analyze | suppress_debt | exclude
```
3. Update default ignore patterns in config if not already covering Foundry/Hardhat dirs.
**Estimated effort:** 1–2 days
---
### 2.5 Hardhat test detection
**Problem:** Only Foundry tests are detected (`*.t.sol`, `forge-std`).
**Tasks:**
1. Extend `test_detection.rs`:
- `@nomicfoundation/hardhat-chai-matchers` / `hardhat` import paths
- File naming: `*.test.sol` convention (if used)
- `contract.*Test` naming (already partial via `is_test_contract_name`)
2. Add fixtures and tests.
**Estimated effort:** 0.5 day
---
### 2.6 Heuristic quality improvements
**Problem:** Current security detectors are intentionally simple and produce false positives/negatives.
**Priority refinements:**
| `external-call-before-state-update` | Flat statement order scan | Walk AST for CEI ordering; distinguish `transfer` vs internal calls |
| `unchecked-low-level-call` | Parent text `require` check | Detect `(bool success, )` destructuring and `if (!success)` |
| `missing-access-control` | String search for `onlyOwner` | Parse modifier list; detect `_checkOwner()`-style internal guards |
| `unbounded-loop` | Crude array-length heuristic | Track `storage` array `.length` vs calldata with explicit bounds |
| `hardcoded-address` | Token split | Regex with word boundaries; exclude common constants |
**Tasks:** Incremental PRs per pattern with fixture-driven tests.
**Estimated effort:** 2–4 days (ongoing)
---
## Phase 3: Cross-File and Project-Level Analysis
**Goal:** Enable architectural insights across a Solidity codebase.
### 3.1 Import path resolution
**Problem:** [`dependencies.rs`](../src/analyzers/solidity/dependencies.rs) records raw import strings (`"./Token.sol"`) but does not resolve to project files.
**Tasks:**
1. Build remapping support:
- Foundry `remappings.txt`
- Hardhat config paths (lower priority)
2. Resolve import paths to absolute project paths for dependency graph.
3. Feed resolved graph into [`src/debt/circular.rs`](../src/debt/circular.rs).
**Estimated effort:** 3–5 days
---
### 3.2 Cross-contract call graph
**Problem:** `FunctionMetrics.call_dependencies` contains raw call text (`token.transfer`) with no cross-file linking.
**Tasks:**
1. Add `src/analyzers/solidity/call_graph.rs`:
- Parse `call_expression`, `member_expression` with type hints where possible
- Link interface calls (`IERC20(token).transfer`) to imported symbols
2. Integrate with existing [`call_graph/`](../src/analyzers/call_graph/) infrastructure or add Solidity-specific project pass (like Go cross-file resolution in `batch.rs`).
3. Emit `upstream_callers` / `downstream_callees` on `FunctionMetrics`.
**Estimated effort:** 5–8 days
---
### 3.3 Contract-level project metrics
**Tasks:**
1. Populate `FileMetrics.classes` with richer `ClassDef` (method list, line numbers, abstract/interface flag)
2. Project-level aggregation: contracts per file, inheritance depth, external call surface
3. Optional: proxy pattern detection (EIP-1967 slot, `delegatecall` in constructor)
**Estimated effort:** 2–3 days
---
## Phase 4: Extended Features and Infrastructure
### 4.1 NatSpec / documentation debt
**Tasks:**
1. Parse `/// @notice`, `@dev`, `@param` NatSpec blocks (text-level or tree-sitter comment nodes)
2. Debt types:
- Missing NatSpec on public/external functions
- Empty or placeholder `@notice`
- Mismatch between `@param` count and function signature
**Estimated effort:** 2–3 days
---
### 4.2 `LanguageSpecificData::Solidity(...)`
**Problem:** [`FunctionMetrics.language_specific`](../src/core/mod.rs) only has a Rust variant today.
**Tasks:**
1. Define `SolidityPatternResult` (proxy usage, upgradeable pattern, payable functions, state mutability)
2. Add enum variant and serialization tests
3. Surface in JSON/TUI output
**Estimated effort:** 1–2 days
---
### 4.3 Purity analysis (EVM-aware)
**Problem:** Deferred from MVP. Solidity “pure/view/payable” mutability exists at language level but debtmap does not use it.
**Tasks:**
1. Extract state mutability from function definition nodes
2. Detect state writes (`SSTORE` heuristic via assignment to state variables)
3. Classify `PurityLevel` for Solidity functions (ReadOnly for `view`, etc.)
4. Flag `nonReentrant` modifier absence on state-changing external calls (optional)
**Estimated effort:** 3–4 days
---
### 4.4 Single-pass extraction layer
**Problem:** Rust uses [`UnifiedFileExtractor`](../src/extraction/extractor.rs) to avoid re-parsing. Solidity re-walks the tree in visitor + debt + dependencies.
**Tasks:**
1. Add `src/extraction/solidity.rs` — one walk producing `ExtractedFileData`
2. Adapter in `src/extraction/adapters/` → `FileMetrics`
3. Benchmark parse+analyze time before/after
**Estimated effort:** 3–5 days (optimization, not blocking)
---
### 4.5 Parsing benchmarks
**Tasks:**
1. Add `benches/solidity_parsing_bench.rs` (criterion)
2. Fixtures: small contract, Uniswap-style size, deeply nested control flow
3. CI threshold or tracking only (no hard gate initially)
**Estimated effort:** 0.5–1 day
---
### 4.6 Tree-sitter grammar alignment
**Problem:** Core bumped to `tree-sitter 0.25` for Solidity ABI 15; other grammars remain on `0.23`.
**Tasks:**
1. Evaluate bumping `tree-sitter-javascript`, `tree-sitter-python`, `tree-sitter-go`, `tree-sitter-typescript` to 0.25-compatible versions
2. Run full test suite + parser smoke tests
3. Pin exact versions in `Cargo.toml`
**Risk:** ABI breakage across grammars. Do as dedicated PR with rollback plan.
**Estimated effort:** 1–2 days
**Completed alignment:**
- Pinned the runtime to `tree-sitter` 0.25.10 and the grammars to JavaScript
0.25.0, TypeScript 0.23.2, Python 0.25.0, Go 0.25.0, and Solidity 1.2.13.
- TypeScript 0.23.2 remains the latest published crate. Its ABI 14 grammar is
compatible with the runtime's ABI 13–15 window; the other grammars use ABI 15.
- Kept the runtime on 0.25.10 because 0.26 changes Rust APIs without expanding
the grammar ABI window needed by debtmap.
- Rollback is limited to restoring JavaScript 0.23.1, Python 0.23.6, and Go
0.23.4 in the manifest and lockfile. The 0.25.10 runtime and Solidity pin must
remain together because Solidity requires ABI 15.
---
### 4.7 External tool integration (optional, long-term)
| Slither | Feature flag to merge Slither JSON detectors into `DebtItem` |
| Mythril | Post-process symbolic findings |
| Foundry coverage | LCOV from `forge coverage` for risk scoring |
**Not recommended until core heuristics stabilize** — avoids duplicate/conflicting signals.
**Estimated effort:** 5+ days each
---
## Phase 5: AST and Pattern Extraction Gaps
### 5.1 `Ast::Solidity` node extraction
**Problem:** [`Ast::extract_nodes()`](../src/core/ast.rs) returns `vec![]` for Solidity — pattern/design extraction pipeline skips `.sol` files.
**Tasks:**
1. Implement `extract_solidity_nodes()` mapping contracts → `NodeKind::Class`, functions → `NodeKind::Function`
2. Enable architectural analysis stages that consume `AstNode` trees
**Estimated effort:** 1–2 days
---
## Recommended PR Sequence
Split work into reviewable PRs:
| **PR A** | Config wiring + security toggles + threshold | — |
| **PR B** | README, init template, book polish | — |
| **PR C** | Security fixture suite (all patterns) | — |
| **PR D** | Suppression tests for Solidity | — |
| **PR E** | Entropy dampening | — |
| **PR F** | Advanced advisory signals | PR C |
| **PR G** | Heuristic refinements (batch 1: reentrancy, unchecked calls) | PR C |
| **PR H** | Vendor/generated code handling | PR A |
| **PR I** | Import remapping + circular deps | — |
| **PR J** | Cross-contract call graph | PR I |
| **PR K** | NatSpec debt | — |
| **PR L** | `LanguageSpecificData`, mutability/purity | PR E |
| **PR M** | tree-sitter 0.25 grammar alignment | — |
| **PR N** | Benchmarks + extraction optimization | PR M |
PRs A–D can land in parallel. PR J depends on import resolution (PR I).
---
## Quality Gates (per PR)
Every Solidity PR should satisfy:
```bash
just fmt
cargo test --lib analyzers::solidity
cargo test --test solidity_analyzer_tests
cargo test --test language_tests
```
Before merge to main:
```bash
just test # full suite
```
Add clippy clean for touched modules.
---
## Risk Register
| `tree-sitter-solidity` AST instability | Pin exact version; parser regression tests on upgrade |
| Security heuristic false positives | Config opt-out per pattern; conservative defaults; clear advisory wording |
| Cross-file resolution complexity | Start with Foundry remappings only; defer Hardhat |
| Entropy token classifier accuracy | Property tests; compare adjusted scores on real fixtures |
| Grammar bump breaks JS/Python/Go | Dedicated PR, multi-platform CI, pin all grammars together |
---
## Definition of Done (Full Solidity Support)
Solidity support is **feature-complete** (beyond MVP) when:
- [ ] All config in `debtmap.toml` is honored at runtime
- [ ] Entropy dampening active for Solidity functions
- [ ] All 11+ security patterns have positive/negative fixture tests
- [ ] Suppression comments verified for `.sol` files
- [ ] Import remapping resolves dependencies for Foundry projects
- [ ] Cross-contract call graph populated on project analysis
- [ ] README and init template list Solidity
- [ ] NatSpec missing-docs detection on public/external functions
- [x] No known parser ABI mismatches across tree-sitter grammars
---
## Out of Scope (Explicit)
- Formal verification or symbolic execution
- Replacing Slither/Mythril/Foundry built-in linters
- Yul-only files (`.yul`) — separate grammar would be needed
- Vyper support — separate language module
- On-chain bytecode analysis
---
## References
- MVP implementation: `src/analyzers/solidity/`
- Original plan: `.cursor/plans/add_solidity_support_*.plan.md` (Cursor plan artifact)
- Go analyzer template: `src/analyzers/go/`
- TypeScript entropy template: `src/analyzers/typescript/entropy/`
- Config schema: `src/config/languages.rs`
- Integration tests: `tests/solidity_analyzer_tests.rs`
- Fixtures: `tests/fixtures/solidity/`