#
tokens: 49659/50000 54/1140 files (page 5/94)
lines: off (toggle) GitHub
raw markdown copy
This is page 5 of 94. Use http://codebase.md/cyfrin/aderyn?page={x} to view the full context.

# Directory Structure

```
├── .cargo
│   └── config.toml
├── .git-blame-ignore-revs
├── .gitattributes
├── .github
│   ├── images
│   │   ├── aderyn_logo.png
│   │   ├── poweredbycyfrinblack.png
│   │   └── poweredbycyfrinblue.png
│   ├── ISSUE_TEMPLATE
│   │   ├── bug_report.md
│   │   ├── false_positive_issue.md
│   │   └── feature_request.md
│   └── workflows
│       ├── cargo.yml
│       ├── dependencies.yml
│       ├── release.yml
│       ├── reports.yml
│       └── toml.yml
├── .gitignore
├── .gitmodules
├── .vscode
│   └── settings.json
├── aderyn
│   ├── Cargo.toml
│   ├── oranda.json
│   ├── README.md
│   ├── src
│   │   ├── birdsong.rs
│   │   ├── completions.rs
│   │   ├── lib.rs
│   │   ├── lsp.rs
│   │   ├── main.rs
│   │   ├── mcp.rs
│   │   └── panic.rs
│   └── templates
│       └── aderyn.toml
├── aderyn_core
│   ├── .gitignore
│   ├── Cargo.toml
│   ├── README.md
│   ├── src
│   │   ├── ast
│   │   │   ├── ast_nodes.rs
│   │   │   ├── ast.rs
│   │   │   ├── impls
│   │   │   │   ├── ctx
│   │   │   │   │   ├── utils.rs
│   │   │   │   │   └── workspace.rs
│   │   │   │   ├── ctx.rs
│   │   │   │   ├── disp
│   │   │   │   │   ├── blocks.rs
│   │   │   │   │   ├── contracts.rs
│   │   │   │   │   ├── enumerations.rs
│   │   │   │   │   ├── errors.rs
│   │   │   │   │   ├── events.rs
│   │   │   │   │   ├── expressions.rs
│   │   │   │   │   ├── functions.rs
│   │   │   │   │   ├── identifiers.rs
│   │   │   │   │   ├── literals.rs
│   │   │   │   │   ├── modifiers.rs
│   │   │   │   │   ├── statements.rs
│   │   │   │   │   ├── structures.rs
│   │   │   │   │   ├── types.rs
│   │   │   │   │   ├── user_defined_value_types.rs
│   │   │   │   │   ├── using_for_directives.rs
│   │   │   │   │   └── variables.rs
│   │   │   │   ├── disp.rs
│   │   │   │   ├── node
│   │   │   │   │   ├── blocks.rs
│   │   │   │   │   ├── contracts.rs
│   │   │   │   │   ├── documentation.rs
│   │   │   │   │   ├── enumerations.rs
│   │   │   │   │   ├── errors.rs
│   │   │   │   │   ├── events.rs
│   │   │   │   │   ├── expressions.rs
│   │   │   │   │   ├── functions.rs
│   │   │   │   │   ├── identifiers.rs
│   │   │   │   │   ├── import_directives.rs
│   │   │   │   │   ├── literals.rs
│   │   │   │   │   ├── modifiers.rs
│   │   │   │   │   ├── pragma_directives.rs
│   │   │   │   │   ├── source_units.rs
│   │   │   │   │   ├── statements.rs
│   │   │   │   │   ├── structures.rs
│   │   │   │   │   ├── types.rs
│   │   │   │   │   ├── user_defined_value_types.rs
│   │   │   │   │   ├── using_for_directives.rs
│   │   │   │   │   └── variables.rs
│   │   │   │   ├── node.rs
│   │   │   │   ├── own
│   │   │   │   │   ├── hashing.rs
│   │   │   │   │   ├── node_id.rs
│   │   │   │   │   ├── source_units.rs
│   │   │   │   │   └── utils.rs
│   │   │   │   └── own.rs
│   │   │   ├── impls.rs
│   │   │   ├── macros.rs
│   │   │   ├── magic.rs
│   │   │   ├── node_type.rs
│   │   │   └── yul.rs
│   │   ├── ast.rs
│   │   ├── audit
│   │   │   ├── attack_surface.rs
│   │   │   ├── auditor.rs
│   │   │   ├── entrypoint.rs
│   │   │   └── public_functions_no_sender.rs
│   │   ├── audit.rs
│   │   ├── context
│   │   │   ├── browser
│   │   │   │   ├── ancestral_line.rs
│   │   │   │   ├── closest_ancestor.rs
│   │   │   │   ├── external_calls.rs
│   │   │   │   ├── extractor.rs
│   │   │   │   ├── immediate_children.rs
│   │   │   │   ├── location.rs
│   │   │   │   ├── macros.rs
│   │   │   │   ├── parent.rs
│   │   │   │   ├── peek_over.rs
│   │   │   │   ├── peek_under.rs
│   │   │   │   ├── peek.rs
│   │   │   │   ├── siblings.rs
│   │   │   │   ├── sort_nodes.rs
│   │   │   │   └── storage_vars.rs
│   │   │   ├── browser.rs
│   │   │   ├── capturable.rs
│   │   │   ├── flow
│   │   │   │   ├── display.rs
│   │   │   │   ├── error.rs
│   │   │   │   ├── kind.rs
│   │   │   │   ├── primitives.rs
│   │   │   │   ├── reducibles.rs
│   │   │   │   ├── tests.rs
│   │   │   │   ├── utils.rs
│   │   │   │   ├── visualizer.rs
│   │   │   │   └── voids.rs
│   │   │   ├── flow.rs
│   │   │   ├── graph
│   │   │   │   ├── callgraph
│   │   │   │   │   ├── legacy.rs
│   │   │   │   │   ├── new.rs
│   │   │   │   │   ├── tests.rs
│   │   │   │   │   ├── utils.rs
│   │   │   │   │   └── visit.rs
│   │   │   │   ├── callgraph.rs
│   │   │   │   ├── preprocess
│   │   │   │   │   ├── legacy.rs
│   │   │   │   │   └── new.rs
│   │   │   │   ├── preprocess.rs
│   │   │   │   ├── traits.rs
│   │   │   │   └── utils.rs
│   │   │   ├── graph.rs
│   │   │   ├── macros.rs
│   │   │   ├── mcp
│   │   │   │   ├── callgraph
│   │   │   │   │   ├── render.rs
│   │   │   │   │   ├── tool.rs
│   │   │   │   │   └── utils.rs
│   │   │   │   ├── callgraph.rs
│   │   │   │   ├── contract_surface
│   │   │   │   │   ├── render.rs
│   │   │   │   │   ├── tool.rs
│   │   │   │   │   └── util.rs
│   │   │   │   ├── contract_surface.rs
│   │   │   │   ├── list_contracts
│   │   │   │   │   ├── render.rs
│   │   │   │   │   └── tool.rs
│   │   │   │   ├── list_contracts.rs
│   │   │   │   ├── node_finder
│   │   │   │   │   ├── render.rs
│   │   │   │   │   ├── tool.rs
│   │   │   │   │   └── utils.rs
│   │   │   │   ├── node_finder.rs
│   │   │   │   ├── node_summarizer
│   │   │   │   │   ├── render.rs
│   │   │   │   │   ├── tool.rs
│   │   │   │   │   └── utils.rs
│   │   │   │   ├── node_summarizer.rs
│   │   │   │   ├── project_overview
│   │   │   │   │   ├── render.rs
│   │   │   │   │   └── tool.rs
│   │   │   │   ├── project_overview.rs
│   │   │   │   ├── tool_guide
│   │   │   │   │   └── tool.rs
│   │   │   │   └── tool_guide.rs
│   │   │   ├── mcp.rs
│   │   │   ├── router
│   │   │   │   ├── external_calls.rs
│   │   │   │   ├── internal_calls.rs
│   │   │   │   ├── modifier_calls.rs
│   │   │   │   └── tests.rs
│   │   │   ├── router.rs
│   │   │   └── workspace.rs
│   │   ├── context.rs
│   │   ├── detect
│   │   │   ├── detector.rs
│   │   │   ├── entrypoint.rs
│   │   │   ├── helpers.rs
│   │   │   ├── high
│   │   │   │   ├── _template.rs
│   │   │   │   ├── abi_encode_packed_hash_collision.rs
│   │   │   │   ├── arbitrary_transfer_from.rs
│   │   │   │   ├── const_func_changes_state.rs
│   │   │   │   ├── contract_locks_ether.rs
│   │   │   │   ├── dangerous_unary_operator.rs
│   │   │   │   ├── delegate_call_unchecked_address.rs
│   │   │   │   ├── delete_nested_mapping.rs
│   │   │   │   ├── dynamic_array_length_assignment.rs
│   │   │   │   ├── enumerable_loop_removal.rs
│   │   │   │   ├── eth_send_unchecked_address.rs
│   │   │   │   ├── experimental_encoder.rs
│   │   │   │   ├── function_selector_collision.rs
│   │   │   │   ├── incorrect_caret_operator.rs
│   │   │   │   ├── incorrect_erc20_interface.rs
│   │   │   │   ├── incorrect_erc721_interface.rs
│   │   │   │   ├── incorrect_shift_order.rs
│   │   │   │   ├── misused_boolean.rs
│   │   │   │   ├── msg_value_in_loops.rs
│   │   │   │   ├── multiple_constructors.rs
│   │   │   │   ├── nested_struct_in_mapping.rs
│   │   │   │   ├── out_of_order_retryable.rs
│   │   │   │   ├── pre_declared_variable_usage.rs
│   │   │   │   ├── reentrancy_state_change.rs
│   │   │   │   ├── reused_contract_name.rs
│   │   │   │   ├── rtlo.rs
│   │   │   │   ├── selfdestruct.rs
│   │   │   │   ├── signed_integer_storage_array.rs
│   │   │   │   ├── state_variable_shadowing.rs
│   │   │   │   ├── storage_array_memory_edit.rs
│   │   │   │   ├── strict_equality_contract_balance.rs
│   │   │   │   ├── tautological_compare.rs
│   │   │   │   ├── tautology_or_contradiction.rs
│   │   │   │   ├── tx_origin_used_for_auth.rs
│   │   │   │   ├── unchecked_low_level_call.rs
│   │   │   │   ├── unchecked_send.rs
│   │   │   │   ├── unprotected_initializer.rs
│   │   │   │   ├── unsafe_casting.rs
│   │   │   │   ├── weak_randomness.rs
│   │   │   │   └── yul_return.rs
│   │   │   ├── high.rs
│   │   │   ├── low
│   │   │   │   ├── _template.rs
│   │   │   │   ├── assert_state_change.rs
│   │   │   │   ├── block_timestamp_deadline.rs
│   │   │   │   ├── boolean_equality.rs
│   │   │   │   ├── builtin_symbol_shadowing.rs
│   │   │   │   ├── centralization_risk.rs
│   │   │   │   ├── constant_function_contains_assembly.rs
│   │   │   │   ├── costly_loop.rs
│   │   │   │   ├── dead_code.rs
│   │   │   │   ├── delegatecall_in_loop.rs
│   │   │   │   ├── deprecated_oz_function.rs
│   │   │   │   ├── division_before_multiplication.rs
│   │   │   │   ├── ecrecover.rs
│   │   │   │   ├── empty_block.rs
│   │   │   │   ├── empty_require_revert.rs
│   │   │   │   ├── function_initializing_state.rs
│   │   │   │   ├── function_pointer_in_constructor.rs
│   │   │   │   ├── inconsistent_type_names.rs
│   │   │   │   ├── incorrect_modifier.rs
│   │   │   │   ├── internal_function_used_once.rs
│   │   │   │   ├── large_numeric_literal.rs
│   │   │   │   ├── literal_instead_of_constant.rs
│   │   │   │   ├── local_variable_shadowing.rs
│   │   │   │   ├── missing_inheritance.rs
│   │   │   │   ├── modifier_used_only_once.rs
│   │   │   │   ├── multiple_placeholders.rs
│   │   │   │   ├── non_reentrant_not_first.rs
│   │   │   │   ├── push_0_opcode.rs
│   │   │   │   ├── redundant_statement.rs
│   │   │   │   ├── require_revert_in_loop.rs
│   │   │   │   ├── return_bomb.rs
│   │   │   │   ├── solmate_safe_transfer_lib.rs
│   │   │   │   ├── state_change_without_event.rs
│   │   │   │   ├── state_no_address_check.rs
│   │   │   │   ├── state_variable_could_be_constant.rs
│   │   │   │   ├── state_variable_could_be_immutable.rs
│   │   │   │   ├── state_variable_read_external.rs
│   │   │   │   ├── storage_array_length_not_cached.rs
│   │   │   │   ├── todo.rs
│   │   │   │   ├── unchecked_return.rs
│   │   │   │   ├── uninitialized_local_variable.rs
│   │   │   │   ├── unsafe_erc20_operation.rs
│   │   │   │   ├── unsafe_oz_erc721_mint.rs
│   │   │   │   ├── unspecific_solidity_pragma.rs
│   │   │   │   ├── unused_error.rs
│   │   │   │   ├── unused_import.rs
│   │   │   │   ├── unused_public_function.rs
│   │   │   │   ├── unused_state_variable.rs
│   │   │   │   └── void_constructor.rs
│   │   │   ├── low.rs
│   │   │   └── test_utils.rs
│   │   ├── detect.rs
│   │   ├── lib.rs
│   │   ├── stats
│   │   │   ├── cloc.rs
│   │   │   ├── dbg_tips.txt
│   │   │   ├── ignore.rs
│   │   │   ├── token.rs
│   │   │   └── util.rs
│   │   ├── stats.rs
│   │   ├── test_utils
│   │   │   └── load_source_unit.rs
│   │   ├── test_utils.rs
│   │   ├── visitor
│   │   │   ├── ast_visitor.rs
│   │   │   ├── macros.rs
│   │   │   └── workspace_visitor.rs
│   │   └── visitor.rs
│   ├── templates
│   │   └── mcp-tool-response
│   │       ├── callgraph.md
│   │       ├── contract_surface.md
│   │       ├── list_contracts.md
│   │       ├── node_finder_get_all.md
│   │       ├── node_finder_grep.md
│   │       ├── node_finder_search.md
│   │       ├── node_summarizer.md
│   │       ├── project_overview.md
│   │       └── tool_guide.md
│   └── tests
│       ├── common
│       │   ├── ancestral_line.rs
│       │   ├── closest_ancestor.rs
│       │   ├── immediate_children.rs
│       │   ├── immediate_parent.rs
│       │   ├── mod.rs
│       │   ├── new_ast_nodes.rs
│       │   ├── peek_over.rs
│       │   └── sibling.rs
│       └── traversal.rs
├── aderyn_driver
│   ├── .gitignore
│   ├── benches
│   │   └── detectors.rs
│   ├── Cargo.toml
│   ├── README.md
│   ├── src
│   │   ├── compile.rs
│   │   ├── config.rs
│   │   ├── display.rs
│   │   ├── driver.rs
│   │   ├── interface
│   │   │   ├── json.rs
│   │   │   ├── lsp.rs
│   │   │   ├── markdown.rs
│   │   │   ├── mod.rs
│   │   │   ├── sarif.rs
│   │   │   ├── tables.rs
│   │   │   └── util.rs
│   │   ├── lib.rs
│   │   ├── mcp.rs
│   │   ├── process.rs
│   │   └── runner.rs
│   └── tests
│       └── astgen.rs
├── bacon.toml
├── benchmarks
│   ├── aderyn
│   │   ├── base
│   │   │   ├── benchmark.json
│   │   │   ├── estimates.json
│   │   │   ├── sample.json
│   │   │   └── tukey.json
│   │   ├── change
│   │   │   └── estimates.json
│   │   ├── new
│   │   │   ├── benchmark.json
│   │   │   ├── estimates.json
│   │   │   ├── sample.json
│   │   │   └── tukey.json
│   │   └── report
│   │       ├── both
│   │       │   ├── iteration_times.svg
│   │       │   └── pdf.svg
│   │       ├── change
│   │       │   ├── mean.svg
│   │       │   ├── median.svg
│   │       │   └── t-test.svg
│   │       ├── index.html
│   │       ├── iteration_times_small.svg
│   │       ├── iteration_times.svg
│   │       ├── MAD.svg
│   │       ├── mean.svg
│   │       ├── median.svg
│   │       ├── pdf_small.svg
│   │       ├── pdf.svg
│   │       ├── relative_iteration_times_small.svg
│   │       ├── relative_pdf_small.svg
│   │       ├── SD.svg
│   │       └── typical.svg
│   ├── arbitrary-transfer-from
│   │   ├── base
│   │   │   ├── benchmark.json
│   │   │   ├── estimates.json
│   │   │   ├── sample.json
│   │   │   └── tukey.json
│   │   ├── change
│   │   │   └── estimates.json
│   │   ├── new
│   │   │   ├── benchmark.json
│   │   │   ├── estimates.json
│   │   │   ├── sample.json
│   │   │   └── tukey.json
│   │   └── report
│   │       ├── both
│   │       │   ├── pdf.svg
│   │       │   └── regression.svg
│   │       ├── change
│   │       │   ├── mean.svg
│   │       │   ├── median.svg
│   │       │   └── t-test.svg
│   │       ├── index.html
│   │       ├── MAD.svg
│   │       ├── mean.svg
│   │       ├── median.svg
│   │       ├── pdf_small.svg
│   │       ├── pdf.svg
│   │       ├── regression_small.svg
│   │       ├── regression.svg
│   │       ├── relative_pdf_small.svg
│   │       ├── relative_regression_small.svg
│   │       ├── SD.svg
│   │       ├── slope.svg
│   │       └── typical.svg
│   ├── avoid-abi-encode-packed
│   │   ├── base
│   │   │   ├── benchmark.json
│   │   │   ├── estimates.json
│   │   │   ├── sample.json
│   │   │   └── tukey.json
│   │   ├── change
│   │   │   └── estimates.json
│   │   ├── new
│   │   │   ├── benchmark.json
│   │   │   ├── estimates.json
│   │   │   ├── sample.json
│   │   │   └── tukey.json
│   │   └── report
│   │       ├── both
│   │       │   ├── pdf.svg
│   │       │   └── regression.svg
│   │       ├── change
│   │       │   ├── mean.svg
│   │       │   ├── median.svg
│   │       │   └── t-test.svg
│   │       ├── index.html
│   │       ├── MAD.svg
│   │       ├── mean.svg
│   │       ├── median.svg
│   │       ├── pdf_small.svg
│   │       ├── pdf.svg
│   │       ├── regression_small.svg
│   │       ├── regression.svg
│   │       ├── relative_pdf_small.svg
│   │       ├── relative_regression_small.svg
│   │       ├── SD.svg
│   │       ├── slope.svg
│   │       └── typical.svg
│   ├── block-timestamp-deadline
│   │   ├── base
│   │   │   ├── benchmark.json
│   │   │   ├── estimates.json
│   │   │   ├── sample.json
│   │   │   └── tukey.json
│   │   ├── change
│   │   │   └── estimates.json
│   │   ├── new
│   │   │   ├── benchmark.json
│   │   │   ├── estimates.json
│   │   │   ├── sample.json
│   │   │   └── tukey.json
│   │   └── report
│   │       ├── both
│   │       │   ├── pdf.svg
│   │       │   └── regression.svg
│   │       ├── change
│   │       │   ├── mean.svg
│   │       │   ├── median.svg
│   │       │   └── t-test.svg
│   │       ├── index.html
│   │       ├── MAD.svg
│   │       ├── mean.svg
│   │       ├── median.svg
│   │       ├── pdf_small.svg
│   │       ├── pdf.svg
│   │       ├── regression_small.svg
│   │       ├── regression.svg
│   │       ├── relative_pdf_small.svg
│   │       ├── relative_regression_small.svg
│   │       ├── SD.svg
│   │       ├── slope.svg
│   │       └── typical.svg
│   ├── centralization-risk
│   │   ├── base
│   │   │   ├── benchmark.json
│   │   │   ├── estimates.json
│   │   │   ├── sample.json
│   │   │   └── tukey.json
│   │   ├── change
│   │   │   └── estimates.json
│   │   ├── new
│   │   │   ├── benchmark.json
│   │   │   ├── estimates.json
│   │   │   ├── sample.json
│   │   │   └── tukey.json
│   │   └── report
│   │       ├── both
│   │       │   ├── pdf.svg
│   │       │   └── regression.svg
│   │       ├── change
│   │       │   ├── mean.svg
│   │       │   ├── median.svg
│   │       │   └── t-test.svg
│   │       ├── index.html
│   │       ├── MAD.svg
│   │       ├── mean.svg
│   │       ├── median.svg
│   │       ├── pdf_small.svg
│   │       ├── pdf.svg
│   │       ├── regression_small.svg
│   │       ├── regression.svg
│   │       ├── relative_pdf_small.svg
│   │       ├── relative_regression_small.svg
│   │       ├── SD.svg
│   │       ├── slope.svg
│   │       └── typical.svg
│   ├── constants-instead-of-literals
│   │   ├── base
│   │   │   ├── benchmark.json
│   │   │   ├── estimates.json
│   │   │   ├── sample.json
│   │   │   └── tukey.json
│   │   ├── change
│   │   │   └── estimates.json
│   │   ├── new
│   │   │   ├── benchmark.json
│   │   │   ├── estimates.json
│   │   │   ├── sample.json
│   │   │   └── tukey.json
│   │   └── report
│   │       ├── both
│   │       │   ├── pdf.svg
│   │       │   └── regression.svg
│   │       ├── change
│   │       │   ├── mean.svg
│   │       │   ├── median.svg
│   │       │   └── t-test.svg
│   │       ├── index.html
│   │       ├── MAD.svg
│   │       ├── mean.svg
│   │       ├── median.svg
│   │       ├── pdf_small.svg
│   │       ├── pdf.svg
│   │       ├── regression_small.svg
│   │       ├── regression.svg
│   │       ├── relative_pdf_small.svg
│   │       ├── relative_regression_small.svg
│   │       ├── SD.svg
│   │       ├── slope.svg
│   │       └── typical.svg
│   ├── delegate-call-in-loop
│   │   ├── base
│   │   │   ├── benchmark.json
│   │   │   ├── estimates.json
│   │   │   ├── sample.json
│   │   │   └── tukey.json
│   │   ├── change
│   │   │   └── estimates.json
│   │   ├── new
│   │   │   ├── benchmark.json
│   │   │   ├── estimates.json
│   │   │   ├── sample.json
│   │   │   └── tukey.json
│   │   └── report
│   │       ├── both
│   │       │   ├── pdf.svg
│   │       │   └── regression.svg
│   │       ├── change
│   │       │   ├── mean.svg
│   │       │   ├── median.svg
│   │       │   └── t-test.svg
│   │       ├── index.html
│   │       ├── MAD.svg
│   │       ├── mean.svg
│   │       ├── median.svg
│   │       ├── pdf_small.svg
│   │       ├── pdf.svg
│   │       ├── regression_small.svg
│   │       ├── regression.svg
│   │       ├── relative_pdf_small.svg
│   │       ├── relative_regression_small.svg
│   │       ├── SD.svg
│   │       ├── slope.svg
│   │       └── typical.svg
│   ├── deprecated-oz-functions
│   │   ├── base
│   │   │   ├── benchmark.json
│   │   │   ├── estimates.json
│   │   │   ├── sample.json
│   │   │   └── tukey.json
│   │   ├── change
│   │   │   └── estimates.json
│   │   ├── new
│   │   │   ├── benchmark.json
│   │   │   ├── estimates.json
│   │   │   ├── sample.json
│   │   │   └── tukey.json
│   │   └── report
│   │       ├── both
│   │       │   ├── pdf.svg
│   │       │   └── regression.svg
│   │       ├── change
│   │       │   ├── mean.svg
│   │       │   ├── median.svg
│   │       │   └── t-test.svg
│   │       ├── index.html
│   │       ├── MAD.svg
│   │       ├── mean.svg
│   │       ├── median.svg
│   │       ├── pdf_small.svg
│   │       ├── pdf.svg
│   │       ├── regression_small.svg
│   │       ├── regression.svg
│   │       ├── relative_pdf_small.svg
│   │       ├── relative_regression_small.svg
│   │       ├── SD.svg
│   │       ├── slope.svg
│   │       └── typical.svg
│   ├── ecrecover
│   │   ├── base
│   │   │   ├── benchmark.json
│   │   │   ├── estimates.json
│   │   │   ├── sample.json
│   │   │   └── tukey.json
│   │   ├── change
│   │   │   └── estimates.json
│   │   ├── new
│   │   │   ├── benchmark.json
│   │   │   ├── estimates.json
│   │   │   ├── sample.json
│   │   │   └── tukey.json
│   │   └── report
│   │       ├── both
│   │       │   ├── pdf.svg
│   │       │   └── regression.svg
│   │       ├── change
│   │       │   ├── mean.svg
│   │       │   ├── median.svg
│   │       │   └── t-test.svg
│   │       ├── index.html
│   │       ├── MAD.svg
│   │       ├── mean.svg
│   │       ├── median.svg
│   │       ├── pdf_small.svg
│   │       ├── pdf.svg
│   │       ├── regression_small.svg
│   │       ├── regression.svg
│   │       ├── relative_pdf_small.svg
│   │       ├── relative_regression_small.svg
│   │       ├── SD.svg
│   │       ├── slope.svg
│   │       └── typical.svg
│   ├── empty-block
│   │   ├── base
│   │   │   ├── benchmark.json
│   │   │   ├── estimates.json
│   │   │   ├── sample.json
│   │   │   └── tukey.json
│   │   ├── change
│   │   │   └── estimates.json
│   │   ├── new
│   │   │   ├── benchmark.json
│   │   │   ├── estimates.json
│   │   │   ├── sample.json
│   │   │   └── tukey.json
│   │   └── report
│   │       ├── both
│   │       │   ├── pdf.svg
│   │       │   └── regression.svg
│   │       ├── change
│   │       │   ├── mean.svg
│   │       │   ├── median.svg
│   │       │   └── t-test.svg
│   │       ├── index.html
│   │       ├── MAD.svg
│   │       ├── mean.svg
│   │       ├── median.svg
│   │       ├── pdf_small.svg
│   │       ├── pdf.svg
│   │       ├── regression_small.svg
│   │       ├── regression.svg
│   │       ├── relative_pdf_small.svg
│   │       ├── relative_regression_small.svg
│   │       ├── SD.svg
│   │       ├── slope.svg
│   │       └── typical.svg
│   ├── hello_world
│   │   ├── base
│   │   │   ├── benchmark.json
│   │   │   ├── estimates.json
│   │   │   ├── sample.json
│   │   │   └── tukey.json
│   │   ├── new
│   │   │   ├── benchmark.json
│   │   │   ├── estimates.json
│   │   │   ├── sample.json
│   │   │   └── tukey.json
│   │   └── report
│   │       ├── index.html
│   │       ├── MAD.svg
│   │       ├── mean.svg
│   │       ├── median.svg
│   │       ├── pdf_small.svg
│   │       ├── pdf.svg
│   │       ├── regression_small.svg
│   │       ├── regression.svg
│   │       ├── SD.svg
│   │       ├── slope.svg
│   │       └── typical.svg
│   ├── inconsistent-type-names
│   │   ├── base
│   │   │   ├── benchmark.json
│   │   │   ├── estimates.json
│   │   │   ├── sample.json
│   │   │   └── tukey.json
│   │   ├── change
│   │   │   └── estimates.json
│   │   ├── new
│   │   │   ├── benchmark.json
│   │   │   ├── estimates.json
│   │   │   ├── sample.json
│   │   │   └── tukey.json
│   │   └── report
│   │       ├── both
│   │       │   ├── pdf.svg
│   │       │   └── regression.svg
│   │       ├── change
│   │       │   ├── mean.svg
│   │       │   ├── median.svg
│   │       │   └── t-test.svg
│   │       ├── index.html
│   │       ├── MAD.svg
│   │       ├── mean.svg
│   │       ├── median.svg
│   │       ├── pdf_small.svg
│   │       ├── pdf.svg
│   │       ├── regression_small.svg
│   │       ├── regression.svg
│   │       ├── relative_pdf_small.svg
│   │       ├── relative_regression_small.svg
│   │       ├── SD.svg
│   │       ├── slope.svg
│   │       └── typical.svg
│   ├── large-numeric-literal
│   │   ├── base
│   │   │   ├── benchmark.json
│   │   │   ├── estimates.json
│   │   │   ├── sample.json
│   │   │   └── tukey.json
│   │   ├── change
│   │   │   └── estimates.json
│   │   ├── new
│   │   │   ├── benchmark.json
│   │   │   ├── estimates.json
│   │   │   ├── sample.json
│   │   │   └── tukey.json
│   │   └── report
│   │       ├── both
│   │       │   ├── pdf.svg
│   │       │   └── regression.svg
│   │       ├── change
│   │       │   ├── mean.svg
│   │       │   ├── median.svg
│   │       │   └── t-test.svg
│   │       ├── index.html
│   │       ├── MAD.svg
│   │       ├── mean.svg
│   │       ├── median.svg
│   │       ├── pdf_small.svg
│   │       ├── pdf.svg
│   │       ├── regression_small.svg
│   │       ├── regression.svg
│   │       ├── relative_pdf_small.svg
│   │       ├── relative_regression_small.svg
│   │       ├── SD.svg
│   │       ├── slope.svg
│   │       └── typical.svg
│   ├── non-reentrant-before-others
│   │   ├── base
│   │   │   ├── benchmark.json
│   │   │   ├── estimates.json
│   │   │   ├── sample.json
│   │   │   └── tukey.json
│   │   ├── change
│   │   │   └── estimates.json
│   │   ├── new
│   │   │   ├── benchmark.json
│   │   │   ├── estimates.json
│   │   │   ├── sample.json
│   │   │   └── tukey.json
│   │   └── report
│   │       ├── both
│   │       │   ├── pdf.svg
│   │       │   └── regression.svg
│   │       ├── change
│   │       │   ├── mean.svg
│   │       │   ├── median.svg
│   │       │   └── t-test.svg
│   │       ├── index.html
│   │       ├── MAD.svg
│   │       ├── mean.svg
│   │       ├── median.svg
│   │       ├── pdf_small.svg
│   │       ├── pdf.svg
│   │       ├── regression_small.svg
│   │       ├── regression.svg
│   │       ├── relative_pdf_small.svg
│   │       ├── relative_regression_small.svg
│   │       ├── SD.svg
│   │       ├── slope.svg
│   │       └── typical.svg
│   ├── push-zero-opcode
│   │   ├── base
│   │   │   ├── benchmark.json
│   │   │   ├── estimates.json
│   │   │   ├── sample.json
│   │   │   └── tukey.json
│   │   ├── change
│   │   │   └── estimates.json
│   │   ├── new
│   │   │   ├── benchmark.json
│   │   │   ├── estimates.json
│   │   │   ├── sample.json
│   │   │   └── tukey.json
│   │   └── report
│   │       ├── both
│   │       │   ├── pdf.svg
│   │       │   └── regression.svg
│   │       ├── change
│   │       │   ├── mean.svg
│   │       │   ├── median.svg
│   │       │   └── t-test.svg
│   │       ├── index.html
│   │       ├── MAD.svg
│   │       ├── mean.svg
│   │       ├── median.svg
│   │       ├── pdf_small.svg
│   │       ├── pdf.svg
│   │       ├── regression_small.svg
│   │       ├── regression.svg
│   │       ├── relative_pdf_small.svg
│   │       ├── relative_regression_small.svg
│   │       ├── SD.svg
│   │       ├── slope.svg
│   │       └── typical.svg
│   ├── report
│   │   └── index.html
│   ├── require-with-string
│   │   ├── base
│   │   │   ├── benchmark.json
│   │   │   ├── estimates.json
│   │   │   ├── sample.json
│   │   │   └── tukey.json
│   │   ├── change
│   │   │   └── estimates.json
│   │   ├── new
│   │   │   ├── benchmark.json
│   │   │   ├── estimates.json
│   │   │   ├── sample.json
│   │   │   └── tukey.json
│   │   └── report
│   │       ├── both
│   │       │   ├── pdf.svg
│   │       │   └── regression.svg
│   │       ├── change
│   │       │   ├── mean.svg
│   │       │   ├── median.svg
│   │       │   └── t-test.svg
│   │       ├── index.html
│   │       ├── MAD.svg
│   │       ├── mean.svg
│   │       ├── median.svg
│   │       ├── pdf_small.svg
│   │       ├── pdf.svg
│   │       ├── regression_small.svg
│   │       ├── regression.svg
│   │       ├── relative_pdf_small.svg
│   │       ├── relative_regression_small.svg
│   │       ├── SD.svg
│   │       ├── slope.svg
│   │       └── typical.svg
│   ├── solmate-safe-transfer-lib
│   │   ├── base
│   │   │   ├── benchmark.json
│   │   │   ├── estimates.json
│   │   │   ├── sample.json
│   │   │   └── tukey.json
│   │   ├── change
│   │   │   └── estimates.json
│   │   ├── new
│   │   │   ├── benchmark.json
│   │   │   ├── estimates.json
│   │   │   ├── sample.json
│   │   │   └── tukey.json
│   │   └── report
│   │       ├── both
│   │       │   ├── pdf.svg
│   │       │   └── regression.svg
│   │       ├── change
│   │       │   ├── mean.svg
│   │       │   ├── median.svg
│   │       │   └── t-test.svg
│   │       ├── index.html
│   │       ├── MAD.svg
│   │       ├── mean.svg
│   │       ├── median.svg
│   │       ├── pdf_small.svg
│   │       ├── pdf.svg
│   │       ├── regression_small.svg
│   │       ├── regression.svg
│   │       ├── relative_pdf_small.svg
│   │       ├── relative_regression_small.svg
│   │       ├── SD.svg
│   │       ├── slope.svg
│   │       └── typical.svg
│   ├── unindexed-events
│   │   ├── base
│   │   │   ├── benchmark.json
│   │   │   ├── estimates.json
│   │   │   ├── sample.json
│   │   │   └── tukey.json
│   │   ├── change
│   │   │   └── estimates.json
│   │   ├── new
│   │   │   ├── benchmark.json
│   │   │   ├── estimates.json
│   │   │   ├── sample.json
│   │   │   └── tukey.json
│   │   └── report
│   │       ├── both
│   │       │   ├── pdf.svg
│   │       │   └── regression.svg
│   │       ├── change
│   │       │   ├── mean.svg
│   │       │   ├── median.svg
│   │       │   └── t-test.svg
│   │       ├── index.html
│   │       ├── MAD.svg
│   │       ├── mean.svg
│   │       ├── median.svg
│   │       ├── pdf_small.svg
│   │       ├── pdf.svg
│   │       ├── regression_small.svg
│   │       ├── regression.svg
│   │       ├── relative_pdf_small.svg
│   │       ├── relative_regression_small.svg
│   │       ├── SD.svg
│   │       ├── slope.svg
│   │       └── typical.svg
│   ├── unprotected-initializer
│   │   ├── base
│   │   │   ├── benchmark.json
│   │   │   ├── estimates.json
│   │   │   ├── sample.json
│   │   │   └── tukey.json
│   │   ├── change
│   │   │   └── estimates.json
│   │   ├── new
│   │   │   ├── benchmark.json
│   │   │   ├── estimates.json
│   │   │   ├── sample.json
│   │   │   └── tukey.json
│   │   └── report
│   │       ├── both
│   │       │   ├── pdf.svg
│   │       │   └── regression.svg
│   │       ├── change
│   │       │   ├── mean.svg
│   │       │   ├── median.svg
│   │       │   └── t-test.svg
│   │       ├── index.html
│   │       ├── MAD.svg
│   │       ├── mean.svg
│   │       ├── median.svg
│   │       ├── pdf_small.svg
│   │       ├── pdf.svg
│   │       ├── regression_small.svg
│   │       ├── regression.svg
│   │       ├── relative_pdf_small.svg
│   │       ├── relative_regression_small.svg
│   │       ├── SD.svg
│   │       ├── slope.svg
│   │       └── typical.svg
│   ├── unsafe-erc20-functions
│   │   ├── base
│   │   │   ├── benchmark.json
│   │   │   ├── estimates.json
│   │   │   ├── sample.json
│   │   │   └── tukey.json
│   │   ├── change
│   │   │   └── estimates.json
│   │   ├── new
│   │   │   ├── benchmark.json
│   │   │   ├── estimates.json
│   │   │   ├── sample.json
│   │   │   └── tukey.json
│   │   └── report
│   │       ├── both
│   │       │   ├── pdf.svg
│   │       │   └── regression.svg
│   │       ├── change
│   │       │   ├── mean.svg
│   │       │   ├── median.svg
│   │       │   └── t-test.svg
│   │       ├── index.html
│   │       ├── MAD.svg
│   │       ├── mean.svg
│   │       ├── median.svg
│   │       ├── pdf_small.svg
│   │       ├── pdf.svg
│   │       ├── regression_small.svg
│   │       ├── regression.svg
│   │       ├── relative_pdf_small.svg
│   │       ├── relative_regression_small.svg
│   │       ├── SD.svg
│   │       ├── slope.svg
│   │       └── typical.svg
│   ├── unsafe-oz-erc721-mint
│   │   ├── base
│   │   │   ├── benchmark.json
│   │   │   ├── estimates.json
│   │   │   ├── sample.json
│   │   │   └── tukey.json
│   │   ├── change
│   │   │   └── estimates.json
│   │   ├── new
│   │   │   ├── benchmark.json
│   │   │   ├── estimates.json
│   │   │   ├── sample.json
│   │   │   └── tukey.json
│   │   └── report
│   │       ├── both
│   │       │   ├── pdf.svg
│   │       │   └── regression.svg
│   │       ├── change
│   │       │   ├── mean.svg
│   │       │   ├── median.svg
│   │       │   └── t-test.svg
│   │       ├── index.html
│   │       ├── MAD.svg
│   │       ├── mean.svg
│   │       ├── median.svg
│   │       ├── pdf_small.svg
│   │       ├── pdf.svg
│   │       ├── regression_small.svg
│   │       ├── regression.svg
│   │       ├── relative_pdf_small.svg
│   │       ├── relative_regression_small.svg
│   │       ├── SD.svg
│   │       ├── slope.svg
│   │       └── typical.svg
│   ├── unspecific-solidity-pragma
│   │   ├── base
│   │   │   ├── benchmark.json
│   │   │   ├── estimates.json
│   │   │   ├── sample.json
│   │   │   └── tukey.json
│   │   ├── change
│   │   │   └── estimates.json
│   │   ├── new
│   │   │   ├── benchmark.json
│   │   │   ├── estimates.json
│   │   │   ├── sample.json
│   │   │   └── tukey.json
│   │   └── report
│   │       ├── both
│   │       │   ├── pdf.svg
│   │       │   └── regression.svg
│   │       ├── change
│   │       │   ├── mean.svg
│   │       │   ├── median.svg
│   │       │   └── t-test.svg
│   │       ├── index.html
│   │       ├── MAD.svg
│   │       ├── mean.svg
│   │       ├── median.svg
│   │       ├── pdf_small.svg
│   │       ├── pdf.svg
│   │       ├── regression_small.svg
│   │       ├── regression.svg
│   │       ├── relative_pdf_small.svg
│   │       ├── relative_regression_small.svg
│   │       ├── SD.svg
│   │       ├── slope.svg
│   │       └── typical.svg
│   ├── useless-internal-function
│   │   ├── base
│   │   │   ├── benchmark.json
│   │   │   ├── estimates.json
│   │   │   ├── sample.json
│   │   │   └── tukey.json
│   │   ├── change
│   │   │   └── estimates.json
│   │   ├── new
│   │   │   ├── benchmark.json
│   │   │   ├── estimates.json
│   │   │   ├── sample.json
│   │   │   └── tukey.json
│   │   └── report
│   │       ├── both
│   │       │   ├── pdf.svg
│   │       │   └── regression.svg
│   │       ├── change
│   │       │   ├── mean.svg
│   │       │   ├── median.svg
│   │       │   └── t-test.svg
│   │       ├── index.html
│   │       ├── MAD.svg
│   │       ├── mean.svg
│   │       ├── median.svg
│   │       ├── pdf_small.svg
│   │       ├── pdf.svg
│   │       ├── regression_small.svg
│   │       ├── regression.svg
│   │       ├── relative_pdf_small.svg
│   │       ├── relative_regression_small.svg
│   │       ├── SD.svg
│   │       ├── slope.svg
│   │       └── typical.svg
│   ├── useless-modifier
│   │   ├── base
│   │   │   ├── benchmark.json
│   │   │   ├── estimates.json
│   │   │   ├── sample.json
│   │   │   └── tukey.json
│   │   ├── change
│   │   │   └── estimates.json
│   │   ├── new
│   │   │   ├── benchmark.json
│   │   │   ├── estimates.json
│   │   │   ├── sample.json
│   │   │   └── tukey.json
│   │   └── report
│   │       ├── both
│   │       │   ├── pdf.svg
│   │       │   └── regression.svg
│   │       ├── change
│   │       │   ├── mean.svg
│   │       │   ├── median.svg
│   │       │   └── t-test.svg
│   │       ├── index.html
│   │       ├── MAD.svg
│   │       ├── mean.svg
│   │       ├── median.svg
│   │       ├── pdf_small.svg
│   │       ├── pdf.svg
│   │       ├── regression_small.svg
│   │       ├── regression.svg
│   │       ├── relative_pdf_small.svg
│   │       ├── relative_regression_small.svg
│   │       ├── SD.svg
│   │       ├── slope.svg
│   │       └── typical.svg
│   ├── useless-public-function
│   │   ├── base
│   │   │   ├── benchmark.json
│   │   │   ├── estimates.json
│   │   │   ├── sample.json
│   │   │   └── tukey.json
│   │   ├── change
│   │   │   └── estimates.json
│   │   ├── new
│   │   │   ├── benchmark.json
│   │   │   ├── estimates.json
│   │   │   ├── sample.json
│   │   │   └── tukey.json
│   │   └── report
│   │       ├── both
│   │       │   ├── pdf.svg
│   │       │   └── regression.svg
│   │       ├── change
│   │       │   ├── mean.svg
│   │       │   ├── median.svg
│   │       │   └── t-test.svg
│   │       ├── index.html
│   │       ├── MAD.svg
│   │       ├── mean.svg
│   │       ├── median.svg
│   │       ├── pdf_small.svg
│   │       ├── pdf.svg
│   │       ├── regression_small.svg
│   │       ├── regression.svg
│   │       ├── relative_pdf_small.svg
│   │       ├── relative_regression_small.svg
│   │       ├── SD.svg
│   │       ├── slope.svg
│   │       └── typical.svg
│   └── zero-address-check
│       ├── base
│       │   ├── benchmark.json
│       │   ├── estimates.json
│       │   ├── sample.json
│       │   └── tukey.json
│       ├── change
│       │   └── estimates.json
│       ├── new
│       │   ├── benchmark.json
│       │   ├── estimates.json
│       │   ├── sample.json
│       │   └── tukey.json
│       └── report
│           ├── both
│           │   ├── pdf.svg
│           │   └── regression.svg
│           ├── change
│           │   ├── mean.svg
│           │   ├── median.svg
│           │   └── t-test.svg
│           ├── index.html
│           ├── MAD.svg
│           ├── mean.svg
│           ├── median.svg
│           ├── pdf_small.svg
│           ├── pdf.svg
│           ├── regression_small.svg
│           ├── regression.svg
│           ├── relative_pdf_small.svg
│           ├── relative_regression_small.svg
│           ├── SD.svg
│           ├── slope.svg
│           └── typical.svg
├── Cargo.lock
├── Cargo.toml
├── cli
│   ├── benchmarks.sh
│   └── reportgen.sh
├── CODEOWNERS
├── CONTRIBUTING.md
├── cyfrinup
│   ├── dynamic_script
│   └── why.md
├── deny.toml
├── dist-workspace.toml
├── funding.json
├── LICENSE
├── Makefile
├── package-lock.json
├── package.json
├── README.md
├── RELEASE_CHECKLIST.md
├── reports
│   ├── adhoc-sol-files-highs-only-report.json
│   ├── adhoc-sol-files-report.md
│   ├── ccip-functions-report.md
│   ├── empty_report.md
│   ├── hardhat-playground-report.md
│   ├── nft-report-icm.md
│   ├── nft-report.md
│   ├── prb-math-report.md
│   ├── report.json
│   ├── report.md
│   ├── report.sarif
│   ├── sablier-aderyn-toml-nested-root.md
│   ├── templegold-report.md
│   └── uniswap_profile.md
├── rust-toolchain.toml
├── rustfmt.toml
├── tests
│   ├── adhoc-sol-files
│   │   ├── aderyn.toml
│   │   ├── Counter.sol
│   │   ├── DemoASTNodes.sol
│   │   ├── Helper.sol
│   │   ├── InconsistentUints.sol
│   │   ├── inheritance
│   │   │   ├── ExtendedInheritance.sol
│   │   │   ├── IContractInheritance.sol
│   │   │   └── InheritanceBase.sol
│   │   ├── InternalFunctions.sol
│   │   ├── lib
│   │   │   └── ThisShouldBeExcluded.sol
│   │   ├── multiple-versions
│   │   │   ├── 0.4
│   │   │   │   ├── A.sol
│   │   │   │   └── B.sol
│   │   │   ├── 0.5
│   │   │   │   ├── A.sol
│   │   │   │   └── B.sol
│   │   │   ├── 0.6
│   │   │   │   ├── A.sol
│   │   │   │   └── B.sol
│   │   │   ├── 0.7
│   │   │   │   ├── A.sol
│   │   │   │   └── B.sol
│   │   │   └── 0.8
│   │   │       ├── A.sol
│   │   │       └── B.sol
│   │   ├── OnceModifierExample.sol
│   │   └── StateVariables.sol
│   ├── ast
│   │   ├── abstract_contract.json
│   │   ├── address_payable.json
│   │   ├── array_type_name.json
│   │   ├── ast-erc4626.json
│   │   ├── base_constructor_call.json
│   │   ├── bit_not.json
│   │   ├── call.json
│   │   ├── constructor.json
│   │   ├── contract_dep_order.json
│   │   ├── do_while.json
│   │   ├── documentation_1.json
│   │   ├── documentation_2.json
│   │   ├── documentation_3.json
│   │   ├── documentation_local_variable.json
│   │   ├── documentation_on_statements.json
│   │   ├── documentation_triple.json
│   │   ├── empty_block.json
│   │   ├── enum_value_declaration.json
│   │   ├── enum_value.json
│   │   ├── event_definition.json
│   │   ├── experimental_encoder_pragma.json
│   │   ├── fallback_and_reveice_ether.json
│   │   ├── fallback_payable.json
│   │   ├── fallback.json
│   │   ├── function_type.json
│   │   ├── function.json
│   │   ├── global_enum.json
│   │   ├── global_struct.json
│   │   ├── inheritance_specifier.json
│   │   ├── leave.json
│   │   ├── license.json
│   │   ├── long_type_name_binary_operation.json
│   │   ├── long_type_name_identifier.json
│   │   ├── loop.json
│   │   ├── mappings.json
│   │   ├── modifier_definition.json
│   │   ├── modifier_invocation.json
│   │   ├── mutability.json
│   │   ├── nested_functions.json
│   │   ├── non_utf8.json
│   │   ├── override.json
│   │   ├── placeholder_statement.json
│   │   ├── receive_ether.json
│   │   ├── short_type_name_ref.json
│   │   ├── short_type_name.json
│   │   ├── slot_offset.json
│   │   ├── smoke.json
│   │   ├── source_location.json
│   │   ├── string.json
│   │   ├── stringlit.json
│   │   ├── switch_default.json
│   │   ├── switch.json
│   │   ├── try_catch.json
│   │   ├── two_base_functions.json
│   │   ├── unicode.json
│   │   ├── used_errors.json
│   │   ├── userDefinedValueType.json
│   │   ├── using_for_directive.json
│   │   ├── var_access.json
│   │   └── yul_hex_literal.json
│   ├── contract-playground
│   │   ├── .github
│   │   │   └── workflows
│   │   │       └── test.yml
│   │   ├── .gitignore
│   │   ├── dot
│   │   │   └── .gitkeep
│   │   ├── foundry.toml
│   │   ├── README.md
│   │   ├── script
│   │   │   └── Counter.s.sol
│   │   ├── src
│   │   │   ├── AbstractContract.sol
│   │   │   ├── AderynIgnoreCustomDetectors.sol
│   │   │   ├── AdminContract.sol
│   │   │   ├── ArbitraryTransferFrom.sol
│   │   │   ├── AssemblyExample.sol
│   │   │   ├── AssertStateChange.sol
│   │   │   ├── auditor_mode
│   │   │   │   ├── ExternalCalls.sol
│   │   │   │   └── PublicFunctionsWithoutSenderCheck.sol
│   │   │   ├── BooleanEquality.sol
│   │   │   ├── BuiltinSymbolShadow.sol
│   │   │   ├── CacheArrayLength.sol
│   │   │   ├── CallGraphTests.sol
│   │   │   ├── Casting.sol
│   │   │   ├── cloc
│   │   │   │   ├── AnotherHeavilyCommentedContract.sol
│   │   │   │   ├── EmptyContractFile.sol
│   │   │   │   └── HeavilyCommentedContract.sol
│   │   │   ├── CompilerBugStorageSignedIntegerArray.sol
│   │   │   ├── ConstantFuncsAssembly.sol
│   │   │   ├── ConstantsLiterals.sol
│   │   │   ├── ConstFuncChangeState.sol
│   │   │   ├── ContractLocksEther.sol
│   │   │   ├── ContractWithTodo.sol
│   │   │   ├── control_flow
│   │   │   │   └── SimpleProgram.sol
│   │   │   ├── CostlyOperationsInsideLoops.sol
│   │   │   ├── Counter.sol
│   │   │   ├── CrazyPragma.sol
│   │   │   ├── DangerousStrictEquality1.sol
│   │   │   ├── DangerousStrictEquality2.sol
│   │   │   ├── DangerousUnaryOperator.sol
│   │   │   ├── DeadCode.sol
│   │   │   ├── DelegateCallWithoutAddressCheck.sol
│   │   │   ├── DeletionNestedMappingStructureContract.sol
│   │   │   ├── DeprecatedOZFunctions.sol
│   │   │   ├── DivisionBeforeMultiplication.sol
│   │   │   ├── DynamicArrayLengthAssignment.sol
│   │   │   ├── EmitAfterExternalCall.sol
│   │   │   ├── EmptyBlocks.sol
│   │   │   ├── EnumerableSetIteration.sol
│   │   │   ├── eth2
│   │   │   │   └── DepositContract.sol
│   │   │   ├── ExperimentalEncoder.sol
│   │   │   ├── ExternalCalls.sol
│   │   │   ├── FunctionInitializingState.sol
│   │   │   ├── FunctionPointers.sol
│   │   │   ├── FunctionSignatureCollision.sol
│   │   │   ├── HugeConstants.sol
│   │   │   ├── IgnoreEverything.sol
│   │   │   ├── InconsistentUints.sol
│   │   │   ├── IncorrectCaretOperator.sol
│   │   │   ├── IncorrectERC20.sol
│   │   │   ├── IncorrectERC721.sol
│   │   │   ├── IncorrectModifier.sol
│   │   │   ├── IncorrectShift.sol
│   │   │   ├── inheritance
│   │   │   │   ├── ExtendedInheritance.sol
│   │   │   │   ├── IContractInheritance.sol
│   │   │   │   └── InheritanceBase.sol
│   │   │   ├── InternalFunctions.sol
│   │   │   ├── KeccakContract.sol
│   │   │   ├── LocalVariableShadow.sol
│   │   │   ├── MissingInheritance.sol
│   │   │   ├── MisusedBoolean.sol
│   │   │   ├── MsgValueInLoop.sol
│   │   │   ├── MultipleConstructorSchemes.sol
│   │   │   ├── MultiplePlaceholders.sol
│   │   │   ├── nested
│   │   │   │   ├── 1
│   │   │   │   │   └── Nested.sol
│   │   │   │   └── 2
│   │   │   │       └── Nested.sol
│   │   │   ├── nested_mappings
│   │   │   │   ├── LaterVersion.sol
│   │   │   │   └── NestedMappings.sol
│   │   │   ├── OnceModifierExample.sol
│   │   │   ├── OnlyLibrary.sol
│   │   │   ├── OutOfOrderRetryable.sol
│   │   │   ├── parent_chain
│   │   │   │   └── ParentChainContract.sol
│   │   │   ├── PragmaRange.sol
│   │   │   ├── PreDeclaredVarUsage.sol
│   │   │   ├── PublicFunction.sol
│   │   │   ├── PublicVariableReadInExternalContext.sol
│   │   │   ├── RedundantStatements.sol
│   │   │   ├── ReturnBomb.sol
│   │   │   ├── reused_contract_name
│   │   │   │   ├── ContractA.sol
│   │   │   │   └── ContractB.sol
│   │   │   ├── RevertsAndRequriesInLoops.sol
│   │   │   ├── router
│   │   │   │   ├── ExternalCalls.sol
│   │   │   │   ├── FallbackAndReceiveOverrides.sol
│   │   │   │   ├── InternalCalls.sol
│   │   │   │   ├── ModifierCalls.sol
│   │   │   │   └── VarOverridesFunction.sol
│   │   │   ├── RTLO.sol
│   │   │   ├── SendEtherNoChecks.sol
│   │   │   ├── SendEtherNoChecksLibImport.sol
│   │   │   ├── StateChangeAfterExternalCall.sol
│   │   │   ├── StateShadowing.sol
│   │   │   ├── StateVariableCouldBeDeclaredConstant.sol
│   │   │   ├── StateVariableCouldBeDeclaredImmutable.sol
│   │   │   ├── StateVariables.sol
│   │   │   ├── StateVariablesChangesWithoutEvents.sol
│   │   │   ├── StateVariablesManipulation.sol
│   │   │   ├── StorageConditionals.sol
│   │   │   ├── StorageParameters.sol
│   │   │   ├── T11sTranferer.sol
│   │   │   ├── TautologicalCompare.sol
│   │   │   ├── TautologyOrContradiction.sol
│   │   │   ├── TestERC20.sol
│   │   │   ├── TransientKeyword.sol
│   │   │   ├── Trump.sol
│   │   │   ├── TxOriginUsedForAuth.sol
│   │   │   ├── U2.sol
│   │   │   ├── U3.sol
│   │   │   ├── U4.sol
│   │   │   ├── U5.sol
│   │   │   ├── UncheckedCalls.sol
│   │   │   ├── UncheckedReturn.sol
│   │   │   ├── UncheckedSend.sol
│   │   │   ├── UninitializedLocalVariables.sol
│   │   │   ├── UninitializedStateVariable.sol
│   │   │   ├── uniswap
│   │   │   │   ├── UniswapV2Swapper.sol
│   │   │   │   └── UniswapV3Swapper.sol
│   │   │   ├── UnprotectedInitialize.sol
│   │   │   ├── UnsafeERC721Mint.sol
│   │   │   ├── UnusedError.sol
│   │   │   ├── UnusedImport.sol
│   │   │   ├── UnusedStateVariables.sol
│   │   │   ├── UsingSelfdestruct.sol
│   │   │   ├── VoidConstructor.sol
│   │   │   ├── WeakRandomness.sol
│   │   │   ├── WrongOrderOfLayout.sol
│   │   │   ├── YulReturn.sol
│   │   │   └── ZeroAddressCheck.sol
│   │   └── test
│   │       └── Counter.t.sol
│   ├── foundry-nft-f23
│   │   ├── .github
│   │   │   └── workflows
│   │   │       └── test.yml
│   │   ├── .gitignore
│   │   ├── foundry.lock
│   │   ├── foundry.toml
│   │   ├── README.md
│   │   ├── remappings.txt
│   │   └── src
│   │       ├── BasicNft.sol
│   │       ├── F1.sol
│   │       ├── F2.sol
│   │       ├── Initializer.sol
│   │       └── inner-core-modules
│   │           └── ICM.sol
│   ├── foundry-nft-f23-icm
│   │   ├── .github
│   │   │   └── workflows
│   │   │       └── test.yml
│   │   ├── .gitignore
│   │   ├── aderyn.toml
│   │   ├── foundry.toml
│   │   ├── README.md
│   │   ├── remappings.txt
│   │   └── src
│   │       ├── BasicNft.sol
│   │       ├── F1.sol
│   │       ├── F2.sol
│   │       ├── Initializer.sol
│   │       └── inner-core-modules
│   │           └── ICM.sol
│   ├── hardhat-js-playground
│   │   ├── .gitignore
│   │   ├── artifacts
│   │   │   ├── build-info
│   │   │   │   └── cee6fe9a9a2f03f7ff10a27ab2746af6.json
│   │   │   └── contracts
│   │   │       ├── Counter.sol
│   │   │       │   ├── Counter.dbg.json
│   │   │       │   └── Counter.json
│   │   │       ├── ExtendedInheritance.sol
│   │   │       │   ├── ExtendedInheritance.dbg.json
│   │   │       │   └── ExtendedInheritance.json
│   │   │       ├── IContractInheritance.sol
│   │   │       │   ├── IContractInheritance.dbg.json
│   │   │       │   └── IContractInheritance.json
│   │   │       ├── InheritanceBase.sol
│   │   │       │   ├── InheritanceBase.dbg.json
│   │   │       │   └── InheritanceBase.json
│   │   │       ├── KeccakContract.sol
│   │   │       │   ├── KeccakContract.dbg.json
│   │   │       │   └── KeccakContract.json
│   │   │       ├── Lock.sol
│   │   │       │   ├── Lock.dbg.json
│   │   │       │   └── Lock.json
│   │   │       └── StateVariables.sol
│   │   │           ├── StateVariables.dbg.json
│   │   │           └── StateVariables.json
│   │   ├── contracts
│   │   │   ├── Counter.sol
│   │   │   ├── ExtendedInheritance.sol
│   │   │   ├── IContractInheritance.sol
│   │   │   ├── InheritanceBase.sol
│   │   │   ├── KeccakContract.sol
│   │   │   ├── Lock.sol
│   │   │   └── StateVariables.sol
│   │   ├── hardhat.config.js
│   │   ├── package.json
│   │   ├── README.md
│   │   ├── scripts
│   │   │   └── deploy.js
│   │   ├── test
│   │   │   └── Lock.js
│   │   └── yarn.lock
│   ├── no-sol-files
│   │   ├── extra
│   │   │   └── HelloAgain.md
│   │   ├── Hello.txt
│   │   └── Hello.yul
│   └── toml
│       ├── nested_project1
│       │   ├── aderyn.toml
│       │   ├── folder1
│       │   │   └── hardhat.config.ts
│       │   ├── folder2
│       │   │   └── hardhat.config.ts
│       │   └── folder3
│       │       └── file.txt
│       └── nested_project2
│           ├── aderyn.toml
│           ├── folder1
│           │   └── foundry.toml
│           └── folder2
│               └── file1.txt
├── tools
│   └── xtask
│       ├── Cargo.toml
│       └── src
│           ├── blesspr.rs
│           ├── cut_release.rs
│           ├── flags.rs
│           ├── main.rs
│           ├── reportgen.rs
│           └── tomlgen.rs
└── typos.toml
```

# Files

--------------------------------------------------------------------------------
/.github/workflows/toml.yml:
--------------------------------------------------------------------------------

```yaml
on: [push, pull_request, workflow_dispatch]

name: Aderyn toml creation

concurrency:
  group: ci-${{ github.ref }}-toml
  cancel-in-progress: true

jobs:
  reports-setup:
    name:  Check toml 
    runs-on: ubuntu-latest
    outputs:
      rust-nightly: nightly-2025-09-20
    
    strategy:
      fail-fast: false
      matrix:
        task:
          - nested_folder1
          - nested_folder2

    steps:
      - name: Checkout Sources
        uses: actions/checkout@v4

      - name: Checkout repository with submodules
        uses: actions/checkout@v4
        with:
          submodules: recursive

      - name: Cache submodules
        id: cache-submodules
        uses: actions/cache@v3
        with:
          path: .git/modules
          key: submodules-${{ runner.os }}-${{ hashFiles('.gitmodules') }}
          restore-keys: |
            submodules-${{ runner.os }}-${{ hashFiles('.gitmodules') }}

      - name: Install Rust Nightly (2025-01-01)
        uses: actions-rs/toolchain@v1
        with:
          profile: minimal
          toolchain: nightly-2025-09-20
          override: true

      - name: Restore Rust Cache
        uses: Swatinem/rust-cache@v2

      - name: Prebuild (${{ matrix.task }})
        run: |
          cargo build

      - name: Generate aderyn.toml (${{ matrix.task }})
        run: |
          case "${{ matrix.task }}" in
            nested-folder1)
              mv ./tests/toml/nested_project1/aderyn.toml expected1.toml

              rm -rf ./tests/toml/nested_project1/aderyn.toml
              cargo run -- init ./tests/toml/nested_project1

              mv ./tests/toml/nested_project1/aderyn.toml actual1.toml
              diff expected1.toml actual1.toml
              ;;
             nested-folder2)
              mv ./tests/toml/nested_project2/aderyn.toml expected2.toml

              rm -rf ./tests/toml/nested_project2/aderyn.toml
              cargo run -- init ./tests/toml/nested_project2

              mv ./tests/toml/nested_project2/aderyn.toml actual2.toml
              diff expected2.toml actual2.toml
              ;;
          esac

```

--------------------------------------------------------------------------------
/aderyn_core/src/ast/impls/own/hashing.rs:
--------------------------------------------------------------------------------

```rust
use crate::ast::*;
use std::hash::{Hash, Hasher};

// Identifier
impl PartialEq for Identifier {
    fn eq(&self, other: &Self) -> bool {
        self.argument_types.eq(&other.argument_types)
            && self.name.eq(&other.name)
            && self.overloaded_declarations.eq(&other.overloaded_declarations)
            && self.referenced_declaration.eq(&other.referenced_declaration)
            && self.type_descriptions.eq(&other.type_descriptions)
    }
}

impl Hash for Identifier {
    fn hash<H: Hasher>(&self, state: &mut H) {
        self.argument_types.hash(state);
        self.name.hash(state);
        self.overloaded_declarations.hash(state);
        self.referenced_declaration.hash(state);
        self.type_descriptions.hash(state);
        self.src.hash(state);
        self.id.hash(state);
    }
}

// Identifier Path
impl PartialEq for IdentifierPath {
    fn eq(&self, other: &Self) -> bool {
        self.name.eq(&other.name) && self.referenced_declaration.eq(&other.referenced_declaration)
    }
}

impl Hash for IdentifierPath {
    fn hash<H: Hasher>(&self, state: &mut H) {
        self.name.hash(state);
        self.referenced_declaration.hash(state);
        self.src.hash(state);
        self.id.hash(state);
    }
}

// ElementaryTypeName
impl PartialEq for ElementaryTypeName {
    fn eq(&self, other: &Self) -> bool {
        self.state_mutability.eq(&other.state_mutability)
            && self.type_descriptions.eq(&other.type_descriptions)
    }
}

impl Hash for ElementaryTypeName {
    fn hash<H: Hasher>(&self, state: &mut H) {
        self.state_mutability.hash(state);
        self.name.hash(state);
        self.type_descriptions.hash(state);
    }
}

// UserDefinedTypeName
impl PartialEq for UserDefinedTypeName {
    fn eq(&self, other: &Self) -> bool {
        self.referenced_declaration.eq(&other.referenced_declaration)
    }
}

impl Hash for UserDefinedTypeName {
    fn hash<H: Hasher>(&self, state: &mut H) {
        self.path_node.hash(state);
        self.referenced_declaration.hash(state);
        self.name.hash(state);
        self.type_descriptions.hash(state);
    }
}

```

--------------------------------------------------------------------------------
/tests/ast/modifier_invocation.json:
--------------------------------------------------------------------------------

```json
{"absolutePath":"a","exportedSymbols":{"C":[14]},"id":15,"nodeType":"SourceUnit","nodes":[{"abstract":false,"baseContracts":[],"canonicalName":"C","contractDependencies":[],"contractKind":"contract","fullyImplemented":true,"id":14,"linearizedBaseContracts":[14],"name":"C","nameLocation":"9:1:1","nodeType":"ContractDefinition","nodes":[{"body":{"id":5,"nodeType":"Block","src":"32:6:1","statements":[{"id":4,"nodeType":"PlaceholderStatement","src":"34:1:1"}]},"id":6,"name":"M","nameLocation":"22:1:1","nodeType":"ModifierDefinition","parameters":{"id":3,"nodeType":"ParameterList","parameters":[{"constant":false,"id":2,"mutability":"mutable","name":"i","nameLocation":"29:1:1","nodeType":"VariableDeclaration","scope":6,"src":"24:6:1","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"},"typeName":{"id":1,"name":"uint","nodeType":"ElementaryTypeName","src":"24:4:1","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"visibility":"internal"}],"src":"23:8:1"},"src":"13:25:1","virtual":false,"visibility":"internal"},{"body":{"id":12,"nodeType":"Block","src":"64:2:1","statements":[]},"functionSelector":"28811f59","id":13,"implemented":true,"kind":"function","modifiers":[{"arguments":[{"hexValue":"31","id":9,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"54:1:1","typeDescriptions":{"typeIdentifier":"t_rational_1_by_1","typeString":"int_const 1"},"value":"1"}],"id":10,"kind":"modifierInvocation","modifierName":{"id":8,"name":"M","nameLocations":["52:1:1"],"nodeType":"IdentifierPath","referencedDeclaration":6,"src":"52:1:1"},"nodeType":"ModifierInvocation","src":"52:4:1"}],"name":"F","nameLocation":"48:1:1","nodeType":"FunctionDefinition","parameters":{"id":7,"nodeType":"ParameterList","parameters":[],"src":"49:2:1"},"returnParameters":{"id":11,"nodeType":"ParameterList","parameters":[],"src":"64:0:1"},"scope":14,"src":"39:27:1","stateMutability":"nonpayable","virtual":false,"visibility":"public"}],"scope":15,"src":"0:68:1","usedErrors":[]}],"src":"0:69:1"}

```

--------------------------------------------------------------------------------
/tests/hardhat-js-playground/artifacts/contracts/InheritanceBase.sol/InheritanceBase.json:
--------------------------------------------------------------------------------

```json
{
  "_format": "hh-sol-artifact-1",
  "contractName": "InheritanceBase",
  "sourceName": "contracts/InheritanceBase.sol",
  "abi": [
    {
      "anonymous": false,
      "inputs": [
        {
          "indexed": false,
          "internalType": "uint256",
          "name": "something",
          "type": "uint256"
        }
      ],
      "name": "Do",
      "type": "event"
    },
    {
      "inputs": [
        {
          "internalType": "uint256",
          "name": "something",
          "type": "uint256"
        }
      ],
      "name": "doSomething",
      "outputs": [],
      "stateMutability": "nonpayable",
      "type": "function"
    }
  ],
  "bytecode": "0x608060405234801561001057600080fd5b5061014e806100206000396000f3fe608060405234801561001057600080fd5b506004361061002b5760003560e01c8063a6b206bf14610030575b600080fd5b61004a600480360381019061004591906100c1565b61004c565b005b7f2ad1127294a42a5200f9832aacf01f051e55151abd09c0d2a055e56b214ebd4c8160405161007b91906100fd565b60405180910390a150565b600080fd5b6000819050919050565b61009e8161008b565b81146100a957600080fd5b50565b6000813590506100bb81610095565b92915050565b6000602082840312156100d7576100d6610086565b5b60006100e5848285016100ac565b91505092915050565b6100f78161008b565b82525050565b600060208201905061011260008301846100ee565b9291505056fea2646970667358221220bf22606c5b554878a183eb94c6d8d4f82fce03670d1285d5b85d2cc78ad83f2164736f6c63430008140033",
  "deployedBytecode": "0x608060405234801561001057600080fd5b506004361061002b5760003560e01c8063a6b206bf14610030575b600080fd5b61004a600480360381019061004591906100c1565b61004c565b005b7f2ad1127294a42a5200f9832aacf01f051e55151abd09c0d2a055e56b214ebd4c8160405161007b91906100fd565b60405180910390a150565b600080fd5b6000819050919050565b61009e8161008b565b81146100a957600080fd5b50565b6000813590506100bb81610095565b92915050565b6000602082840312156100d7576100d6610086565b5b60006100e5848285016100ac565b91505092915050565b6100f78161008b565b82525050565b600060208201905061011260008301846100ee565b9291505056fea2646970667358221220bf22606c5b554878a183eb94c6d8d4f82fce03670d1285d5b85d2cc78ad83f2164736f6c63430008140033",
  "linkReferences": {},
  "deployedLinkReferences": {}
}

```

--------------------------------------------------------------------------------
/tests/ast/using_for_directive.json:
--------------------------------------------------------------------------------

```json
{"absolutePath":"a","exportedSymbols":{"C":[13],"L":[4],"f":[10]},"id":14,"nodeType":"SourceUnit","nodes":[{"functionList":[{"function":{"id":1,"name":"f","nameLocations":["7:1:1"],"nodeType":"IdentifierPath","referencedDeclaration":10,"src":"7:1:1"}}],"global":false,"id":3,"nodeType":"UsingForDirective","src":"0:19:1","typeName":{"id":2,"name":"uint","nodeType":"ElementaryTypeName","src":"14:4:1","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}}},{"abstract":false,"baseContracts":[],"canonicalName":"L","contractDependencies":[],"contractKind":"library","fullyImplemented":true,"id":4,"linearizedBaseContracts":[4],"name":"L","nameLocation":"28:1:1","nodeType":"ContractDefinition","nodes":[],"scope":14,"src":"20:12:1","usedErrors":[]},{"body":{"id":9,"nodeType":"Block","src":"50:2:1","statements":[]},"id":10,"implemented":true,"kind":"freeFunction","modifiers":[],"name":"f","nameLocation":"42:1:1","nodeType":"FunctionDefinition","parameters":{"id":7,"nodeType":"ParameterList","parameters":[{"constant":false,"id":6,"mutability":"mutable","name":"","nameLocation":"-1:-1:-1","nodeType":"VariableDeclaration","scope":10,"src":"44:4:1","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"},"typeName":{"id":5,"name":"uint","nodeType":"ElementaryTypeName","src":"44:4:1","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"visibility":"internal"}],"src":"43:6:1"},"returnParameters":{"id":8,"nodeType":"ParameterList","parameters":[],"src":"50:0:1"},"scope":14,"src":"33:19:1","stateMutability":"nonpayable","virtual":false,"visibility":"internal"},{"abstract":false,"baseContracts":[],"canonicalName":"C","contractDependencies":[],"contractKind":"contract","fullyImplemented":true,"id":13,"linearizedBaseContracts":[13],"name":"C","nameLocation":"62:1:1","nodeType":"ContractDefinition","nodes":[{"global":false,"id":12,"libraryName":{"id":11,"name":"L","nameLocations":["72:1:1"],"nodeType":"IdentifierPath","referencedDeclaration":4,"src":"72:1:1"},"nodeType":"UsingForDirective","src":"66:14:1"}],"scope":14,"src":"53:29:1","usedErrors":[]}],"src":"0:83:1"}

```

--------------------------------------------------------------------------------
/tests/ast/switch.json:
--------------------------------------------------------------------------------

```json
{"absolutePath":"a","exportedSymbols":{"C":[6]},"id":7,"nodeType":"SourceUnit","nodes":[{"abstract":false,"baseContracts":[],"canonicalName":"C","contractDependencies":[],"contractKind":"contract","fullyImplemented":true,"id":6,"linearizedBaseContracts":[6],"name":"C","nameLocation":"9:1:1","nodeType":"ContractDefinition","nodes":[{"body":{"id":4,"nodeType":"Block","src":"42:154:1","statements":[{"AST":{"nodeType":"YulBlock","src":"61:129:1","statements":[{"nodeType":"YulVariableDeclaration","src":"75:10:1","value":{"kind":"number","nodeType":"YulLiteral","src":"84:1:1","type":"","value":"0"},"variables":[{"name":"v","nodeType":"YulTypedName","src":"79:1:1","type":""}]},{"cases":[{"body":{"nodeType":"YulBlock","src":"139:10:1","statements":[{"nodeType":"YulAssignment","src":"141:6:1","value":{"kind":"number","nodeType":"YulLiteral","src":"146:1:1","type":"","value":"1"},"variableNames":[{"name":"v","nodeType":"YulIdentifier","src":"141:1:1"}]}]},"nodeType":"YulCase","src":"132:17:1","value":{"kind":"number","nodeType":"YulLiteral","src":"137:1:1","type":"","value":"0"}},{"body":{"nodeType":"YulBlock","src":"170:10:1","statements":[{"nodeType":"YulAssignment","src":"172:6:1","value":{"kind":"number","nodeType":"YulLiteral","src":"177:1:1","type":"","value":"2"},"variableNames":[{"name":"v","nodeType":"YulIdentifier","src":"172:1:1"}]}]},"nodeType":"YulCase","src":"162:18:1","value":"default"}],"expression":{"arguments":[],"functionName":{"name":"calldatasize","nodeType":"YulIdentifier","src":"105:12:1"},"nodeType":"YulFunctionCall","src":"105:14:1"},"nodeType":"YulSwitch","src":"98:82:1"}]},"evmVersion":"london","externalReferences":[],"id":3,"nodeType":"InlineAssembly","src":"52:138:1"}]},"functionSelector":"26121ff0","id":5,"implemented":true,"kind":"function","modifiers":[],"name":"f","nameLocation":"26:1:1","nodeType":"FunctionDefinition","parameters":{"id":1,"nodeType":"ParameterList","parameters":[],"src":"27:2:1"},"returnParameters":{"id":2,"nodeType":"ParameterList","parameters":[],"src":"42:0:1"},"scope":6,"src":"17:179:1","stateMutability":"pure","virtual":false,"visibility":"public"}],"scope":7,"src":"0:198:1","usedErrors":[]}],"src":"0:199:1"}

```

--------------------------------------------------------------------------------
/tests/ast/source_location.json:
--------------------------------------------------------------------------------

```json
{"absolutePath":"a","exportedSymbols":{"C":[12]},"id":13,"nodeType":"SourceUnit","nodes":[{"abstract":false,"baseContracts":[],"canonicalName":"C","contractDependencies":[],"contractKind":"contract","fullyImplemented":true,"id":12,"linearizedBaseContracts":[12],"name":"C","nameLocation":"9:1:1","nodeType":"ContractDefinition","nodes":[{"body":{"id":10,"nodeType":"Block","src":"33:20:1","statements":[{"assignments":[4],"declarations":[{"constant":false,"id":4,"mutability":"mutable","name":"x","nameLocation":"40:1:1","nodeType":"VariableDeclaration","scope":10,"src":"35:6:1","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"},"typeName":{"id":3,"name":"uint","nodeType":"ElementaryTypeName","src":"35:4:1","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"visibility":"internal"}],"id":6,"initialValue":{"hexValue":"32","id":5,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"44:1:1","typeDescriptions":{"typeIdentifier":"t_rational_2_by_1","typeString":"int_const 2"},"value":"2"},"nodeType":"VariableDeclarationStatement","src":"35:10:1"},{"expression":{"id":8,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"nodeType":"UnaryOperation","operator":"++","prefix":false,"src":"47:3:1","subExpression":{"id":7,"name":"x","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":4,"src":"47:1:1","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"id":9,"nodeType":"ExpressionStatement","src":"47:3:1"}]},"functionSelector":"26121ff0","id":11,"implemented":true,"kind":"function","modifiers":[],"name":"f","nameLocation":"22:1:1","nodeType":"FunctionDefinition","parameters":{"id":1,"nodeType":"ParameterList","parameters":[],"src":"23:2:1"},"returnParameters":{"id":2,"nodeType":"ParameterList","parameters":[],"src":"33:0:1"},"scope":12,"src":"13:40:1","stateMutability":"nonpayable","virtual":false,"visibility":"public"}],"scope":13,"src":"0:55:1","usedErrors":[]}],"src":"0:56:1"}

```

--------------------------------------------------------------------------------
/aderyn_core/tests/common/closest_ancestor.rs:
--------------------------------------------------------------------------------

```rust
#![allow(clippy::collapsible_match)]
use std::{collections::BTreeMap, error::Error};

use aderyn_core::{
    ast::{NodeID, NodeType},
    capture,
    context::{
        browser::GetClosestAncestorOfTypeX,
        workspace::{ASTNode, WorkspaceContext},
    },
    detect::detector::{IssueDetector, IssueDetectorNamePool, IssueSeverity},
};
use eyre::Result;

#[derive(Default)]
pub struct ClosestAncestorDemonstrator {
    // Keys are: [0] source file name, [1] line number, [2] character location of node.
    // Do not add items manually, use `capture!` to add nodes to this BTreeMap.
    found_instances: BTreeMap<(String, usize, String), NodeID>,
}

/*

In ParentChainContract.sol, there is only 1 assignment done. The goal is to capture it first, second and third parent
*/

impl IssueDetector for ClosestAncestorDemonstrator {
    fn detect(&mut self, context: &WorkspaceContext) -> Result<bool, Box<dyn Error>> {
        for assignment in context.assignments() {
            capture!(self, context, assignment);

            if let Some(ASTNode::Block(block)) =
                assignment.closest_ancestor_of_type(context, NodeType::Block)
            {
                capture!(self, context, block);
            }

            if let Some(for_statement) =
                assignment.closest_ancestor_of_type(context, NodeType::ForStatement)
            {
                capture!(self, context, for_statement);

                if let Some(ASTNode::Block(block)) =
                    for_statement.closest_ancestor_of_type(context, NodeType::Block)
                {
                    capture!(self, context, block);
                }
            }
        }

        Ok(!self.found_instances.is_empty())
    }

    fn severity(&self) -> IssueSeverity {
        IssueSeverity::High
    }

    fn title(&self) -> String {
        String::from("Closest Parent Demonstrator")
    }

    fn description(&self) -> String {
        String::from("Closest Parent Demonstrator")
    }

    fn instances(&self) -> BTreeMap<(String, usize, String), NodeID> {
        self.found_instances.clone()
    }

    fn name(&self) -> String {
        format!("{}", IssueDetectorNamePool::CentralizationRisk)
    }
}

```

--------------------------------------------------------------------------------
/Cargo.toml:
--------------------------------------------------------------------------------

```toml
[workspace]
resolver="2"

members = [
    "aderyn",
    "aderyn_core",
    "aderyn_driver",
    "tools/*",
]

[workspace.package]
edition = "2024"
authors = ["Cyfrin <[email protected]>"]
description = "Rust based Solidity AST analyzer backend"
license = "MIT"
repository = "https://github.com/cyfrin/aderyn"
homepage = "https://github.com/cyfrin/aderyn"

[workspace.lints.clippy]
large_enum_variant = "allow"
result_large_err = "allow"

[workspace.dependencies]
aderyn_core = { version = "0.6.5", path = "aderyn_core" }
aderyn_driver = { version = "0.6.5", path = "aderyn_driver" }
indoc = "2"
clap = "4.4.6"
criterion = "0.5.1"
derive_more = "2"
eyre = "0.6.12"
field_access = "0.1.8"
ignore = "0.4.21"
lazy-regex = "3.2.0"
log = "0.4.22"
notify-debouncer-full = "0.3.1"
num-bigint = "0.4"
num-traits = "0.2"
once_cell = "1.19.0"
phf = "0.11.2"
prettytable = "0.10.0"
rayon = "1.8.0"
reqwest = { version = "0.12.2", default-features = false }
semver = "1.0.26"
serde = "1.0.160"
serde-sarif = "0.4.2"
serde_json = "1.0.96"
serde_repr = "0.1.12"
serial_test = "3.0.0"
strum = "0.26"
termcolor = "1.4.1"
tokio = "1.40.0"
toml = "0.8.13"
tower-lsp = "0.20.0"
dunce = "=1.0.5"
petgraph = "0"
crossbeam-channel = "0.5.15"
webbrowser = "1.0.4"
urlencoding = "2.1.3"
derive_builder = "0.20.2"
rmcp = { version = "0.6", features = ["transport-streamable-http-server"] }
axum = { version = "0.8", features = ["macros"] }
askama = { version = "0.14.0", features = ["full"] }
clap_complete = "4.4"
regex = "1.12.2"

# Uncomment in Production (just before merging to dev)
# Cyfrin managed github repository
solidity_ast = { git = "https://github.com/Cyfrin/solidity-ast-rs", tag = "v0.0.1-alpha.beta.5", package = "solidity-ast" }

# Uncomment when debugging in branch (PR)
# solidity_ast = { git = "https://github.com/Cyfrin/solidity-ast-rs", branch = "main", package = "solidity-ast" }

# Uncomment when debuggin locally
# solidity_ast = { path = "../solidity-ast-rs", package = "solidity-ast"}

[profile.release]
codegen-units = 1
lto = true

[profile.lspdev]
inherits = "dist"

[profile.lspdev.package."*"]
inherits = "dist"

# The profile that 'dist' will build with
[profile.dist]
inherits = "release"
lto = "thin"

```

--------------------------------------------------------------------------------
/aderyn_core/src/detect/high/rtlo.rs:
--------------------------------------------------------------------------------

```rust
use std::{collections::BTreeMap, error::Error};

use crate::ast::NodeID;

use crate::{
    capture,
    context::workspace::WorkspaceContext,
    detect::detector::{IssueDetector, IssueDetectorNamePool, IssueSeverity},
};
use eyre::Result;

#[derive(Default)]
pub struct RTLODetector {
    // Keys are: [0] source file name, [1] line number, [2] character location of node.
    // Do not add items manually, use `capture!` to add nodes to this BTreeMap.
    found_instances: BTreeMap<(String, usize, String), NodeID>,
}

impl IssueDetector for RTLODetector {
    fn detect(&mut self, context: &WorkspaceContext) -> Result<bool, Box<dyn Error>> {
        // When you have found an instance of the issue,
        // use the following macro to add it to `found_instances`:
        //
        // capture!(self, context, item);

        for source_unit in context.source_units() {
            if let Some(content) = &source_unit.source
                && content.contains('\u{202e}')
            {
                capture!(self, context, source_unit);
            }
        }

        Ok(!self.found_instances.is_empty())
    }

    fn severity(&self) -> IssueSeverity {
        IssueSeverity::High
    }

    fn title(&self) -> String {
        String::from("RTLO character detected in file: \\u{202e}")
    }

    fn description(&self) -> String {
        String::from(
            "The right to left override character may be misleading and cause potential attacks by visually misordering method arguments.",
        )
    }

    fn instances(&self) -> BTreeMap<(String, usize, String), NodeID> {
        self.found_instances.clone()
    }

    fn name(&self) -> String {
        IssueDetectorNamePool::RTLO.to_string()
    }
}

#[cfg(test)]
mod rtlo_detector_tests {

    use crate::detect::{detector::IssueDetector, high::rtlo::RTLODetector};

    #[test]

    fn test_rtlo_detector() {
        let context = crate::detect::test_utils::load_solidity_source_unit(
            "../tests/contract-playground/src/RTLO.sol",
        );

        let mut detector = RTLODetector::default();
        let found = detector.detect(&context).unwrap();
        assert!(found);
        assert_eq!(detector.instances().len(), 1);
    }
}

```

--------------------------------------------------------------------------------
/aderyn_core/src/context/mcp.rs:
--------------------------------------------------------------------------------

```rust
// Imports
use crate::context::{macros::make_route, workspace::WorkspaceContext};
use rmcp::{
    ErrorData as McpError,
    handler::server::{tool::ToolRoute, wrapper::Parameters},
    model::*,
    schemars::JsonSchema,
};
use solidity_ast::ProjectConfigInput;
use std::{any::Any, path::PathBuf, sync::Arc};
use strum::{Display, EnumString};

// Tools
pub mod callgraph;
pub mod contract_surface;
pub mod list_contracts;
pub mod node_finder;
pub mod node_summarizer;
pub mod project_overview;
pub mod tool_guide;

pub use callgraph::CallgraphTool;
pub use contract_surface::ContractSurfaceTool;
pub use list_contracts::ListContractsTool;
pub use node_finder::NodeFinderTool;
pub use node_summarizer::NodeSummarizerTool;
pub use project_overview::ProjectOverviewTool;
pub use tool_guide::ToolGuide;

pub struct ModelContextProtocolState {
    pub contexts: Vec<WorkspaceContext>,
    pub root_path: PathBuf,
    pub project_config: ProjectConfigInput,
}

pub trait ModelContextProtocolTool: Send + Sync + Clone {
    type Input: JsonSchema + Any + Send;

    fn new(state: Arc<ModelContextProtocolState>) -> Self;

    // Appears to the MCP client
    fn name(&self) -> String;

    // LLM uses this information to decide if this tool should be called
    fn description(&self) -> String;

    // Tool execution logic
    fn execute(&self, input: Parameters<Self::Input>) -> Result<CallToolResult, McpError>;
}

pub fn get_all_mcp_tools<T>(state: Arc<ModelContextProtocolState>) -> Vec<ToolRoute<T>>
where
    T: Send + Sync + 'static,
{
    vec![
        // register MCP tools here
        make_route!(ToolGuide, state),
        make_route!(ProjectOverviewTool, state),
        make_route!(ListContractsTool, state),
        make_route!(ContractSurfaceTool, state),
        make_route!(CallgraphTool, state),
        make_route!(NodeSummarizerTool, state),
        make_route!(NodeFinderTool, state),
    ]
}

#[derive(Debug, PartialEq, EnumString, Display)]
#[strum(serialize_all = "snake_case")]
pub enum MCPToolNamePool {
    AderynGetToolGuide,
    AderynGetProjectOverview,
    AderynListContracts,
    AderynContractSurfaceInspector,
    AderynExploreCallgraphFromEntrypoint,
    AderynNodeSummarizer,
    AderynNodeFinder,
}

```

--------------------------------------------------------------------------------
/aderyn_core/tests/common/immediate_children.rs:
--------------------------------------------------------------------------------

```rust
#![allow(clippy::collapsible_match)]
use std::{collections::BTreeMap, error::Error};

use aderyn_core::{
    ast::{NodeID, NodeType},
    capture,
    context::{browser::GetImmediateChildren, workspace::WorkspaceContext},
    detect::detector::{IssueDetector, IssueDetectorNamePool, IssueSeverity},
};
use eyre::Result;

#[derive(Default)]
pub struct ImmediateChildrenDemonstrator {
    // Keys are: [0] source file name, [1] line number, [2] character location of node.
    // Do not add items manually, use `capture!` to add nodes to this BTreeMap.
    found_instances: BTreeMap<(String, usize, String), NodeID>,
}

impl IssueDetector for ImmediateChildrenDemonstrator {
    fn detect(&mut self, context: &WorkspaceContext) -> Result<bool, Box<dyn Error>> {
        // Step 1: Find the ParentChain contract

        let parent_chain_contract = context
            .contract_definitions()
            .into_iter()
            .filter(|x| x.name.contains("ParentChain"))
            .take(1)
            .next()
            .unwrap();

        // Step 2: Find the `increment` function

        let inc = parent_chain_contract
            .function_definitions()
            .into_iter()
            .filter(|x| x.name.contains("increment"))
            .take(1)
            .next()
            .unwrap();

        if let Some(children) = inc.body.as_ref().unwrap().children(context) {
            for child in children {
                assert!(
                    child.node_type() == NodeType::IfStatement,
                    "Only if statement should be caught in function body's immediate children!"
                );
                capture!(self, context, child);
            }
        }

        Ok(!self.found_instances.is_empty())
    }

    fn severity(&self) -> IssueSeverity {
        IssueSeverity::High
    }

    fn title(&self) -> String {
        String::from("ImmediateChildrenDemonstrator")
    }

    fn description(&self) -> String {
        String::from("ImmediateChildrenDemonstrator")
    }

    fn instances(&self) -> BTreeMap<(String, usize, String), NodeID> {
        self.found_instances.clone()
    }

    fn name(&self) -> String {
        format!("{}", IssueDetectorNamePool::CentralizationRisk)
    }
}

```

--------------------------------------------------------------------------------
/RELEASE_CHECKLIST.md:
--------------------------------------------------------------------------------

```markdown
# Release checklist

This checklist is meant to be used as a guide for the `aderyn` release process.

Releases are always made in lockstep, meaning that all crates in the repository
are released with the same version number, regardless of whether they have
changed or not.

## Requirements

- [cargo-release](https://github.com/crate-ci/cargo-release): `cargo install cargo-release`
- [gh](https://cli.github.com/): `brew install gh`

Stay logged in with `gh auth login`

## Pre-requisites

- Code in the `dev` branch must be in good shape for release.
- If there are breaking changes, a newer version of VSCode extension is ready to be released in it's `main` branch.

## Steps

- [ ] Cut a release.
    - [ ] Switch to dev branch and pull latest changes.
    - [ ] Run `cargo patch`. Wait until the command is fully done.
    - [ ] Generate Release Notes in the Github's Release page

- **NOTE: Expect the following in CI**:
  * Sarif report tests fail because of version mismatch.
  * After the building of global artifacts, `aderyn_driver` and `aderyn_core` crates fail to publish.
  * Binary crate `aderyn` is successfully published.

- [ ] Create a checkpoint on `master`.
    - [ ] Run `git checkout master && git pull`
    - [ ] Run `git checkout -b master-merge-<version-to-be-released>`.
    - [ ] Merge `dev` into it and preserve all changes in `dev`. `git merge --squash -X theirs dev`.
    - [ ] Sometimes if conflicts are not auto-resolved, pick to keep all the changes from `dev`
    - [ ] Merge it back to master by creating a PR (Verify CI tests)

- [ ] Switch back to `dev` branch with `git checkout dev`.

> NOTE: Replace `patch` with `minor` based on the needs.

## Breaking change

If at least one of the following is observed, it's considered a breaking change. In that case, the minor version must be bumped at a minimum. This ensures the VS Code extension remains compatible, as users will be prompted to install the updated version.

- [ ] Changes in CLI flags - `--lsp`, `--json`, `--stdout`
- [ ] Changes in the JSON output format.
- [ ] Arbitrary Changes to LSP server.
- [ ] Changes to asset names or URLs in Github Releases.
- [ ] Changes to `aderyn.toml` template.

Above is a non-exhaustive list There can be more.

```

--------------------------------------------------------------------------------
/aderyn_core/src/detect/low/division_before_multiplication.rs:
--------------------------------------------------------------------------------

```rust
use std::{collections::BTreeMap, error::Error};

use crate::ast::NodeID;

use crate::{
    ast::Expression,
    capture,
    context::workspace::WorkspaceContext,
    detect::detector::{IssueDetector, IssueDetectorNamePool, IssueSeverity},
};
use eyre::Result;

#[derive(Default)]
pub struct DivisionBeforeMultiplicationDetector {
    // Keys are source file name, line number, and description
    found_instances: BTreeMap<(String, usize, String), NodeID>,
}

impl IssueDetector for DivisionBeforeMultiplicationDetector {
    fn detect(&mut self, context: &WorkspaceContext) -> Result<bool, Box<dyn Error>> {
        for op in context.binary_operations().iter().filter(|op| op.operator == "*") {
            if let Expression::BinaryOperation(left_op) = op.left_expression.as_ref()
                && left_op.operator == "/"
            {
                capture!(self, context, left_op)
            }
        }

        Ok(!self.found_instances.is_empty())
    }

    fn severity(&self) -> IssueSeverity {
        IssueSeverity::Low
    }

    fn title(&self) -> String {
        String::from("Incorrect Order of Division and Multiplication")
    }

    fn description(&self) -> String {
        String::from("Division operations followed directly by multiplication operations can lead to precision loss due to the way integer arithmetic is handled in Solidity./
        Consider Multiplication before Division.")
    }

    fn instances(&self) -> BTreeMap<(String, usize, String), NodeID> {
        self.found_instances.clone()
    }

    fn name(&self) -> String {
        format!("{}", IssueDetectorNamePool::DivisionBeforeMultiplication)
    }
}

#[cfg(test)]
mod division_before_multiplication_detector_tests {

    use super::DivisionBeforeMultiplicationDetector;
    use crate::detect::detector::IssueDetector;

    #[test]

    fn test_template_detector() {
        let context = crate::detect::test_utils::load_solidity_source_unit(
            "../tests/contract-playground/src/DivisionBeforeMultiplication.sol",
        );

        let mut detector = DivisionBeforeMultiplicationDetector::default();
        let found = detector.detect(&context).unwrap();
        assert!(found);
        assert_eq!(detector.instances().len(), 4);
    }
}

```

--------------------------------------------------------------------------------
/aderyn_core/src/ast/impls/node/source_units.rs:
--------------------------------------------------------------------------------

```rust
use crate::{ast::*, visitor::ast_visitor::*};
use eyre::Result;

impl Node for SourceUnitNode {
    fn accept(&self, visitor: &mut impl ASTConstVisitor) -> Result<()> {
        match self {
            SourceUnitNode::PragmaDirective(pragma_directive) => pragma_directive.accept(visitor),
            SourceUnitNode::ImportDirective(import_directive) => import_directive.accept(visitor),
            SourceUnitNode::ContractDefinition(contract_definition) => {
                contract_definition.accept(visitor)
            }
            SourceUnitNode::StructDefinition(struct_definition) => {
                struct_definition.accept(visitor)
            }
            SourceUnitNode::EnumDefinition(enum_definition) => enum_definition.accept(visitor),
            SourceUnitNode::ErrorDefinition(error_definition) => error_definition.accept(visitor),
            SourceUnitNode::VariableDeclaration(variable_declaration) => {
                variable_declaration.accept(visitor)
            }
            SourceUnitNode::UserDefinedValueTypeDefinition(user_defined_value_type_definition) => {
                user_defined_value_type_definition.accept(visitor)
            }
            SourceUnitNode::FunctionDefinition(function_defn) => function_defn.accept(visitor),
            SourceUnitNode::UsingForDirective(using_for_directive) => {
                using_for_directive.accept(visitor)
            }
            SourceUnitNode::EventDefinition(event_definition) => event_definition.accept(visitor),
        }
    }
    fn accept_id(&self, visitor: &mut impl ASTConstVisitor) -> Result<()> {
        visitor.visit_node_id(self.get_node_id())?;
        Ok(())
    }
}

impl Node for SourceUnit {
    fn accept(&self, visitor: &mut impl ASTConstVisitor) -> Result<()> {
        if visitor.visit_source_unit(self)? {
            list_accept(&self.nodes, visitor)?;
        }
        self.accept_metadata(visitor)?;
        visitor.end_visit_source_unit(self)
    }
    fn accept_metadata(&self, visitor: &mut impl ASTConstVisitor) -> Result<()> {
        let node_ids = &self.nodes.iter().flat_map(|x| x.get_node_id()).collect::<Vec<_>>();
        visitor.visit_immediate_children(self.id, node_ids.clone())?;
        Ok(())
    }
    macros::accept_id!();
}

```

--------------------------------------------------------------------------------
/tests/ast/long_type_name_binary_operation.json:
--------------------------------------------------------------------------------

```json
{"absolutePath":"a","exportedSymbols":{"c":[11]},"id":12,"nodeType":"SourceUnit","nodes":[{"abstract":false,"baseContracts":[],"canonicalName":"c","contractDependencies":[],"contractKind":"contract","fullyImplemented":true,"id":11,"linearizedBaseContracts":[11],"name":"c","nameLocation":"9:1:1","nodeType":"ContractDefinition","nodes":[{"body":{"id":9,"nodeType":"Block","src":"33:19:1","statements":[{"assignments":[4],"declarations":[{"constant":false,"id":4,"mutability":"mutable","name":"a","nameLocation":"40:1:1","nodeType":"VariableDeclaration","scope":9,"src":"35:6:1","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"},"typeName":{"id":3,"name":"uint","nodeType":"ElementaryTypeName","src":"35:4:1","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"visibility":"internal"}],"id":8,"initialValue":{"commonType":{"typeIdentifier":"t_rational_5_by_1","typeString":"int_const 5"},"id":7,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"leftExpression":{"hexValue":"32","id":5,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"44:1:1","typeDescriptions":{"typeIdentifier":"t_rational_2_by_1","typeString":"int_const 2"},"value":"2"},"nodeType":"BinaryOperation","operator":"+","rightExpression":{"hexValue":"33","id":6,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"48:1:1","typeDescriptions":{"typeIdentifier":"t_rational_3_by_1","typeString":"int_const 3"},"value":"3"},"src":"44:5:1","typeDescriptions":{"typeIdentifier":"t_rational_5_by_1","typeString":"int_const 5"}},"nodeType":"VariableDeclarationStatement","src":"35:14:1"}]},"functionSelector":"26121ff0","id":10,"implemented":true,"kind":"function","modifiers":[],"name":"f","nameLocation":"22:1:1","nodeType":"FunctionDefinition","parameters":{"id":1,"nodeType":"ParameterList","parameters":[],"src":"23:2:1"},"returnParameters":{"id":2,"nodeType":"ParameterList","parameters":[],"src":"33:0:1"},"scope":11,"src":"13:39:1","stateMutability":"nonpayable","virtual":false,"visibility":"public"}],"scope":12,"src":"0:54:1","usedErrors":[]}],"src":"0:55:1"}

```

--------------------------------------------------------------------------------
/aderyn_core/src/detect/high/dangerous_unary_operator.rs:
--------------------------------------------------------------------------------

```rust
use std::{collections::BTreeMap, error::Error};

use crate::ast::NodeID;

use crate::{
    capture,
    context::{browser::Peek, workspace::WorkspaceContext},
    detect::detector::{IssueDetector, IssueDetectorNamePool, IssueSeverity},
};
use eyre::Result;

#[derive(Default)]
pub struct DangerousUnaryOperatorDetector {
    // Keys are: [0] source file name, [1] line number, [2] character location of node.
    // Do not add items manually, use `capture!` to add nodes to this BTreeMap.
    found_instances: BTreeMap<(String, usize, String), NodeID>,
}

impl IssueDetector for DangerousUnaryOperatorDetector {
    fn detect(&mut self, context: &WorkspaceContext) -> Result<bool, Box<dyn Error>> {
        for assignment in context.assignments() {
            if let Some(content) = assignment.peek(context)
                && (content.contains("=-") || content.contains("=+"))
            {
                capture!(self, context, assignment);
            }
        }

        Ok(!self.found_instances.is_empty())
    }

    fn severity(&self) -> IssueSeverity {
        IssueSeverity::High
    }

    fn title(&self) -> String {
        String::from("Dangerous unary operator")
    }

    fn description(&self) -> String {
        String::from(
            "Potentially mistaken `=+` for `+=` or `=-` for `-=`. This acts as an assignment instead of an increment or decrement.\
        Use the correct operator to increment or decrement a variable.",
        )
    }

    fn instances(&self) -> BTreeMap<(String, usize, String), NodeID> {
        self.found_instances.clone()
    }

    fn name(&self) -> String {
        IssueDetectorNamePool::DangerousUnaryOperator.to_string()
    }
}

#[cfg(test)]
mod dangerous_unary_expression_tests {

    use crate::detect::{
        detector::IssueDetector, high::dangerous_unary_operator::DangerousUnaryOperatorDetector,
    };

    #[test]
    fn test_dangerous_unary_operator() {
        let context = crate::detect::test_utils::load_solidity_source_unit(
            "../tests/contract-playground/src/DangerousUnaryOperator.sol",
        );

        let mut detector = DangerousUnaryOperatorDetector::default();
        let found = detector.detect(&context).unwrap();

        assert!(found);
        assert_eq!(detector.instances().len(), 2);
    }
}

```

--------------------------------------------------------------------------------
/aderyn_core/src/context/browser/location.rs:
--------------------------------------------------------------------------------

```rust
use std::cmp::Ordering;

use crate::{
    ast::NodeID,
    context::workspace::WorkspaceContext,
    visitor::ast_visitor::{ASTConstVisitor, Node},
};

pub trait AppearsAfterNodeLocation<T: Node + ?Sized> {
    fn appears_after(&self, context: &WorkspaceContext, other: &T) -> Option<bool>;
}

pub trait AppearsBeforeNodeLocation<T: Node + ?Sized> {
    fn appears_before(&self, context: &WorkspaceContext, other: &T) -> Option<bool>;
}

#[derive(Default)]
struct NodeIDReceiver {
    id: Option<NodeID>,
}

impl ASTConstVisitor for NodeIDReceiver {
    fn visit_node_id(&mut self, node_id: Option<NodeID>) -> eyre::Result<()> {
        self.id = node_id;
        Ok(())
    }
}

impl<T: Node + ?Sized, U: Node + ?Sized> AppearsBeforeNodeLocation<U> for T {
    fn appears_before(&self, context: &WorkspaceContext, other: &U) -> Option<bool> {
        // Setup a Node ID receiver
        let mut node_id_receiver = NodeIDReceiver::default();

        // Find the ID of the node this method is called upon
        self.accept_id(&mut node_id_receiver).ok()?;
        let current_node_id = node_id_receiver.id?;

        // FInd the ID of the target node
        other.accept_id(&mut node_id_receiver).ok()?;
        let target_node_id = node_id_receiver.id?;

        match context.get_relative_location_of_nodes(current_node_id, target_node_id)? {
            Ordering::Less => Some(true),
            Ordering::Greater => Some(false),
            Ordering::Equal => Some(false),
        }
    }
}

impl<T: Node + ?Sized, U: Node + ?Sized> AppearsAfterNodeLocation<U> for T {
    fn appears_after(&self, context: &WorkspaceContext, other: &U) -> Option<bool> {
        // Setup a Node ID receiver
        let mut node_id_receiver = NodeIDReceiver::default();

        // Find the ID of the node this method is called upon
        self.accept_id(&mut node_id_receiver).ok()?;
        let current_node_id = node_id_receiver.id?;

        // FInd the ID of the target node
        other.accept_id(&mut node_id_receiver).ok()?;
        let target_node_id = node_id_receiver.id?;

        match context.get_relative_location_of_nodes(current_node_id, target_node_id)? {
            Ordering::Less => Some(false),
            Ordering::Greater => Some(true),
            Ordering::Equal => Some(false),
        }
    }
}

```

--------------------------------------------------------------------------------
/aderyn_core/src/detect/high/experimental_encoder.rs:
--------------------------------------------------------------------------------

```rust
use std::{collections::BTreeMap, error::Error};

use crate::ast::NodeID;

use crate::{
    capture,
    context::workspace::WorkspaceContext,
    detect::detector::{IssueDetector, IssueDetectorNamePool, IssueSeverity},
};
use eyre::Result;

#[derive(Default)]
pub struct ExperimentalEncoderDetector {
    // Keys are: [0] source file name, [1] line number, [2] character location of node.
    // Do not add items manually, use `capture!` to add nodes to this BTreeMap.
    found_instances: BTreeMap<(String, usize, String), NodeID>,
}

impl IssueDetector for ExperimentalEncoderDetector {
    fn detect(&mut self, context: &WorkspaceContext) -> Result<bool, Box<dyn Error>> {
        for pragma_directive in context.pragma_directives() {
            for literal in &pragma_directive.literals {
                if literal == "experimental" {
                    capture!(self, context, pragma_directive);
                }
            }
        }

        Ok(!self.found_instances.is_empty())
    }

    fn severity(&self) -> IssueSeverity {
        IssueSeverity::High
    }

    fn title(&self) -> String {
        String::from("Experimental ABI Encoder")
    }

    fn description(&self) -> String {
        String::from(
            "Experimental encoders should not be used in production. There are multiple known compiler bugs that are caused by the experimental encoder. Upgrade your solidity version to remove the need for experimental features.",
        )
    }

    fn instances(&self) -> BTreeMap<(String, usize, String), NodeID> {
        self.found_instances.clone()
    }

    fn name(&self) -> String {
        IssueDetectorNamePool::ExperimentalEncoder.to_string()
    }
}

#[cfg(test)]
mod storage_array_encode_compiler_bug_detector_tests {

    use crate::detect::{
        detector::IssueDetector, high::experimental_encoder::ExperimentalEncoderDetector,
    };

    #[test]

    fn test_storage_array_encode_compiler_bug_detector() {
        let context = crate::detect::test_utils::load_solidity_source_unit(
            "../tests/contract-playground/src/ExperimentalEncoder.sol",
        );

        let mut detector = ExperimentalEncoderDetector::default();
        let found = detector.detect(&context).unwrap();
        assert!(found);
        assert_eq!(detector.instances().len(), 1);
    }
}

```

--------------------------------------------------------------------------------
/aderyn_core/src/ast/impls/disp/functions.rs:
--------------------------------------------------------------------------------

```rust
use crate::ast::*;
use std::fmt::Display;

impl Display for FunctionKind {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        f.write_fmt(format_args!("{}", format!("{self:?}").to_lowercase()))
    }
}

impl Display for ParameterList {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        f.write_str("(")?;

        for (i, parameter) in self.parameters.iter().enumerate() {
            if i > 0 {
                f.write_str(", ")?;
            }

            f.write_fmt(format_args!("{parameter}"))?;
        }

        f.write_str(")")
    }
}

impl Display for OverrideSpecifier {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        f.write_str("override")?;

        if !self.overrides.is_empty() {
            f.write_str("(")?;

            for (i, identifier_path) in self.overrides.iter().enumerate() {
                if i > 0 {
                    f.write_str(", ")?;
                }

                f.write_fmt(format_args!("{:?}", identifier_path))?;
            }

            f.write_str(")")?;
        }

        Ok(())
    }
}

impl Display for FunctionDefinition {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        f.write_fmt(format_args!("{}", self.kind()))?;

        if !self.name.is_empty() {
            f.write_fmt(format_args!(" {}", self.name))?;
        }

        f.write_fmt(format_args!("{} {}", self.parameters, self.visibility))?;

        if let Some(state_mutability) = &self.state_mutability
            && *state_mutability != StateMutability::NonPayable
        {
            f.write_fmt(format_args!(" {}", state_mutability))?;
        }

        if self.is_virtual {
            f.write_str(" virtual")?;
        }

        if let Some(overrides) = self.overrides.as_ref() {
            f.write_fmt(format_args!(" {overrides}"))?;
        }

        for modifier in self.modifiers.iter() {
            f.write_fmt(format_args!(" {modifier}"))?;
        }

        if !self.return_parameters.parameters.is_empty() {
            f.write_fmt(format_args!(" returns {}", self.return_parameters))?;
        }

        match self.body.as_ref() {
            Some(body) => f.write_fmt(format_args!(" {body}")),
            None => f.write_str(";"),
        }
    }
}

```

--------------------------------------------------------------------------------
/aderyn_core/templates/mcp-tool-response/callgraph.md:
--------------------------------------------------------------------------------

```markdown
## Callgraph for {{ contract.name }} contract when traversed from {{ entrypoint_function.name }}

*Compilation Unit index:* {{ compilation_unit_index }}

*Contract:* {{ contract.name }} | Node ID: {{ contract.node_id }}

*Entrypoint function:* {{ entrypoint_function.name }} | Node ID: {{ entrypoint_function.node_id }}

Below is a adjacency list representation of the subgraph of {{ contract.name }}'s callgraph. It covers all function or modifiers nodes reachable when we start traversal from the single entrypoint function `{{ entrypoint_function.name }}`   with Node ID: {{ entrypoint_function.node_id }}

**Note:** This represents only the portion of {{ contract.name }}'s complete callgraph that is reachable from this specific entrypoint. Other public/external functions in the contract and their call chains are not included unless they are called by `{{ entrypoint_function.name }}`.

Every number in the adjacency list is a Node ID of a function or a modifier node.
For example, if there is an edge from `A->B` (i.e A calls B) and `A->C` (A calls C), it would be represented as *A -> B, C*

### Adjacency List Graph of NodeIDs

{% for (from, to_list) in &graph %}
{% if to_list.len() > 0 %}
- {{ from }} -> {% for (i, v) in to_list.iter().enumerate() %} {{ v }}{% if i != to_list.len() %},{% endif %} {% endfor %}
{% else %}
- {{ from }} -> *empty*
{% endif %}
{% endfor %}

### Reverse Post Order of nodes in the above graph and their corresponding Node IDs

{% for node in post_order_nodes.iter().rev() %}
**{{ node.name }} ({{ node.node_id }})** calls:
{% if node.called_nodes.len() == 0 %}
  - No subsequent calls found
{% else %}
{% for called_node in node.called_nodes %}
  - {{ called_node.name }} ({{ called_node.node_id }})
{% endfor %}
{% endif %}
{% endfor %}

The above order provides an approximation of the actual flow of data when a transaction reaches {{ entrypoint_function.name }} The infamouse LLVM project uses this technique to perform analysis so it is a very useful piece of information.

### Next steps:
It is maybe helpful to now run the node summarizer tool on function nodes and modifier nodes in the above output. That gives access to the source code and some potentially interesting metadata concerning those functions. To invoke the tool you have to pass the compilation unit index and the node ID mentioned above.

```

--------------------------------------------------------------------------------
/aderyn_core/src/context/browser/siblings.rs:
--------------------------------------------------------------------------------

```rust
use crate::{
    ast::*,
    context::workspace::{ASTNode, WorkspaceContext},
    visitor::ast_visitor::{ASTConstVisitor, Node},
};

use super::{GetImmediateChildren, SortNodeReferencesToSequence};

pub trait GetNextSibling {
    /// Get the next sibling an ASTNode
    fn next_sibling<'a>(&self, context: &'a WorkspaceContext) -> Option<&'a ASTNode>;
}

pub trait GetPreviousSibling {
    /// Get the previous sibling an ASTNode
    fn previous_sibling<'a>(&self, context: &'a WorkspaceContext) -> Option<&'a ASTNode>;
}

#[derive(Default)]
struct NodeIDReceiver {
    id: Option<NodeID>,
}

impl ASTConstVisitor for NodeIDReceiver {
    fn visit_node_id(&mut self, node_id: Option<NodeID>) -> eyre::Result<()> {
        self.id = node_id;
        Ok(())
    }
}

impl<T: Node + ?Sized> GetNextSibling for T {
    fn next_sibling<'a>(&self, context: &'a WorkspaceContext) -> Option<&'a ASTNode> {
        // Setup a Node ID receiver
        let mut node_id_receiver = NodeIDReceiver::default();

        // Find the ID of the node this method is called upon
        self.accept_id(&mut node_id_receiver).ok()?;
        let current_node_id = node_id_receiver.id?;

        let parent = context.get_parent(current_node_id)?;
        let children = parent.children(context)?;
        let sorted_children = children.sort_by_src_position(context)?;

        for i in 0..sorted_children.len() - 1 {
            if sorted_children[i].id()? == current_node_id {
                return Some(sorted_children[i + 1]);
            }
        }

        None
    }
}

impl<T: Node + ?Sized> GetPreviousSibling for T {
    fn previous_sibling<'a>(&self, context: &'a WorkspaceContext) -> Option<&'a ASTNode> {
        // Setup a Node ID receiver
        let mut node_id_receiver = NodeIDReceiver::default();

        // Find the ID of the node this method is called upon
        self.accept_id(&mut node_id_receiver).ok()?;
        let current_node_id = node_id_receiver.id?;

        let parent = context.get_parent(current_node_id)?;
        let children = parent.children(context)?;
        let sorted_children = children.sort_by_src_position(context)?;

        for i in (1..sorted_children.len()).rev() {
            if sorted_children[i].id()? == current_node_id {
                return Some(sorted_children[i - 1]);
            }
        }

        None
    }
}

```

--------------------------------------------------------------------------------
/aderyn_core/src/context/graph/callgraph/legacy.rs:
--------------------------------------------------------------------------------

```rust
use crate::{
    ast::{NodeID, NodeType},
    context::{
        browser::{ExtractReferencedDeclarations, GetClosestAncestorOfTypeX},
        workspace::{ASTNode, WorkspaceContext},
    },
};

pub(super) fn derive_outward_surface_points(
    context: &WorkspaceContext,
    nodes: &[&ASTNode],
) -> Vec<NodeID> {
    let mut outward_surface_points = vec![];
    for &node in nodes {
        if node.node_type() == NodeType::FunctionDefinition
            || node.node_type() == NodeType::ModifierDefinition
        {
            if let Some(id) = node.id() {
                outward_surface_points.push(id);
            }
        } else {
            let parent_surface_point = node
                .closest_ancestor_of_type(context, NodeType::FunctionDefinition)
                .or_else(|| node.closest_ancestor_of_type(context, NodeType::ModifierDefinition));
            if let Some(parent_surface_point) = parent_surface_point
                && let Some(parent_surface_point_id) = parent_surface_point.id()
            {
                outward_surface_points.push(parent_surface_point_id);
            }
        }
    }
    outward_surface_points
}

pub(super) fn derive_entry_points(nodes: &[&ASTNode]) -> super::Result<Vec<NodeID>> {
    let mut entry_points = vec![];
    for &node in nodes {
        let node_id =
            node.id().ok_or_else(|| super::Error::UnidentifiedEntryPointNode(node.clone()))?;
        entry_points.push(node_id);
    }
    Ok(entry_points)
}

pub(super) fn derive_inward_surface_points_legacy(
    context: &WorkspaceContext,
    nodes: &[&ASTNode],
) -> Vec<NodeID> {
    let mut inward_surface_points = vec![];

    // Construct inward surface points
    for &node in nodes {
        let referenced_declarations = ExtractReferencedDeclarations::from(node).extracted;

        for declared_id in referenced_declarations {
            if let Some(node) = context.nodes.get(&declared_id) {
                if node.node_type() == NodeType::ModifierDefinition {
                    inward_surface_points.push(declared_id);
                } else if let ASTNode::FunctionDefinition(function_definition) = node
                    && function_definition.implemented
                {
                    inward_surface_points.push(declared_id);
                }
            }
        }
    }

    inward_surface_points
}

```

--------------------------------------------------------------------------------
/tests/ast/contract_dep_order.json:
--------------------------------------------------------------------------------

```json
{"absolutePath":"a","exportedSymbols":{"A":[1],"B":[4],"C":[7],"D":[10],"E":[13]},"id":14,"nodeType":"SourceUnit","nodes":[{"abstract":false,"baseContracts":[],"canonicalName":"A","contractDependencies":[],"contractKind":"contract","fullyImplemented":true,"id":1,"linearizedBaseContracts":[1],"name":"A","nameLocation":"9:1:1","nodeType":"ContractDefinition","nodes":[],"scope":14,"src":"0:14:1","usedErrors":[]},{"abstract":false,"baseContracts":[{"baseName":{"id":2,"name":"A","nameLocations":["29:1:1"],"nodeType":"IdentifierPath","referencedDeclaration":1,"src":"29:1:1"},"id":3,"nodeType":"InheritanceSpecifier","src":"29:1:1"}],"canonicalName":"B","contractDependencies":[],"contractKind":"contract","fullyImplemented":true,"id":4,"linearizedBaseContracts":[4,1],"name":"B","nameLocation":"24:1:1","nodeType":"ContractDefinition","nodes":[],"scope":14,"src":"15:19:1","usedErrors":[]},{"abstract":false,"baseContracts":[{"baseName":{"id":5,"name":"B","nameLocations":["49:1:1"],"nodeType":"IdentifierPath","referencedDeclaration":4,"src":"49:1:1"},"id":6,"nodeType":"InheritanceSpecifier","src":"49:1:1"}],"canonicalName":"C","contractDependencies":[],"contractKind":"contract","fullyImplemented":true,"id":7,"linearizedBaseContracts":[7,4,1],"name":"C","nameLocation":"44:1:1","nodeType":"ContractDefinition","nodes":[],"scope":14,"src":"35:19:1","usedErrors":[]},{"abstract":false,"baseContracts":[{"baseName":{"id":8,"name":"C","nameLocations":["69:1:1"],"nodeType":"IdentifierPath","referencedDeclaration":7,"src":"69:1:1"},"id":9,"nodeType":"InheritanceSpecifier","src":"69:1:1"}],"canonicalName":"D","contractDependencies":[],"contractKind":"contract","fullyImplemented":true,"id":10,"linearizedBaseContracts":[10,7,4,1],"name":"D","nameLocation":"64:1:1","nodeType":"ContractDefinition","nodes":[],"scope":14,"src":"55:19:1","usedErrors":[]},{"abstract":false,"baseContracts":[{"baseName":{"id":11,"name":"D","nameLocations":["89:1:1"],"nodeType":"IdentifierPath","referencedDeclaration":10,"src":"89:1:1"},"id":12,"nodeType":"InheritanceSpecifier","src":"89:1:1"}],"canonicalName":"E","contractDependencies":[],"contractKind":"contract","fullyImplemented":true,"id":13,"linearizedBaseContracts":[13,10,7,4,1],"name":"E","nameLocation":"84:1:1","nodeType":"ContractDefinition","nodes":[],"scope":14,"src":"75:19:1","usedErrors":[]}],"src":"0:95:1"}

```

--------------------------------------------------------------------------------
/tools/xtask/src/flags.rs:
--------------------------------------------------------------------------------

```rust
xflags::xflags! {
    src "./src/flags.rs"

    cmd xtask {
        cmd cut-release {
            /// Cut a patch release
            optional -p, --patch

            /// Cut a minor release
            optional -m, --minor
        }
        cmd blesspr {}
        cmd reportgen {
            /// Run all integration tests
            optional -a, --all

            /// Parallel
            optional --parallel

            /// Sablier
            optional -s, --sablier

            /// Templegold
            optional -t, --tg

            /// AdHoc Sol files
            optional -h, --adhoc

            /// CCIP
            optional -c, --ccip

            /// Contract Playground
            optional -p, --cpg

            /// Foundry NFT
            optional -n, --fnft

            /// Foundry NFT ICM
            optional -i, --fnft-icm

            /// Contract Playrground Uniswap
            optional -u, --cpgu

            /// Hardhat Js Playground
            optional -b, --hhpg

            /// PRB Math
            optional -y, --prb-math

            /// Run in release mode
            optional --release
        }
        cmd tomlgen{}
    }
}

// generated start
// The following code is generated by `xflags` macro.
// Run `env UPDATE_XFLAGS=1 cargo build` to regenerate.
#[derive(Debug)]
pub struct Xtask {
    pub subcommand: XtaskCmd,
}

#[derive(Debug)]
pub enum XtaskCmd {
    CutRelease(CutRelease),
    Blesspr(Blesspr),
    Reportgen(Reportgen),
    Tomlgen(Tomlgen),
}

#[derive(Debug)]
pub struct CutRelease {
    pub patch: bool,
    pub minor: bool,
}

#[derive(Debug)]
pub struct Blesspr;

#[derive(Debug)]
pub struct Reportgen {
    pub all: bool,
    pub parallel: bool,
    pub sablier: bool,
    pub tg: bool,
    pub adhoc: bool,
    pub ccip: bool,
    pub cpg: bool,
    pub fnft: bool,
    pub fnft_icm: bool,
    pub cpgu: bool,
    pub hhpg: bool,
    pub prb_math: bool,
    pub release: bool,
}

#[derive(Debug)]
pub struct Tomlgen;

impl Xtask {
    #[allow(dead_code)]
    pub fn from_env_or_exit() -> Self {
        Self::from_env_or_exit_()
    }

    #[allow(dead_code)]
    pub fn from_env() -> xflags::Result<Self> {
        Self::from_env_()
    }

    #[allow(dead_code)]
    pub fn from_vec(args: Vec<std::ffi::OsString>) -> xflags::Result<Self> {
        Self::from_vec_(args)
    }
}
// generated end

```

--------------------------------------------------------------------------------
/aderyn_core/src/detect/low/ecrecover.rs:
--------------------------------------------------------------------------------

```rust
use std::{collections::BTreeMap, error::Error};

use crate::{
    ast::NodeID,
    capture,
    context::workspace::WorkspaceContext,
    detect::detector::{IssueDetector, IssueDetectorNamePool, IssueSeverity},
};
use eyre::Result;

#[derive(Default)]
pub struct EcrecoverDetector {
    // Keys are: [0] source file name, [1] line number, [2] character location of node.
    // Do not add items manually, use `capture!` to add nodes to this BTreeMap.
    found_instances: BTreeMap<(String, usize, String), NodeID>,
}

impl IssueDetector for EcrecoverDetector {
    fn detect(&mut self, context: &WorkspaceContext) -> Result<bool, Box<dyn Error>> {
        for identifier in context.identifiers() {
            if identifier.name == "ecrecover" {
                capture!(self, context, identifier);
            }
        }
        Ok(!self.found_instances.is_empty())
    }

    fn title(&self) -> String {
        String::from("`ecrecover` Signature Malleability")
    }

    fn description(&self) -> String {
        String::from(
            "The `ecrecover` function is susceptible to signature malleability. \
            This means that the same message can be signed in multiple ways, \
            allowing an attacker to change the message signature without invalidating it. \
            This can lead to unexpected behavior in smart contracts, \
            such as the loss of funds or the ability to bypass access control. \
            Consider using OpenZeppelin's ECDSA library instead of the built-in function.",
        )
    }

    fn severity(&self) -> IssueSeverity {
        IssueSeverity::Low
    }

    fn instances(&self) -> BTreeMap<(String, usize, String), NodeID> {
        self.found_instances.clone()
    }

    fn name(&self) -> String {
        format!("{}", IssueDetectorNamePool::Ecrecover)
    }
}

#[cfg(test)]
mod ecrecover_tests {

    use crate::detect::detector::IssueDetector;

    use super::EcrecoverDetector;

    #[test]

    fn test_ecrecover_detector_by_loading_contract_directly() {
        let context = crate::detect::test_utils::load_solidity_source_unit(
            "../tests/contract-playground/src/inheritance/ExtendedInheritance.sol",
        );

        let mut detector = EcrecoverDetector::default();
        let found = detector.detect(&context).unwrap();
        assert!(found);
        assert_eq!(detector.instances().len(), 1);
    }
}

```

--------------------------------------------------------------------------------
/aderyn/src/panic.rs:
--------------------------------------------------------------------------------

```rust
#![allow(clippy::unwrap_used)]
use std::{io::Write, panic::PanicHookInfo};
use termcolor::{Color, ColorSpec, WriteColor};

use std::io::IsTerminal;

use termcolor::{BufferWriter, ColorChoice};

pub fn stderr_buffer_writer() -> BufferWriter {
    // Prefer to add colors to the output only if it is forced via an environment variable or
    // because it's a terminal

    let color_choice = {
        if std::env::var("FORCE_COLOR").is_ok_and(|e| !e.is_empty()) {
            ColorChoice::Always
        } else if std::io::stderr().is_terminal() {
            ColorChoice::Auto
        } else {
            ColorChoice::Never
        }
    };

    BufferWriter::stderr(color_choice)
}

pub fn add_handler() {
    std::panic::set_hook(Box::new(move |info: &PanicHookInfo<'_>| {
        print_compiler_bug_message(info)
    }));
}

fn print_compiler_bug_message(info: &PanicHookInfo<'_>) {
    let message =
        match (info.payload().downcast_ref::<&str>(), info.payload().downcast_ref::<String>()) {
            (Some(s), _) => (*s).to_string(),
            (_, Some(s)) => s.to_string(),
            (None, None) => "unknown error".into(),
        };

    let location = match info.location() {
        None => "".into(),
        Some(location) => format!("{}:{}\n\t", location.file(), location.line()),
    };

    let buffer_writer = stderr_buffer_writer();
    let mut buffer = buffer_writer.buffer();
    buffer.set_color(ColorSpec::new().set_bold(true).set_fg(Some(Color::Red))).unwrap();
    write!(buffer, "error").unwrap();
    buffer.set_color(ColorSpec::new().set_bold(true)).unwrap();
    write!(buffer, ": Fatal compiler bug!\n\n").unwrap();
    buffer.set_color(&ColorSpec::new()).unwrap();
    writeln!(
        buffer,
        "This is a fatal bug in Aderyn, sorry!

Please report this crash to https://github.com/cyfrin/aderyn/issues/new and include this error message with your report.

Panic: {location}{message}
Aderyn version: {version}
Operating system: {os}

If you can also share your code and say what file you were editing or any
steps to reproduce the crash that would be a great help.

You may also want to try again with the `ADERYN_LOG=trace` environment
variable set.
",
        location = location,
        message = message,
        version = env!("CARGO_PKG_VERSION"),
        os = std::env::consts::OS,
    )
    .unwrap();
    buffer_writer.print(&buffer).unwrap();
}

```

--------------------------------------------------------------------------------
/aderyn_core/src/detect/high/incorrect_shift_order.rs:
--------------------------------------------------------------------------------

```rust
use std::{collections::BTreeMap, error::Error};

use crate::ast::{NodeID, YulExpression};

use crate::{
    capture,
    context::workspace::WorkspaceContext,
    detect::detector::{IssueDetector, IssueDetectorNamePool, IssueSeverity},
};
use eyre::Result;

#[derive(Default)]
pub struct IncorrectShiftOrderDetector {
    // Keys are: [0] source file name, [1] line number, [2] character location of node.
    // Do not add items manually, use `capture!` to add nodes to this BTreeMap.
    found_instances: BTreeMap<(String, usize, String), NodeID>,
}

impl IssueDetector for IncorrectShiftOrderDetector {
    fn detect(&mut self, context: &WorkspaceContext) -> Result<bool, Box<dyn Error>> {
        let yul_function_calls = context.yul_function_calls();
        for yul_function_call in yul_function_calls {
            if (yul_function_call.function_name.name == "shl"
                || yul_function_call.function_name.name == "shr")
                && yul_function_call
                    .arguments
                    .get(1)
                    .is_some_and(|n| matches!(n, YulExpression::YulLiteral(_)))
            {
                capture!(self, context, yul_function_call);
            }
        }

        Ok(!self.found_instances.is_empty())
    }

    fn severity(&self) -> IssueSeverity {
        IssueSeverity::High
    }

    fn title(&self) -> String {
        String::from("Incorrect Assembly Shift Parameter Order")
    }

    fn description(&self) -> String {
        String::from(
            "Example: `shl(shifted, 4)` will shift the right constant `4` by `a` bits. The correct order is `shl(4, shifted)`.",
        )
    }

    fn instances(&self) -> BTreeMap<(String, usize, String), NodeID> {
        self.found_instances.clone()
    }

    fn name(&self) -> String {
        IssueDetectorNamePool::IncorrectShiftOrder.to_string()
    }
}

#[cfg(test)]
mod incorrect_shift_order_detector_tests {

    use crate::detect::{detector::IssueDetector, high::IncorrectShiftOrderDetector};

    #[test]

    fn test_incorrect_shift_order_detector() {
        let context = crate::detect::test_utils::load_solidity_source_unit(
            "../tests/contract-playground/src/IncorrectShift.sol",
        );

        let mut detector = IncorrectShiftOrderDetector::default();
        let found = detector.detect(&context).unwrap();
        assert!(found);
        assert_eq!(detector.instances().len(), 2);
    }
}

```

--------------------------------------------------------------------------------
/tests/ast/documentation_3.json:
--------------------------------------------------------------------------------

```json
{"absolutePath":"c","exportedSymbols":{"C":[23]},"id":24,"nodeType":"SourceUnit","nodes":[{"abstract":false,"baseContracts":[],"canonicalName":"C","contractDependencies":[],"contractKind":"contract","fullyImplemented":true,"id":23,"linearizedBaseContracts":[23],"name":"C","nameLocation":"9:1:3","nodeType":"ContractDefinition","nodes":[{"constant":false,"documentation":{"id":7,"nodeType":"StructuredDocumentation","src":"15:32:3","text":"Some comment on state var."},"functionSelector":"c19d93fb","id":9,"mutability":"mutable","name":"state","nameLocation":"60:5:3","nodeType":"VariableDeclaration","scope":23,"src":"48:17:3","stateVariable":true,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"},"typeName":{"id":8,"name":"uint","nodeType":"ElementaryTypeName","src":"48:4:3","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"visibility":"public"},{"anonymous":false,"documentation":{"id":10,"nodeType":"StructuredDocumentation","src":"69:26:3","text":"Some comment on Evt."},"eventSelector":"a69007916fc1145953e5a7032d7c3eab4b8e2f33ec59b0f71e732904eeede3a4","id":12,"name":"Evt","nameLocation":"102:3:3","nodeType":"EventDefinition","parameters":{"id":11,"nodeType":"ParameterList","parameters":[],"src":"105:2:3"},"src":"96:12:3"},{"body":{"id":16,"nodeType":"Block","src":"153:6:3","statements":[{"id":15,"nodeType":"PlaceholderStatement","src":"155:1:3"}]},"documentation":{"id":13,"nodeType":"StructuredDocumentation","src":"111:26:3","text":"Some comment on mod."},"id":17,"name":"mod","nameLocation":"147:3:3","nodeType":"ModifierDefinition","parameters":{"id":14,"nodeType":"ParameterList","parameters":[],"src":"150:2:3"},"src":"138:21:3","virtual":false,"visibility":"internal"},{"body":{"id":21,"nodeType":"Block","src":"209:2:3","statements":[]},"documentation":{"id":18,"nodeType":"StructuredDocumentation","src":"162:25:3","text":"Some comment on fn."},"functionSelector":"a4a2c40b","id":22,"implemented":true,"kind":"function","modifiers":[],"name":"fn","nameLocation":"197:2:3","nodeType":"FunctionDefinition","parameters":{"id":19,"nodeType":"ParameterList","parameters":[],"src":"199:2:3"},"returnParameters":{"id":20,"nodeType":"ParameterList","parameters":[],"src":"209:0:3"},"scope":23,"src":"188:23:3","stateMutability":"nonpayable","virtual":false,"visibility":"public"}],"scope":24,"src":"0:213:3","usedErrors":[]}],"src":"0:214:3"}

```

--------------------------------------------------------------------------------
/aderyn_core/src/context/graph/callgraph.rs:
--------------------------------------------------------------------------------

```rust
//! This module helps with strategies on performing different types of investigations.
//!
//! Our first kind of callgraph is [`CallGraph`] it comes bundled with actions to help
//! application modules "hook in" and consume the graphs.

mod legacy;
mod new;
mod tests;
mod utils;
mod visit;

use super::{Error, Result, traits::CallGraphVisitor};
use crate::{
    ast::NodeID,
    context::workspace::{ASTNode, WorkspaceContext},
};

#[derive(Clone, PartialEq)]
pub enum CallGraphDirection {
    /// Deeper into the callgraph
    Inward,

    /// Opposite of Inward
    Outward,

    /// Both inward and outward (If outward side effects also need to be tracked)
    BothWays,
}

pub struct CallGraphConsumer {
    /// Ad-hoc Nodes that we would like to explore inward from.
    pub entry_points: Vec<NodeID>,

    /// Surface points are calculated based on the entry points (input)
    /// and only consists of [`crate::ast::FunctionDefinition`] and
    /// [`crate::ast::ModifierDefinition`] These are nodes that are the *actual* starting
    /// points for traversal in the graph
    pub inward_surface_points: Vec<NodeID>,

    /// Same as the inward one, but acts on reverse graph.
    pub outward_surface_points: Vec<NodeID>,

    /// Decides what graph type to chose.
    pub direction: CallGraphDirection,

    /// Decides what graph to chose from [`WorkspaceContext::callgraphs`].
    pub base_contract: Option<NodeID>,
}

#[derive(PartialEq, Clone, Copy)]
enum CurrentDFSVector {
    Inward,
    Outward,
    OutwardSideEffect,
}

impl CallGraphConsumer {
    pub fn get_legacy(
        context: &WorkspaceContext,
        nodes: &[&ASTNode],
        direction: CallGraphDirection,
    ) -> super::Result<CallGraphConsumer> {
        Self::from_nodes(context, nodes, direction)
    }

    pub fn get(
        context: &WorkspaceContext,
        nodes: &[&ASTNode],
        direction: CallGraphDirection,
    ) -> super::Result<Vec<CallGraphConsumer>> {
        Self::many_from_nodes(context, nodes, direction)
    }

    /// Visit the entry points and all the plausible function definitions and modifier definitions
    /// that EVM may encounter during execution.
    pub fn accept<T>(&self, context: &WorkspaceContext, visitor: &mut T) -> super::Result<()>
    where
        T: CallGraphVisitor,
    {
        self._accept(context, visitor)
    }

    #[inline]
    pub fn is_legacy(&self) -> bool {
        self.base_contract.is_none()
    }
}

```

--------------------------------------------------------------------------------
/aderyn_core/src/detect/high/_template.rs:
--------------------------------------------------------------------------------

```rust
use std::{collections::BTreeMap, error::Error};

use crate::ast::NodeID;

use crate::{
    capture,
    context::workspace_context::WorkspaceContext,
    detect::detector::{IssueDetector, IssueDetectorNamePool, IssueSeverity},
};
use eyre::Result;

// HOW TO USE THIS TEMPLATE:
// 1. Copy this file and rename it to the snake_case version of the issue you are detecting.
// 2. Rename the TemplateDetector struct and impl to your new issue name.
// 3. Add this file and detector struct to the mod.rs file in the same directory.
// 4. Implement the detect function to find instances of the issue.

#[derive(Default)]
pub struct TemplateDetector {
    // Keys are: [0] source file name, [1] line number, [2] character location of node.
    // Do not add items manually, use `capture!` to add nodes to this BTreeMap.
    found_instances: BTreeMap<(String, usize, String), NodeID>,
    hints: BTreeMap<(String, usize, String), String>,
}

impl IssueDetector for TemplateDetector {
    fn detect(&mut self, context: &WorkspaceContext) -> Result<bool, Box<dyn Error>> {
        // When you have found an instance of the issue,
        // use the following macro to add it to `found_instances`:
        //
        // capture!(self, context, item);
        // capture!(self, context, item, "hint");

        Ok(!self.found_instances.is_empty())
    }

    fn severity(&self) -> IssueSeverity {
        IssueSeverity::High
    }

    fn title(&self) -> String {
        String::from("High Issue Title")
    }

    fn description(&self) -> String {
        String::from("Description of the high issue.")
    }

    fn instances(&self) -> BTreeMap<(String, usize, String), NodeID> {
        self.found_instances.clone()
    }

    fn hints(&self) -> BTreeMap<(String, usize, String), String> {
        self.hints.clone()
    }

    fn name(&self) -> String {
        format!("high-issue-template")
    }
}

#[cfg(test)]
mod template_detector_tests {
    use serial_test::serial;

    use crate::detect::{detector::IssueDetector, high::template_detector::TemplateDetector};

    #[test]
    fn test_template_detector() {
        let context = crate::detect::test_utils::load_solidity_source_unit(
            "../tests/contract-playground/src/ArbitraryTransferFrom.sol",
        );

        let mut detector = TemplateDetector::default();
        let found = detector.detect(&context).unwrap();
        assert!(found);
        assert_eq!(detector.instances().len(), 1);
    }
}

```

--------------------------------------------------------------------------------
/aderyn_core/src/ast/impls/node/modifiers.rs:
--------------------------------------------------------------------------------

```rust
use crate::{ast::*, visitor::ast_visitor::*};
use eyre::Result;

impl Node for ModifierDefinition {
    fn accept(&self, visitor: &mut impl ASTConstVisitor) -> Result<()> {
        if visitor.visit_modifier_definition(self)? {
            // TODO: should we implement a string based visitor?
            // self.name.accept(visitor)?;
            if let Some(body) = &self.body {
                body.accept(visitor)?;
            }
            if let Some(override_specifier) = &self.overrides {
                override_specifier.accept(visitor)?;
            }
            self.parameters.accept(visitor)?;
        }
        self.accept_metadata(visitor)?;
        visitor.end_visit_modifier_definition(self)
    }
    fn accept_metadata(&self, visitor: &mut impl ASTConstVisitor) -> Result<()> {
        if let Some(body) = &self.body {
            visitor.visit_immediate_children(self.id, vec![body.id])?;
        }
        if let Some(override_specifier) = &self.overrides {
            visitor.visit_immediate_children(self.id, vec![override_specifier.id])?;
        }
        visitor.visit_immediate_children(self.id, vec![self.parameters.id])?;
        Ok(())
    }
    macros::accept_id!();
}

impl Node for ModifierInvocation {
    fn accept(&self, visitor: &mut impl ASTConstVisitor) -> Result<()> {
        if visitor.visit_modifier_invocation(self)? {
            match &self.modifier_name {
                IdentifierOrIdentifierPath::Identifier(identifier) => identifier.accept(visitor)?,
                IdentifierOrIdentifierPath::IdentifierPath(identifier_path) => {
                    identifier_path.accept(visitor)?
                }
            };
            if self.arguments.is_some() {
                list_accept(self.arguments.as_ref().unwrap(), visitor)?;
            }
        }
        self.accept_metadata(visitor)?;
        visitor.end_visit_modifier_invocation(self)
    }
    fn accept_metadata(&self, visitor: &mut impl ASTConstVisitor) -> Result<()> {
        visitor.visit_immediate_children(self.id, vec![self.modifier_name.get_node_id()])?;
        if let Some(arguments) = &self.arguments {
            let mut argument_ids = vec![];
            for arg in arguments {
                if let Some(arg_id) = arg.get_node_id() {
                    argument_ids.push(arg_id);
                }
            }
            visitor.visit_immediate_children(self.id, argument_ids)?;
        }
        Ok(())
    }
    macros::accept_id!();
}

```

--------------------------------------------------------------------------------
/tests/ast/long_type_name_identifier.json:
--------------------------------------------------------------------------------

```json
{"absolutePath":"a","exportedSymbols":{"c":[15]},"id":16,"nodeType":"SourceUnit","nodes":[{"abstract":false,"baseContracts":[],"canonicalName":"c","contractDependencies":[],"contractKind":"contract","fullyImplemented":true,"id":15,"linearizedBaseContracts":[15],"name":"c","nameLocation":"9:1:1","nodeType":"ContractDefinition","nodes":[{"constant":false,"id":3,"mutability":"mutable","name":"a","nameLocation":"20:1:1","nodeType":"VariableDeclaration","scope":15,"src":"13:8:1","stateVariable":true,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_array$_t_uint256_$dyn_storage","typeString":"uint256[]"},"typeName":{"baseType":{"id":1,"name":"uint","nodeType":"ElementaryTypeName","src":"13:4:1","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"id":2,"nodeType":"ArrayTypeName","src":"13:6:1","typeDescriptions":{"typeIdentifier":"t_array$_t_uint256_$dyn_storage_ptr","typeString":"uint256[]"}},"visibility":"internal"},{"body":{"id":13,"nodeType":"Block","src":"43:25:1","statements":[{"assignments":[10],"declarations":[{"constant":false,"id":10,"mutability":"mutable","name":"b","nameLocation":"60:1:1","nodeType":"VariableDeclaration","scope":13,"src":"45:16:1","stateVariable":false,"storageLocation":"storage","typeDescriptions":{"typeIdentifier":"t_array$_t_uint256_$dyn_storage_ptr","typeString":"uint256[]"},"typeName":{"baseType":{"id":8,"name":"uint","nodeType":"ElementaryTypeName","src":"45:4:1","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"id":9,"nodeType":"ArrayTypeName","src":"45:6:1","typeDescriptions":{"typeIdentifier":"t_array$_t_uint256_$dyn_storage_ptr","typeString":"uint256[]"}},"visibility":"internal"}],"id":12,"initialValue":{"id":11,"name":"a","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":3,"src":"64:1:1","typeDescriptions":{"typeIdentifier":"t_array$_t_uint256_$dyn_storage","typeString":"uint256[] storage ref"}},"nodeType":"VariableDeclarationStatement","src":"45:20:1"}]},"functionSelector":"26121ff0","id":14,"implemented":true,"kind":"function","modifiers":[],"name":"f","nameLocation":"32:1:1","nodeType":"FunctionDefinition","parameters":{"id":4,"nodeType":"ParameterList","parameters":[],"src":"33:2:1"},"returnParameters":{"id":5,"nodeType":"ParameterList","parameters":[],"src":"43:0:1"},"scope":15,"src":"23:45:1","stateMutability":"nonpayable","virtual":false,"visibility":"public"}],"scope":16,"src":"0:70:1","usedErrors":[]}],"src":"0:71:1"}

```

--------------------------------------------------------------------------------
/aderyn_core/src/detect/low/_template.rs:
--------------------------------------------------------------------------------

```rust
use std::collections::BTreeMap;
use std::error::Error;

use crate::ast::NodeID;

use crate::capture;
use crate::detect::detector::IssueDetectorNamePool;
use crate::{
    context::workspace_context::WorkspaceContext,
    detect::detector::{IssueDetector, IssueSeverity},
};
use eyre::Result;

// HOW TO USE THIS TEMPLATE:
// 1. Copy this file and rename it to the snake_case version of the issue you are detecting.
// 2. Rename the TemplateDetector struct and impl to your new issue name.
// 3. Add this file and detector struct to the mod.rs file in the same directory.
// 4. Implement the detect function to find instances of the issue.

#[derive(Default)]
pub struct TemplateDetector {
    // Keys are: [0] source file name, [1] line number, [2] character location of node.
    // Do not add items manually, use `capture!` to add nodes to this BTreeMap.
    found_instances: BTreeMap<(String, usize, String), NodeID>,
    hints: BTreeMap<(String, usize, String), String>,
}

impl IssueDetector for TemplateDetector {
    fn detect(&mut self, context: &WorkspaceContext) -> Result<bool, Box<dyn Error>> {
        // When you have found an instance of the issue,
        // use the following macro to add it to `found_instances`:
        //
        // capture!(self, context, item);
        // capture!(self, context, item, "hint");

        Ok(!self.found_instances.is_empty())
    }

    fn severity(&self) -> IssueSeverity {
        IssueSeverity::Low
    }

    fn title(&self) -> String {
        String::from("Low Issue Title")
    }

    fn description(&self) -> String {
        String::from("Description of the low issue.")
    }

    fn instances(&self) -> BTreeMap<(String, usize, String), NodeID> {
        self.found_instances.clone()
    }

    fn hints(&self) -> BTreeMap<(String, usize, String), String> {
        self.hints.clone()
    }

    fn name(&self) -> String {
        format!("low-issue-template")
    }
}

#[cfg(test)]
mod template_detector_tests {
    use serial_test::serial;

    use crate::detect::{detector::IssueDetector, low::template_detector::TemplateDetector};

    #[test]
    fn test_template_detector() {
        let context = crate::detect::test_utils::load_solidity_source_unit(
            "../tests/contract-playground/src/ArbitraryTransferFrom.sol",
        );

        let mut detector = TemplateDetector::default();
        let found = detector.detect(&context).unwrap();
        assert!(found);
        assert_eq!(detector.instances().len(), 1);
    }
}

```

--------------------------------------------------------------------------------
/aderyn_core/src/detect/low/unsafe_erc20_operation.rs:
--------------------------------------------------------------------------------

```rust
use std::{collections::BTreeMap, error::Error};

use crate::{
    ast::NodeID,
    capture,
    context::workspace::WorkspaceContext,
    detect::detector::{IssueDetector, IssueDetectorNamePool, IssueSeverity},
};
use eyre::Result;

#[derive(Default)]
pub struct UnsafeERC20OperationDetector {
    // Keys are: [0] source file name, [1] line number, [2] character location of node.
    // Do not add items manually, use `capture!` to add nodes to this BTreeMap.
    found_instances: BTreeMap<(String, usize, String), NodeID>,
}

impl IssueDetector for UnsafeERC20OperationDetector {
    fn detect(&mut self, context: &WorkspaceContext) -> Result<bool, Box<dyn Error>> {
        for member_access in context.member_accesses() {
            if member_access.expression.as_ref().type_descriptions().is_some_and(|desc| {
                desc.type_string.as_ref().is_some_and(|type_string| type_string.contains("ERC20"))
            }) && member_access.member_name == "transferFrom"
                || member_access.member_name == "approve"
                || member_access.member_name == "transfer"
            {
                capture!(self, context, member_access);
            }
        }
        Ok(!self.found_instances.is_empty())
    }

    fn title(&self) -> String {
        String::from("Unsafe ERC20 Operation")
    }

    fn description(&self) -> String {
        String::from(
            "ERC20 functions may not behave as expected. For example: return values are not always meaningful. It is recommended to use OpenZeppelin's SafeERC20 library.",
        )
    }

    fn severity(&self) -> IssueSeverity {
        IssueSeverity::Low
    }

    fn instances(&self) -> BTreeMap<(String, usize, String), NodeID> {
        self.found_instances.clone()
    }

    fn name(&self) -> String {
        format!("{}", IssueDetectorNamePool::UnsafeERC20Operation)
    }
}

#[cfg(test)]
mod unsafe_erc20_functions_tests {
    use crate::detect::detector::IssueDetector;

    use super::UnsafeERC20OperationDetector;

    #[test]

    fn test_unsafe_erc20_functions_by_loading_contract_directly() {
        let context = crate::detect::test_utils::load_solidity_source_unit(
            "../tests/contract-playground/src/DeprecatedOZFunctions.sol",
        );

        let mut detector = UnsafeERC20OperationDetector::default();
        let found = detector.detect(&context).unwrap();
        assert!(found);
        // failure0, failure1 and failure3
        assert_eq!(detector.instances().len(), 5);
    }
}

```

--------------------------------------------------------------------------------
/aderyn_core/src/detect/low/internal_function_used_once.rs:
--------------------------------------------------------------------------------

```rust
use std::{collections::BTreeMap, error::Error};

use crate::{
    ast::{NodeID, Visibility},
    capture,
    context::workspace::WorkspaceContext,
    detect::{
        detector::{IssueDetector, IssueDetectorNamePool, IssueSeverity},
        helpers::count_identifiers_that_reference_an_id,
    },
};
use eyre::Result;

#[derive(Default)]
pub struct InternalFunctionUsedOnceDetector {
    // Keys are: [0] source file name, [1] line number, [2] character location of node.
    // Do not add items manually, use `capture!` to add nodes to this BTreeMap.
    found_instances: BTreeMap<(String, usize, String), NodeID>,
}

impl IssueDetector for InternalFunctionUsedOnceDetector {
    fn detect(&mut self, context: &WorkspaceContext) -> Result<bool, Box<dyn Error>> {
        let internal_functions = context.function_definitions().into_iter().filter(|&function| {
            matches!(function.visibility, Visibility::Internal) && !function.name.starts_with('_')
        });

        for internal_function in internal_functions {
            if count_identifiers_that_reference_an_id(context, internal_function.id) == 1 {
                capture!(self, context, internal_function);
            }
        }

        Ok(!self.found_instances.is_empty())
    }

    fn title(&self) -> String {
        String::from("Internal Function Used Only Once")
    }

    fn description(&self) -> String {
        String::from(
            "Instead of separating the logic into a separate function, consider inlining the logic into the calling function. This can reduce the number of function calls and improve readability.",
        )
    }

    fn severity(&self) -> IssueSeverity {
        IssueSeverity::Low
    }

    fn instances(&self) -> BTreeMap<(String, usize, String), NodeID> {
        self.found_instances.clone()
    }

    fn name(&self) -> String {
        format!("{}", IssueDetectorNamePool::InternalFunctionUsedOnce)
    }
}

#[cfg(test)]
mod uselss_internal_function {
    use crate::detect::detector::IssueDetector;

    use super::InternalFunctionUsedOnceDetector;

    #[test]

    fn test_useless_internal_functions_by_loading_contract_directly() {
        let context = crate::detect::test_utils::load_solidity_source_unit(
            "../tests/contract-playground/src/InternalFunctions.sol",
        );

        let mut detector = InternalFunctionUsedOnceDetector::default();
        let found = detector.detect(&context).unwrap();
        assert!(found);
        assert_eq!(detector.instances().len(), 1);
    }
}

```

--------------------------------------------------------------------------------
/aderyn_core/src/detect/low/non_reentrant_not_first.rs:
--------------------------------------------------------------------------------

```rust
use std::{collections::BTreeMap, error::Error};

use crate::{
    ast::NodeID,
    capture,
    context::workspace::WorkspaceContext,
    detect::detector::{IssueDetector, IssueDetectorNamePool, IssueSeverity},
};
use eyre::Result;

#[derive(Default)]
pub struct NonReentrantBeforeOthersDetector {
    // Keys are source file name, line number and source location
    found_instances: BTreeMap<(String, usize, String), NodeID>,
}

impl IssueDetector for NonReentrantBeforeOthersDetector {
    fn detect(&mut self, context: &WorkspaceContext) -> Result<bool, Box<dyn Error>> {
        let function_definitions = context.function_definitions();
        for definition in function_definitions {
            if definition.modifiers.len() > 1 {
                for (index, modifier) in definition.modifiers.iter().enumerate() {
                    if modifier.modifier_name.name().to_lowercase().contains("nonreentrant")
                        && index != 0
                    {
                        capture!(self, context, modifier);
                    }
                }
            }
        }
        Ok(!self.found_instances.is_empty())
    }

    fn title(&self) -> String {
        String::from("`nonReentrant` is Not the First Modifier")
    }

    fn description(&self) -> String {
        String::from(
            "To protect against reentrancy in other modifiers, the `nonReentrant` modifier should be the first modifier in the list of modifiers.",
        )
    }

    fn severity(&self) -> IssueSeverity {
        IssueSeverity::Low
    }

    fn instances(&self) -> BTreeMap<(String, usize, String), NodeID> {
        self.found_instances.clone()
    }

    fn name(&self) -> String {
        format!("{}", IssueDetectorNamePool::NonReentrantNotFirst)
    }
}

#[cfg(test)]
mod non_reentrant_before_others_tests {

    use crate::detect::{detector::IssueDetector, low::NonReentrantBeforeOthersDetector};

    #[test]

    fn test_non_reentrant_before_others_by_loading_contract_directly() {
        let context = crate::detect::test_utils::load_solidity_source_unit(
            "../tests/contract-playground/src/AdminContract.sol",
        );

        let mut detector = NonReentrantBeforeOthersDetector::default();
        let found = detector.detect(&context).unwrap();
        assert!(found);
        assert_eq!(detector.instances().len(), 1);

        // assert that the line number is 10
        let (_, line_number, _) = detector.instances().keys().next().unwrap().clone();
        assert_eq!(line_number, 10);
    }
}

```

--------------------------------------------------------------------------------
/tests/ast/mutability.json:
--------------------------------------------------------------------------------

```json
{"absolutePath":"a","exportedSymbols":{"C":[10]},"id":11,"nodeType":"SourceUnit","nodes":[{"abstract":false,"baseContracts":[],"canonicalName":"C","contractDependencies":[],"contractKind":"contract","fullyImplemented":true,"id":10,"linearizedBaseContracts":[10],"name":"C","nameLocation":"9:1:1","nodeType":"ContractDefinition","nodes":[{"constant":false,"functionSelector":"0dbe671f","id":3,"mutability":"immutable","name":"a","nameLocation":"39:1:1","nodeType":"VariableDeclaration","scope":10,"src":"17:27:1","stateVariable":true,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"},"typeName":{"id":1,"name":"uint","nodeType":"ElementaryTypeName","src":"17:4:1","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"value":{"hexValue":"34","id":2,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"43:1:1","typeDescriptions":{"typeIdentifier":"t_rational_4_by_1","typeString":"int_const 4"},"value":"4"},"visibility":"public"},{"constant":true,"functionSelector":"4df7e3d0","id":6,"mutability":"constant","name":"b","nameLocation":"71:1:1","nodeType":"VariableDeclaration","scope":10,"src":"50:26:1","stateVariable":true,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"},"typeName":{"id":4,"name":"uint","nodeType":"ElementaryTypeName","src":"50:4:1","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"value":{"hexValue":"32","id":5,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"75:1:1","typeDescriptions":{"typeIdentifier":"t_rational_2_by_1","typeString":"int_const 2"},"value":"2"},"visibility":"public"},{"constant":false,"functionSelector":"c3da42b8","id":9,"mutability":"mutable","name":"c","nameLocation":"94:1:1","nodeType":"VariableDeclaration","scope":10,"src":"82:17:1","stateVariable":true,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"},"typeName":{"id":7,"name":"uint","nodeType":"ElementaryTypeName","src":"82:4:1","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"value":{"hexValue":"33","id":8,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"98:1:1","typeDescriptions":{"typeIdentifier":"t_rational_3_by_1","typeString":"int_const 3"},"value":"3"},"visibility":"public"}],"scope":11,"src":"0:102:1","usedErrors":[]}],"src":"0:103:1"}

```

--------------------------------------------------------------------------------
/aderyn_core/src/ast/impls/node/types.rs:
--------------------------------------------------------------------------------

```rust
use crate::{ast::*, visitor::ast_visitor::*};
use eyre::Result;
use macros::accept_id;

impl Node for TypeName {
    fn accept(&self, visitor: &mut impl ASTConstVisitor) -> Result<()> {
        match self {
            TypeName::FunctionTypeName(function_type_name) => function_type_name.accept(visitor),
            TypeName::ArrayTypeName(array_type_name) => array_type_name.accept(visitor),
            TypeName::Mapping(mapping) => mapping.accept(visitor),
            TypeName::UserDefinedTypeName(user_defined_type_name) => {
                user_defined_type_name.accept(visitor)
            }
            TypeName::ElementaryTypeName(elementary_type_name) => {
                elementary_type_name.accept(visitor)
            }
            TypeName::Raw(_) => Ok(()),
        }
    }
    fn accept_id(&self, visitor: &mut impl ASTConstVisitor) -> Result<()> {
        visitor.visit_node_id(self.get_node_id())?;
        Ok(())
    }
}

impl Node for ElementaryTypeName {
    fn accept(&self, visitor: &mut impl ASTConstVisitor) -> Result<()> {
        visitor.visit_elementary_type_name(self)?;
        visitor.end_visit_elementary_type_name(self)
    }
    accept_id!();
}

impl Node for UserDefinedTypeName {
    fn accept(&self, visitor: &mut impl ASTConstVisitor) -> Result<()> {
        if visitor.visit_user_defined_type_name(self)? && self.path_node.is_some() {
            self.path_node.as_ref().unwrap().accept(visitor)?;
        }
        visitor.end_visit_user_defined_type_name(self)
    }
    accept_id!();
}

impl Node for FunctionTypeName {
    fn accept(&self, visitor: &mut impl ASTConstVisitor) -> Result<()> {
        if visitor.visit_function_type_name(self)? {
            self.parameter_types.accept(visitor)?;
            self.return_parameter_types.accept(visitor)?;
        }
        visitor.end_visit_function_type_name(self)
    }
    accept_id!();
}

impl Node for ArrayTypeName {
    fn accept(&self, visitor: &mut impl ASTConstVisitor) -> Result<()> {
        if visitor.visit_array_type_name(self)? {
            self.base_type.accept(visitor)?;
            if let Some(length) = self.length.as_ref() {
                length.accept(visitor)?;
            }
        }
        visitor.end_visit_array_type_name(self)
    }
    accept_id!();
}

impl Node for Mapping {
    fn accept(&self, visitor: &mut impl ASTConstVisitor) -> Result<()> {
        if visitor.visit_mapping(self)? {
            self.key_type.accept(visitor)?;
            self.value_type.accept(visitor)?;
        }
        visitor.end_visit_mapping(self)
    }
    accept_id!();
}

```

--------------------------------------------------------------------------------
/aderyn_core/src/context/flow/kind.rs:
--------------------------------------------------------------------------------

```rust
//! Following are the types of statements that are to be considered when building a
//! Control Flow graph
//!
//! REDUCIBLES
//!
//! Step-in
//! -------
//! Block
//! UncheckedBlock
//!
//! Flow
//! ----
//! DoWhileStatement
//! IfStatement
//! ForStatement
//! WhileStatement
//!
//! ----------------------------
//!
//! PRIMITIVES
//!
//! Substitute
//! ----------
//! PlaceholderStatement
//!
//! Jumper
//! ------
//! Break
//! Continue
//! Return
//!
//! Regular
//! ------
//! EmitStatement
//! RevertStatement
//! ExpressionStatement
//! InlineAssembly
//! VariableDeclarationStatement
//! TryStatement

use super::CfgNodeDescriptor;

#[derive(PartialEq, Clone, Copy)]
pub enum CfgNodeKind {
    Void,
    Reducible,
    Primitive,
}

impl CfgNodeDescriptor {
    pub fn kind(&self) -> CfgNodeKind {
        match self {
            // Void nodes
            CfgNodeDescriptor::Start(_) => CfgNodeKind::Void,
            CfgNodeDescriptor::End(_) => CfgNodeKind::Void,

            // Primitives
            CfgNodeDescriptor::VariableDeclarationStatement(_) => CfgNodeKind::Primitive,
            CfgNodeDescriptor::ExpressionStatement(_) => CfgNodeKind::Primitive,
            CfgNodeDescriptor::PlaceholderStatement(_) => CfgNodeKind::Primitive,
            CfgNodeDescriptor::Break(_) => CfgNodeKind::Primitive,
            CfgNodeDescriptor::Continue(_) => CfgNodeKind::Primitive,
            CfgNodeDescriptor::Return(_) => CfgNodeKind::Primitive,
            CfgNodeDescriptor::EmitStatement(_) => CfgNodeKind::Primitive,
            CfgNodeDescriptor::RevertStatement(_) => CfgNodeKind::Primitive,
            CfgNodeDescriptor::InlineAssembly(_) => CfgNodeKind::Primitive,
            CfgNodeDescriptor::TryStatement(_) => CfgNodeKind::Primitive,
            CfgNodeDescriptor::IfStatementCondition(_) => CfgNodeKind::Primitive,
            CfgNodeDescriptor::WhileStatementCondition(_) => CfgNodeKind::Primitive,
            CfgNodeDescriptor::ForStatementCondition(_) => CfgNodeKind::Primitive,
            CfgNodeDescriptor::DoWhileStatementCondition(_) => CfgNodeKind::Primitive,

            // Reducibles
            CfgNodeDescriptor::Block(_) => CfgNodeKind::Reducible,
            CfgNodeDescriptor::UncheckedBlock(_) => CfgNodeKind::Reducible,
            CfgNodeDescriptor::IfStatement(_) => CfgNodeKind::Reducible,
            CfgNodeDescriptor::WhileStatement(_) => CfgNodeKind::Reducible,
            CfgNodeDescriptor::ForStatement(_) => CfgNodeKind::Reducible,
            CfgNodeDescriptor::DoWhileStatement(_) => CfgNodeKind::Reducible,
        }
    }
}

```

--------------------------------------------------------------------------------
/aderyn_core/src/detect/low/large_numeric_literal.rs:
--------------------------------------------------------------------------------

```rust
use std::{collections::BTreeMap, error::Error};

use crate::{
    ast::{LiteralKind, NodeID},
    capture,
    context::workspace::WorkspaceContext,
    detect::detector::{IssueDetector, IssueDetectorNamePool, IssueSeverity},
};
use eyre::Result;

#[derive(Default)]
pub struct LargeLiteralValueDetector {
    // Keys are: [0] source file name, [1] line number, [2] character location of node.
    // Do not add items manually, use `capture!` to add nodes to this BTreeMap.
    found_instances: BTreeMap<(String, usize, String), NodeID>,
}

impl IssueDetector for LargeLiteralValueDetector {
    fn detect(&mut self, context: &WorkspaceContext) -> Result<bool, Box<dyn Error>> {
        for numeric_literal in context.literals().iter().filter(|x| x.kind == LiteralKind::Number) {
            if let Some(value) = numeric_literal.value.clone() {
                // Strip any underscore separators
                let value_no_underscores = value.replace('_', "");
                let is_huge = value_no_underscores.ends_with("0000");
                let is_hex = value_no_underscores.starts_with("0x");
                let is_exp = value_no_underscores.contains('e');
                if is_huge && !is_hex && !is_exp {
                    capture!(self, context, numeric_literal);
                }
            }
        }

        Ok(!self.found_instances.is_empty())
    }

    fn title(&self) -> String {
        String::from("Large Numeric Literal")
    }

    fn description(&self) -> String {
        String::from(
            "Large literal values multiples of 10000 can be replaced with scientific notation.Use `e` notation, for example: `1e18`, instead of its full numeric value.",
        )
    }

    fn severity(&self) -> IssueSeverity {
        IssueSeverity::Low
    }

    fn instances(&self) -> BTreeMap<(String, usize, String), NodeID> {
        self.found_instances.clone()
    }

    fn name(&self) -> String {
        format!("{}", IssueDetectorNamePool::LargeNumericLiteral)
    }
}

#[cfg(test)]
mod large_literal_values {

    use crate::detect::detector::IssueDetector;

    use super::LargeLiteralValueDetector;

    #[test]

    fn test_large_literal_values_multiples_of_10000_by_loading_contract_directly() {
        let context = crate::detect::test_utils::load_solidity_source_unit(
            "../tests/contract-playground/src/HugeConstants.sol",
        );

        let mut detector = LargeLiteralValueDetector::default();
        let found = detector.detect(&context).unwrap();
        assert!(found);
        assert_eq!(detector.instances().len(), 22);
    }
}

```

--------------------------------------------------------------------------------
/aderyn_core/src/detect/low/unused_error.rs:
--------------------------------------------------------------------------------

```rust
use crate::{
    ast::NodeID,
    capture,
    context::workspace::WorkspaceContext,
    detect::detector::{IssueDetector, IssueDetectorNamePool, IssueSeverity},
};
use eyre::Result;
use std::{
    collections::{BTreeMap, HashSet},
    error::Error,
};

#[derive(Default)]
pub struct UnusedErrorDetector {
    // Keys are source file name and line number
    found_instances: BTreeMap<(String, usize, String), NodeID>,
}

impl IssueDetector for UnusedErrorDetector {
    fn detect(&mut self, context: &WorkspaceContext) -> Result<bool, Box<dyn Error>> {
        let error_definitions = context.error_definitions().into_iter().collect::<Vec<_>>();
        let mut referenced_ids = HashSet::new();

        //Get all MemberAccess and Identifier nodes where the referenced_declaration is an ID of an
        // error definition
        for identifier in context.identifiers() {
            if let Some(reference_id) = identifier.referenced_declaration {
                referenced_ids.insert(reference_id);
            }
        }
        for member_access in context.member_accesses() {
            if let Some(reference_id) = member_access.referenced_declaration {
                referenced_ids.insert(reference_id);
            }
        }

        // Identify unused errors by comparing defined and used error IDs
        for error_def in error_definitions {
            if !referenced_ids.contains(&error_def.id) {
                // Capture unused error instances
                capture!(self, context, error_def);
            }
        }
        Ok(!self.found_instances.is_empty())
    }

    fn title(&self) -> String {
        String::from("Unused Error")
    }

    fn description(&self) -> String {
        String::from("Consider using or removing the unused error.")
    }

    fn severity(&self) -> IssueSeverity {
        IssueSeverity::Low
    }

    fn instances(&self) -> BTreeMap<(String, usize, String), NodeID> {
        self.found_instances.clone()
    }

    fn name(&self) -> String {
        format!("{}", IssueDetectorNamePool::UnusedError)
    }
}

#[cfg(test)]
mod unused_error_tests {

    use crate::detect::detector::IssueDetector;

    use super::UnusedErrorDetector;

    #[test]

    fn test_unused_error_detection() {
        let context = crate::detect::test_utils::load_solidity_source_unit(
            "../tests/contract-playground/src/UnusedError.sol",
        );

        let mut detector = UnusedErrorDetector::default();
        let found = detector.detect(&context).unwrap();
        assert!(found);
        assert_eq!(detector.instances().len(), 2);
    }
}

```

--------------------------------------------------------------------------------
/aderyn/templates/aderyn.toml:
--------------------------------------------------------------------------------

```toml
# Aderyn Configuration File
# Help Aderyn work with more granular control

# DO NOT CHANGE version below. As of now, only 1 is supported
version = 1

# Read the description carefully and uncomment the examples in each paragraph should you consider using them.

# Base path for resolving remappings and compiling smart contracts, relative to workspace-root (directory in which the editor is open)
# Most of the time, you want to point it to the directory containing foundry.toml or hardhat.config.js/ts.
root = {}

# Path of source directory containing the contracts, relative to root (above)
# Aderyn will traverse all the nested files inside to scan and report vulnerabilities found inside.
# - If not specified, Aderyn will try to extract it from the framework that is being used. (Foundry / Hardhat). 
#   That would be "contracts/" in case of Hardhat and in case of Foundry, it depends on foundry.toml and
#   many other factors like FOUNDRY_PROFILE environment variable, etc.
# - If specified, Aderyn will override the above found `src`.
# Example:
# src = "src/"

# Path segments of contract files to include in the analysis.
# - It can be a partial match like "/interfaces/", which will include all files with "/interfaces/" in the file path.
#   Or it can be a full match like "src/counters/Counter.sol", which will include only the file with the exact path.
# - If not specified, all contract files in the source directory will be included.
# Examples:
# include = ["src/counters/Counter.sol", "src/others/"]
# include = ["/interfaces/"]

# Path segments of contract files to exclude in the analysis.
# - It can be a partial match like "/interfaces/", which will exclude all files with "/interfaces/" in the file path.
#   Or it can be a full match like "src/counters/Counter.sol", which will exclude only the file with the exact path.
# - If not specified, no contract files will be excluded.
# Examples:
# exclude = ["src/counters/Counter.sol", "src/others/"]
# exclude = ["/interfaces/"]

# For advanced use cases, leverage the following

# Remappings 
# - It can be specified in `remappings.txt` within the root folder of the project.
# - If not specified, Aderyn will try to derive the values from foundry.toml (if present.)

# Environment
# - These are usually all the FOUNDRY_, DAPP_ environment variables that are used during development.
# - For example, if different profiles have different `src` declaration in `foundry.toml`, FOUNDRY_PROFILE can dictate the correct `src` value.
#   Env variables and their values can be specified below.

[env]
# Example:
# FOUNDRY_PROFILE = "default"

```

--------------------------------------------------------------------------------
/tests/toml/nested_project1/aderyn.toml:
--------------------------------------------------------------------------------

```toml
# Aderyn Configuration File
# Help Aderyn work with more granular control

# DO NOT CHANGE version below. As of now, only 1 is supported
version = 1

# Read the description carefully and uncomment the examples in each paragraph should you consider using them.

# Base path for resolving remappings and compiling smart contracts, relative to workspace-root (directory in which the editor is open)
# Most of the time, you want to point it to the directory containing foundry.toml or hardhat.config.js/ts.
root = "folder2"

# Path of source directory containing the contracts, relative to root (above)
# Aderyn will traverse all the nested files inside to scan and report vulnerabilities found inside.
# - If not specified, Aderyn will try to extract it from the framework that is being used. (Foundry / Hardhat). 
#   That would be "contracts/" in case of Hardhat and in case of Foundry, it depends on foundry.toml and
#   many other factors like FOUNDRY_PROFILE environment variable, etc.
# - If specified, Aderyn will override the above found `src`.
# Example:
# src = "src/"

# Path segments of contract files to include in the analysis.
# - It can be a partial match like "/interfaces/", which will include all files with "/interfaces/" in the file path.
#   Or it can be a full match like "src/counters/Counter.sol", which will include only the file with the exact path.
# - If not specified, all contract files in the source directory will be included.
# Examples:
# include = ["src/counters/Counter.sol", "src/others/"]
# include = ["/interfaces/"]

# Path segments of contract files to exclude in the analysis.
# - It can be a partial match like "/interfaces/", which will exclude all files with "/interfaces/" in the file path.
#   Or it can be a full match like "src/counters/Counter.sol", which will exclude only the file with the exact path.
# - If not specified, no contract files will be excluded.
# Examples:
# exclude = ["src/counters/Counter.sol", "src/others/"]
# exclude = ["/interfaces/"]

# For advanced use cases, leverage the following

# Remappings 
# - It can be specified in `remappings.txt` within the root folder of the project.
# - If not specified, Aderyn will try to derive the values from foundry.toml (if present.)

# Environment
# - These are usually all the FOUNDRY_, DAPP_ environment variables that are used during development.
# - For example, if different profiles have different `src` declaration in `foundry.toml`, FOUNDRY_PROFILE can dictate the correct `src` value.
#   Env variables and their values can be specified below.

[env]
# Example:
# FOUNDRY_PROFILE = "default"

```

--------------------------------------------------------------------------------
/tests/toml/nested_project2/aderyn.toml:
--------------------------------------------------------------------------------

```toml
# Aderyn Configuration File
# Help Aderyn work with more granular control

# DO NOT CHANGE version below. As of now, only 1 is supported
version = 1

# Read the description carefully and uncomment the examples in each paragraph should you consider using them.

# Base path for resolving remappings and compiling smart contracts, relative to workspace-root (directory in which the editor is open)
# Most of the time, you want to point it to the directory containing foundry.toml or hardhat.config.js/ts.
root = "folder1"

# Path of source directory containing the contracts, relative to root (above)
# Aderyn will traverse all the nested files inside to scan and report vulnerabilities found inside.
# - If not specified, Aderyn will try to extract it from the framework that is being used. (Foundry / Hardhat). 
#   That would be "contracts/" in case of Hardhat and in case of Foundry, it depends on foundry.toml and
#   many other factors like FOUNDRY_PROFILE environment variable, etc.
# - If specified, Aderyn will override the above found `src`.
# Example:
# src = "src/"

# Path segments of contract files to include in the analysis.
# - It can be a partial match like "/interfaces/", which will include all files with "/interfaces/" in the file path.
#   Or it can be a full match like "src/counters/Counter.sol", which will include only the file with the exact path.
# - If not specified, all contract files in the source directory will be included.
# Examples:
# include = ["src/counters/Counter.sol", "src/others/"]
# include = ["/interfaces/"]

# Path segments of contract files to exclude in the analysis.
# - It can be a partial match like "/interfaces/", which will exclude all files with "/interfaces/" in the file path.
#   Or it can be a full match like "src/counters/Counter.sol", which will exclude only the file with the exact path.
# - If not specified, no contract files will be excluded.
# Examples:
# exclude = ["src/counters/Counter.sol", "src/others/"]
# exclude = ["/interfaces/"]

# For advanced use cases, leverage the following

# Remappings 
# - It can be specified in `remappings.txt` within the root folder of the project.
# - If not specified, Aderyn will try to derive the values from foundry.toml (if present.)

# Environment
# - These are usually all the FOUNDRY_, DAPP_ environment variables that are used during development.
# - For example, if different profiles have different `src` declaration in `foundry.toml`, FOUNDRY_PROFILE can dictate the correct `src` value.
#   Env variables and their values can be specified below.

[env]
# Example:
# FOUNDRY_PROFILE = "default"

```

--------------------------------------------------------------------------------
/aderyn_core/src/detect/low/modifier_used_only_once.rs:
--------------------------------------------------------------------------------

```rust
use std::{
    collections::{BTreeMap, HashMap},
    error::Error,
};

use crate::{
    ast::NodeID,
    capture,
    context::workspace::WorkspaceContext,
    detect::detector::{IssueDetector, IssueDetectorNamePool, IssueSeverity},
};
use eyre::Result;

#[derive(Default)]
pub struct ModifierUsedOnlyOnceDetector {
    // Keys are: [0] source file name, [1] line number, [2] character location of node.
    // Do not add items manually, use `capture!` to add nodes to this BTreeMap.
    found_instances: BTreeMap<(String, usize, String), NodeID>,
}

impl IssueDetector for ModifierUsedOnlyOnceDetector {
    fn detect(&mut self, context: &WorkspaceContext) -> Result<bool, Box<dyn Error>> {
        let mut invocations: HashMap<i64, usize> = HashMap::new();

        for inv in context.modifier_invocations() {
            if let Some(id) = inv.modifier_name.referenced_declaration() {
                match invocations.entry(id) {
                    std::collections::hash_map::Entry::Occupied(mut o) => *o.get_mut() += 1,
                    std::collections::hash_map::Entry::Vacant(v) => {
                        v.insert(1);
                    }
                };
            }
        }

        for modifier in context.modifier_definitions() {
            let count = *invocations.get(&modifier.id).unwrap_or(&0);
            if count == 1 {
                capture!(self, context, modifier);
            }
        }

        Ok(!self.found_instances.is_empty())
    }

    fn title(&self) -> String {
        String::from("Modifier Invoked Only Once")
    }

    fn description(&self) -> String {
        String::from(
            "Consider removing the modifier or inlining the logic into the calling function.",
        )
    }

    fn severity(&self) -> IssueSeverity {
        IssueSeverity::Low
    }

    fn instances(&self) -> BTreeMap<(String, usize, String), NodeID> {
        self.found_instances.clone()
    }

    fn name(&self) -> String {
        format!("{}", IssueDetectorNamePool::ModifierUsedOnlyOnce)
    }
}

#[cfg(test)]
mod useless_modifier_tests {
    use crate::detect::detector::IssueDetector;

    use super::ModifierUsedOnlyOnceDetector;

    #[test]

    fn test_useless_modifier_tests_by_loading_contract_directly() {
        let context = crate::detect::test_utils::load_solidity_source_unit(
            "../tests/contract-playground/src/OnceModifierExample.sol",
        );

        let mut detector = ModifierUsedOnlyOnceDetector::default();
        let found = detector.detect(&context).unwrap();
        assert!(found);
        assert_eq!(detector.instances().len(), 1);
    }
}

```

--------------------------------------------------------------------------------
/aderyn_driver/src/mcp.rs:
--------------------------------------------------------------------------------

```rust
use crate::process::WorkspaceContextWrapper;

use aderyn_core::context::mcp::*;
use rmcp::{
    ErrorData as McpError, RoleServer, ServerHandler, handler::server::router::tool::ToolRouter,
    model::*, service::RequestContext, tool_handler,
};
use std::sync::Arc;

pub struct McpServer {
    tool_router: ToolRouter<Self>,
}

impl McpServer {
    pub fn new(raw_state: WorkspaceContextWrapper) -> Self {
        let state = Arc::new(ModelContextProtocolState {
            contexts: raw_state.contexts,
            root_path: raw_state.root_path,
            project_config: raw_state.project_config,
        });
        let tools = get_all_mcp_tools(state);
        let mut tool_router = ToolRouter::new();
        tools.into_iter().for_each(|r| tool_router.add_route(r));
        Self { tool_router }
    }
}

#[tool_handler]
impl ServerHandler for McpServer {
    async fn initialize(
        &self,
        _request: InitializeRequestParam,
        _context: RequestContext<RoleServer>,
    ) -> Result<rmcp::model::InitializeResult, McpError> {
        Ok(ServerInfo {
            protocol_version: ProtocolVersion::V_2024_11_05,
            capabilities: ServerCapabilities::builder().enable_tools().build(),
            server_info: Implementation::from_build_env(),
            instructions: Some(
                "Intelligently search for patterns in Solidity codebases. To get started, call the tool guide."
                    .to_string(),
            ),
        })
    }
}

#[derive(Clone)]
pub struct SingletonMcpServer(Arc<McpServer>);

impl SingletonMcpServer {
    pub fn new(inner: McpServer) -> Self {
        Self(Arc::new(inner))
    }
}

impl ServerHandler for SingletonMcpServer {
    fn initialize(
        &self,
        request: InitializeRequestParam,
        context: RequestContext<RoleServer>,
    ) -> impl std::future::Future<Output = Result<rmcp::model::InitializeResult, McpError>> + Send + '_
    {
        let inner = self.0.clone();
        async move { inner.initialize(request, context).await }
    }

    fn call_tool(
        &self,
        request: CallToolRequestParam,
        context: RequestContext<RoleServer>,
    ) -> impl std::future::Future<Output = Result<CallToolResult, McpError>> + Send + '_ {
        let inner = self.0.clone();
        async move { inner.call_tool(request, context).await }
    }

    fn list_tools(
        &self,
        request: Option<PaginatedRequestParam>,
        context: RequestContext<RoleServer>,
    ) -> impl std::future::Future<Output = Result<ListToolsResult, McpError>> + Send + '_ {
        let inner = self.0.clone();
        async move { inner.list_tools(request, context).await }
    }
}

```

--------------------------------------------------------------------------------
/aderyn_core/src/context/mcp/list_contracts/tool.rs:
--------------------------------------------------------------------------------

```rust
use crate::context::{
    macros::{mcp_error, mcp_success},
    mcp::{
        MCPToolNamePool, ModelContextProtocolState, ModelContextProtocolTool,
        list_contracts::render::{ContractInfoBuilder, ContractsListBuilder},
    },
};
use indoc::indoc;
use rmcp::{
    ErrorData as McpError, handler::server::wrapper::Parameters, model::CallToolResult, schemars,
};
use serde::Deserialize;
use std::sync::Arc;

#[derive(Clone)]
pub struct ListContractsTool {
    state: Arc<ModelContextProtocolState>,
}

#[derive(Deserialize, schemars::JsonSchema)]
pub struct ListContractsPayload {
    /// The index of the compilation unit to analyze. Must be a positive integer starting from 1.
    /// Use the project overview tool first to see all available compilation units and their
    /// indices.
    pub compilation_unit_index: usize,
}

impl ModelContextProtocolTool for ListContractsTool {
    type Input = ListContractsPayload;

    fn new(state: Arc<ModelContextProtocolState>) -> Self {
        Self { state }
    }

    fn name(&self) -> String {
        MCPToolNamePool::AderynListContracts.to_string()
    }

    fn description(&self) -> String {
        indoc! {
            "Enumerates deployable contracts within a specific compilation unit. Returns contract names, \
            file names (relative to the project root) and node IDs."
        }
        .to_string()
    }

    fn execute(&self, input: Parameters<Self::Input>) -> Result<CallToolResult, McpError> {
        let comp_unit_idx = input.0.compilation_unit_index;
        if comp_unit_idx < 1 || comp_unit_idx > self.state.contexts.len() {
            return mcp_error!(
                "invalid value passed for compilation unit - must be in the range [1, {}] inclusive",
                self.state.contexts.len()
            );
        }
        let context = self.state.contexts.get(comp_unit_idx - 1).expect("bounds check failed");
        let mut contracts_info = vec![];
        for contract in context.deployable_contracts() {
            let (filepath, _, _) = context.get_node_sort_key_from_capturable(&contract.into());
            let contract_info = ContractInfoBuilder::default()
                .name(contract.name.clone())
                .filepath(filepath)
                .node_id(contract.id)
                .build()
                .expect("failed to build contract info");
            contracts_info.push(contract_info);
        }

        let contract_list = ContractsListBuilder::default()
            .compilation_unit_index(comp_unit_idx)
            .contracts_info(contracts_info)
            .build()
            .expect("failed to build contracts list");

        mcp_success!(contract_list)
    }
}

```

--------------------------------------------------------------------------------
/tests/ast/base_constructor_call.json:
--------------------------------------------------------------------------------

```json
{"absolutePath":"a","exportedSymbols":{"A":[7],"C":[17]},"id":18,"nodeType":"SourceUnit","nodes":[{"abstract":false,"baseContracts":[],"canonicalName":"A","contractDependencies":[],"contractKind":"contract","fullyImplemented":true,"id":7,"linearizedBaseContracts":[7],"name":"A","nameLocation":"9:1:1","nodeType":"ContractDefinition","nodes":[{"body":{"id":5,"nodeType":"Block","src":"31:2:1","statements":[]},"id":6,"implemented":true,"kind":"constructor","modifiers":[],"name":"","nameLocation":"-1:-1:-1","nodeType":"FunctionDefinition","parameters":{"id":3,"nodeType":"ParameterList","parameters":[{"constant":false,"id":2,"mutability":"mutable","name":"","nameLocation":"-1:-1:-1","nodeType":"VariableDeclaration","scope":6,"src":"25:4:1","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"},"typeName":{"id":1,"name":"uint","nodeType":"ElementaryTypeName","src":"25:4:1","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"visibility":"internal"}],"src":"24:6:1"},"returnParameters":{"id":4,"nodeType":"ParameterList","parameters":[],"src":"31:0:1"},"scope":7,"src":"13:20:1","stateMutability":"nonpayable","virtual":false,"visibility":"public"}],"scope":18,"src":"0:35:1","usedErrors":[]},{"abstract":false,"baseContracts":[{"baseName":{"id":8,"name":"A","nameLocations":["50:1:1"],"nodeType":"IdentifierPath","referencedDeclaration":7,"src":"50:1:1"},"id":9,"nodeType":"InheritanceSpecifier","src":"50:1:1"}],"canonicalName":"C","contractDependencies":[],"contractKind":"contract","fullyImplemented":true,"id":17,"linearizedBaseContracts":[17,7],"name":"C","nameLocation":"45:1:1","nodeType":"ContractDefinition","nodes":[{"body":{"id":15,"nodeType":"Block","src":"73:2:1","statements":[]},"id":16,"implemented":true,"kind":"constructor","modifiers":[{"arguments":[{"hexValue":"32","id":12,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"70:1:1","typeDescriptions":{"typeIdentifier":"t_rational_2_by_1","typeString":"int_const 2"},"value":"2"}],"id":13,"kind":"baseConstructorSpecifier","modifierName":{"id":11,"name":"A","nameLocations":["68:1:1"],"nodeType":"IdentifierPath","referencedDeclaration":7,"src":"68:1:1"},"nodeType":"ModifierInvocation","src":"68:4:1"}],"name":"","nameLocation":"-1:-1:-1","nodeType":"FunctionDefinition","parameters":{"id":10,"nodeType":"ParameterList","parameters":[],"src":"65:2:1"},"returnParameters":{"id":14,"nodeType":"ParameterList","parameters":[],"src":"73:0:1"},"scope":17,"src":"54:21:1","stateMutability":"nonpayable","virtual":false,"visibility":"public"}],"scope":18,"src":"36:41:1","usedErrors":[]}],"src":"0:78:1"}

```

--------------------------------------------------------------------------------
/aderyn_core/src/detect/low/empty_require_revert.rs:
--------------------------------------------------------------------------------

```rust
use std::{collections::BTreeMap, error::Error};

use crate::{
    ast::NodeID,
    capture,
    context::workspace::WorkspaceContext,
    detect::detector::{IssueDetector, IssueDetectorNamePool, IssueSeverity},
};
use eyre::Result;

#[derive(Default)]
pub struct EmptyRequireRevertDetector {
    // Keys are: [0] source file name, [1] line number, [2] character location of node.
    // Do not add items manually, use `capture!` to add nodes to this BTreeMap.
    found_instances: BTreeMap<(String, usize, String), NodeID>,
}

impl IssueDetector for EmptyRequireRevertDetector {
    fn detect(&mut self, context: &WorkspaceContext) -> Result<bool, Box<dyn Error>> {
        // Collect all require statements without a string literal.
        let requires_and_reverts = context
            .identifiers()
            .into_iter()
            .filter(|&id| id.name == "revert" || id.name == "require");

        for id in requires_and_reverts {
            if (id.name == "revert" && id.argument_types.as_ref().unwrap().is_empty())
                || (id.name == "require" && id.argument_types.as_ref().unwrap().len() == 1)
            {
                capture!(self, context, id);
            }
        }

        Ok(!self.found_instances.is_empty())
    }

    fn title(&self) -> String {
        String::from("Empty `require()` / `revert()` Statement")
    }

    fn description(&self) -> String {
        String::from("Use descriptive reason strings or custom errors for revert paths.")
    }

    fn severity(&self) -> IssueSeverity {
        IssueSeverity::Low
    }

    fn instances(&self) -> BTreeMap<(String, usize, String), NodeID> {
        self.found_instances.clone()
    }

    fn name(&self) -> String {
        format!("{}", IssueDetectorNamePool::EmptyRequireRevert)
    }
}

#[cfg(test)]
mod require_with_string_tests {

    use crate::detect::detector::IssueDetector;

    use super::EmptyRequireRevertDetector;

    #[test]
    fn test_require_with_string_by_loading_contract_directly() {
        let context = crate::detect::test_utils::load_solidity_source_unit(
            "../tests/contract-playground/src/DeprecatedOZFunctions.sol",
        );

        let mut detector = EmptyRequireRevertDetector::default();
        let found = detector.detect(&context).unwrap();
        assert!(found);
        assert_eq!(detector.instances().len(), 2);
    }

    #[test]
    fn test_require_with_custom_error_by_loading_contract_directly() {
        let context = crate::detect::test_utils::load_solidity_source_unit(
            "../tests/contract-playground/src/UnusedError.sol",
        );

        let mut detector = EmptyRequireRevertDetector::default();
        let found = detector.detect(&context).unwrap();
        assert!(!found);
    }
}

```

--------------------------------------------------------------------------------
/aderyn_core/src/context/graph/traits.rs:
--------------------------------------------------------------------------------

```rust
use crate::ast::{ASTNode, FunctionDefinition, ModifierDefinition};

/// Trait to support reversing of callgraph. (Because, direct impl is not allowed on Foreign Types)
pub trait Transpose {
    fn reverse(&self) -> Self;
}

/// Use with [`super::CallGraph`]
pub trait CallGraphVisitor {
    /// Shift all logic to tracker otherwise, you would track state at 2 different places
    /// One at the tracker level, and other at the application level. Instead, we must
    /// contain all of the tracking logic in the tracker. Therefore, visit entry point
    /// is essential because the tracker can get to take a look at not just the
    /// inward functions and modifiers, but also the entry points that have invoked it.
    fn visit_entry_point(&mut self, node: &ASTNode) -> eyre::Result<()> {
        self.visit_any(node)
    }

    /// Meant to be invoked while traversing
    /// [`crate::context::workspace_context::WorkspaceContext::inward_callgraph`]
    fn visit_inward_function_definition(&mut self, node: &FunctionDefinition) -> eyre::Result<()> {
        self.visit_any(&(node.into()))
    }

    /// Meant to be invoked while traversing
    /// [`crate::context::workspace_context::WorkspaceContext::outward_callgraph`]
    fn visit_outward_function_definition(&mut self, node: &FunctionDefinition) -> eyre::Result<()> {
        self.visit_any(&(node.into()))
    }

    /// Meant to be invoked while traversing
    /// [`crate::context::workspace_context::WorkspaceContext::inward_callgraph`]
    fn visit_inward_modifier_definition(&mut self, node: &ModifierDefinition) -> eyre::Result<()> {
        self.visit_any(&(node.into()))
    }

    /// Meant to be invoked while traversing
    /// [`crate::context::workspace_context::WorkspaceContext::outward_callgraph`]
    fn visit_outward_modifier_definition(&mut self, node: &ModifierDefinition) -> eyre::Result<()> {
        self.visit_any(&(node.into()))
    }

    /// Read as "outward's inward-side-effect" function definition
    /// These are function definitions that are inward from the outward nodes
    /// but are themselves neither outward nor inward to the entry points
    fn visit_outward_side_effect_function_definition(
        &mut self,
        node: &FunctionDefinition,
    ) -> eyre::Result<()> {
        self.visit_any(&(node.into()))
    }

    /// Read as "outward's inward-side-effect" modifier definition
    /// These are modifier definitions that are inward from the outward nodes
    /// but are themselves neither outward nor inward to the entry points
    fn visit_outward_side_effect_modifier_definition(
        &mut self,
        node: &ModifierDefinition,
    ) -> eyre::Result<()> {
        self.visit_any(&(node.into()))
    }

    fn visit_any(&mut self, _node: &ASTNode) -> eyre::Result<()> {
        Ok(())
    }
}

```

--------------------------------------------------------------------------------
/aderyn_core/src/context/graph/preprocess/new.rs:
--------------------------------------------------------------------------------

```rust
use crate::{
    ast::ContractDefinition,
    context::{
        browser::{ExtractFunctionCalls, ExtractModifierInvocations},
        graph::*,
        workspace::WorkspaceContext,
    },
};
use std::collections::{HashSet, hash_map::*};

impl WorkspaceCallGraphs {
    pub fn build(context: &WorkspaceContext) -> WorkspaceCallGraphs {
        let mut workspace_cg: WorkspaceCallGraphs = Default::default();
        for contract in context.deployable_contracts() {
            if let Some(raw_callgraph) = _create_raw_callgraph(context, contract) {
                workspace_cg.inward_callgraphs.insert(contract.id, raw_callgraph.clone());
                workspace_cg.outward_callgraphs.insert(contract.id, raw_callgraph.reverse());
            }
        }
        workspace_cg
    }
}

pub fn _create_raw_callgraph(
    context: &WorkspaceContext,
    contract: &ContractDefinition,
) -> Option<RawCallGraph> {
    let mut raw_callgraph = Default::default();
    let mut visited: HashSet<NodeID> = Default::default();
    for entrypoint in context.entrypoint_functions(contract)? {
        let mut current = vec![entrypoint.id];
        while let Some(node_id) = current.pop() {
            if visited.contains(&node_id) {
                continue;
            }
            visited.insert(node_id);
            create_node_if_not_exists(node_id, &mut raw_callgraph);
            let Some(node) = context.nodes.get(&node_id) else {
                continue;
            };
            for function_call in ExtractFunctionCalls::from(node).extracted {
                if let Some(f) = context.resolve_internal_call(contract, &function_call) {
                    create_connection_if_not_exists(node_id, f.id, &mut raw_callgraph);
                    current.push(f.id);
                }
            }
            for modifier_call in ExtractModifierInvocations::from(node).extracted {
                if let Some(m) = context.resolve_modifier_call(contract, &modifier_call) {
                    create_connection_if_not_exists(node_id, m.id, &mut raw_callgraph);
                    current.push(m.id);
                }
            }
        }
    }
    Some(raw_callgraph)
}

fn create_node_if_not_exists(node_id: NodeID, raw_callgraph: &mut RawCallGraph) {
    if let Entry::Vacant(v) = raw_callgraph.entry(node_id) {
        v.insert(vec![]);
    }
}

fn create_connection_if_not_exists(
    from_id: NodeID,
    to_id: NodeID,
    raw_callgraph: &mut RawCallGraph,
) {
    match raw_callgraph.entry(from_id) {
        Entry::Occupied(mut o) => {
            // Performance Tip: Maybe later use binary search (it requires keeping ascending order
            // while inserting tho)
            if !o.get().contains(&to_id) {
                o.get_mut().push(to_id);
            }
        }
        Entry::Vacant(v) => {
            v.insert(vec![to_id]);
        }
    }
}

```

--------------------------------------------------------------------------------
/aderyn_core/src/detect/high/dynamic_array_length_assignment.rs:
--------------------------------------------------------------------------------

```rust
use std::{collections::BTreeMap, error::Error};

use crate::ast::NodeID;

use crate::{
    capture,
    context::workspace::WorkspaceContext,
    detect::detector::{IssueDetector, IssueDetectorNamePool, IssueSeverity},
};
use eyre::Result;

#[derive(Default)]
pub struct DynamicArrayLengthAssignmentDetector {
    // Keys are: [0] source file name, [1] line number, [2] character location of node.
    // Do not add items manually, use `capture!` to add nodes to this BTreeMap.
    found_instances: BTreeMap<(String, usize, String), NodeID>,
}

impl IssueDetector for DynamicArrayLengthAssignmentDetector {
    fn detect(&mut self, context: &WorkspaceContext) -> Result<bool, Box<dyn Error>> {
        for member_access in context
            .member_accesses()
            .into_iter()
            .filter(|member_access| member_access.l_value_requested)
        {
            let assignment_to = member_access.expression.type_descriptions();

            let is_being_assigned_on_dynamic_array = assignment_to.is_some_and(|assignment_to| {
                assignment_to
                    .type_string
                    .as_ref()
                    .is_some_and(|type_string| type_string.ends_with("[] storage ref"))
            });

            let is_being_assigned_to_length_property = member_access.member_name == "length";

            if is_being_assigned_on_dynamic_array && is_being_assigned_to_length_property {
                capture!(self, context, member_access);
            }
        }

        Ok(!self.found_instances.is_empty())
    }

    fn severity(&self) -> IssueSeverity {
        IssueSeverity::High
    }

    fn title(&self) -> String {
        String::from("Direct assignment of array length")
    }

    fn description(&self) -> String {
        String::from(
            "If the length of a dynamic array (storage variable) is directly assigned to, \
        it may allow access to other storage slots by tweaking it's value. This practice has \
        been deprecated in newer Solidity versions",
        )
    }

    fn instances(&self) -> BTreeMap<(String, usize, String), NodeID> {
        self.found_instances.clone()
    }

    fn name(&self) -> String {
        IssueDetectorNamePool::DynamicArrayLengthAssignment.to_string()
    }
}

#[cfg(test)]
mod dynamic_array_length_assignment_tests {

    use crate::detect::{
        detector::IssueDetector, high::DynamicArrayLengthAssignmentDetector,
        test_utils::load_solidity_source_unit,
    };

    #[test]

    fn test_dynamic_array_length_assignment() {
        let context = load_solidity_source_unit(
            "../tests/contract-playground/src/DynamicArrayLengthAssignment.sol",
        );

        let mut detector = DynamicArrayLengthAssignmentDetector::default();
        let found = detector.detect(&context).unwrap();

        assert!(found);
        assert_eq!(detector.instances().len(), 5);
    }
}

```

--------------------------------------------------------------------------------
/aderyn_core/src/detect/low/redundant_statement.rs:
--------------------------------------------------------------------------------

```rust
use std::{collections::BTreeMap, error::Error};

use crate::ast::{Expression, NodeID, NodeType};

use crate::{
    capture,
    context::{browser::GetImmediateParent, workspace::WorkspaceContext},
    detect::detector::{IssueDetector, IssueDetectorNamePool, IssueSeverity},
};
use eyre::Result;

// HOW TO USE THIS TEMPLATE:
// 1. Copy this file and rename it to the snake_case version of the issue you are detecting.
// 2. Rename the RedundantStatementDetector struct and impl to your new issue name.
// 3. Add this file and detector struct to the mod.rs file in the same directory.
// 4. Implement the detect function to find instances of the issue.

#[derive(Default)]
pub struct RedundantStatementDetector {
    // Keys are: [0] source file name, [1] line number, [2] character location of node.
    // Do not add items manually, use `capture!` to add nodes to this BTreeMap.
    found_instances: BTreeMap<(String, usize, String), NodeID>,
}

impl IssueDetector for RedundantStatementDetector {
    fn detect(&mut self, context: &WorkspaceContext) -> Result<bool, Box<dyn Error>> {
        for expression_statement in context.expression_statements() {
            if let Some(parent) = expression_statement.parent(context) {
                if parent.node_type() != NodeType::Block {
                    continue;
                }

                match &expression_statement.expression {
                    Expression::Identifier(identifier) => {
                        capture!(self, context, identifier);
                    }
                    Expression::ElementaryTypeNameExpression(elementary_type_expression) => {
                        capture!(self, context, elementary_type_expression);
                    }
                    _ => (),
                };
            }
        }

        Ok(!self.found_instances.is_empty())
    }

    fn severity(&self) -> IssueSeverity {
        IssueSeverity::Low
    }

    fn title(&self) -> String {
        String::from("Redundant Statement")
    }

    fn description(&self) -> String {
        String::from("Remove the redundant statement.")
    }

    fn instances(&self) -> BTreeMap<(String, usize, String), NodeID> {
        self.found_instances.clone()
    }

    fn name(&self) -> String {
        IssueDetectorNamePool::RedundantStatement.to_string()
    }
}

#[cfg(test)]
mod redundant_statements_detector {

    use crate::detect::{
        detector::IssueDetector, low::redundant_statement::RedundantStatementDetector,
    };

    #[test]

    fn test_redundant_statements() {
        let context = crate::detect::test_utils::load_solidity_source_unit(
            "../tests/contract-playground/src/RedundantStatements.sol",
        );

        let mut detector = RedundantStatementDetector::default();
        let found = detector.detect(&context).unwrap();
        assert!(found);
        assert_eq!(detector.instances().len(), 6);
    }
}

```
Page 5/94FirstPrevNextLast