#
tokens: 49627/50000 42/1140 files (page 6/94)
lines: off (toggle) GitHub
raw markdown copy
This is page 6 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

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

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

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

#[derive(Default)]
pub struct TodoDetector {
    // 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 TodoDetector {
    fn detect(&mut self, context: &WorkspaceContext) -> Result<bool, Box<dyn Error>> {
        for contract in context.contract_definitions() {
            let contract_as_ast: ASTNode = contract.into();
            if let Some(contract_code) = contract_as_ast.peek(context) {
                if contract_code.is_empty() {
                    continue;
                }
                let tokens = stats::token::tokenize(&contract_code);
                for token in tokens {
                    match token.token_type {
                        stats::token::TokenType::MultilineComment
                        | stats::token::TokenType::SinglelineComment => {
                            if token.content.to_lowercase().contains("todo") {
                                capture!(self, context, contract);
                                break;
                            }
                        }
                        _ => (),
                    }
                }
            }
        }

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

    fn title(&self) -> String {
        String::from("Contract has TODO Comments")
    }

    fn description(&self) -> String {
        String::from(
            "Contract contains comments with TODOS. Consider implementing or removing them.",
        )
    }

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

    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!("{}", IssueDetectorNamePool::Todo)
    }
}

#[cfg(test)]
mod contracts_with_todos_tests {

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

    use super::TodoDetector;

    #[test]

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

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

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

```

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

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

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

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

#[derive(Default)]
pub struct UncheckedSendDetector {
    // 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 UncheckedSendDetector {
    fn detect(&mut self, context: &WorkspaceContext) -> Result<bool, Box<dyn Error>> {
        for member_access in context.member_accesses() {
            if member_access.member_name == "send"
                && member_access.expression.type_descriptions().is_some_and(|type_desc| {
                    type_desc.type_string.as_ref().is_some_and(|type_string| {
                        type_string == "address" || type_string == "address payable"
                    })
                })
                && let Some(ASTNode::FunctionCall(func_call)) = member_access.parent(context)
                && let Some(ASTNode::ExpressionStatement(expr_stmnt)) = func_call.parent(context)
                && expr_stmnt
                    .parent(context)
                    .is_some_and(|node| node.node_type() == NodeType::Block)
            {
                capture!(self, context, func_call);
            }
        }

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

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

    fn title(&self) -> String {
        String::from("Unchecked `bool success` value for ETH send")
    }

    fn description(&self) -> String {
        String::from(
            "The call `address(payable?).send(address)` may fail because of reasons like out-of-gas, \
        invalid recipient address or revert from the recipient, but not revert the transaction. Therefore, the boolean returned by this function call must be checked \
        to be `true` in order to verify that the transaction was successful.",
        )
    }

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

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

#[cfg(test)]
mod unchecked_send_tests {

    use crate::detect::{detector::IssueDetector, high::unchecked_send::UncheckedSendDetector};

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

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

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

```

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

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

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

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

#[derive(Default)]
pub struct ReusedContractNameDetector {
    // 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 ReusedContractNameDetector {
    fn detect(&mut self, context: &WorkspaceContext) -> Result<bool, Box<dyn Error>> {
        let mut contract_names: HashMap<&str, Vec<&ContractDefinition>> = HashMap::new();

        // Simplify the map filling process using the Entry API
        for contract in context.contract_definitions() {
            contract_names.entry(&contract.name).or_default().push(contract);
        }

        // Process duplicate contracts
        contract_names
            .values() // Directly iterate over values
            .filter(|contracts| contracts.len() > 1) // Filter for duplicates
            .flatten() // Flatten the list of lists to a single list of contracts
            .for_each(|contract| capture!(self, context, contract)); // Process each contract

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

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

    fn title(&self) -> String {
        String::from("Contract Name Reused in Different Files")
    }

    fn description(&self) -> String {
        String::from(
            "When compiling contracts with certain development frameworks (for example: Truffle), having contracts with the same name across different files can lead to one being overwritten.",
        )
    }

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

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

#[cfg(test)]
mod reused_contract_name_detector_tests {
    use semver::Version;

    use crate::detect::{
        detector::IssueDetector, high::ReusedContractNameDetector,
        test_utils::load_multiple_solidity_source_units_into_single_context,
    };

    #[test]

    fn test_reused_contract_name_detector() {
        let context = load_multiple_solidity_source_units_into_single_context(
            &[
                "../tests/contract-playground/src/reused_contract_name/ContractA.sol",
                "../tests/contract-playground/src/reused_contract_name/ContractB.sol",
            ],
            Version::new(0, 8, 19),
        );

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

```

--------------------------------------------------------------------------------
/aderyn_core/tests/traversal.rs:
--------------------------------------------------------------------------------

```rust
mod common;

use aderyn_core::detect::{detector::IssueDetector, test_utils::load_solidity_source_unit};
use common::*;

#[test]
fn test_immediate_parent_demo() {
    let context = load_solidity_source_unit(
        "../tests/contract-playground/src/parent_chain/ParentChainContract.sol",
    );

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

    println!("Total number of instances: {:?}", detector.instances().len());
    assert!(detector.instances().len() == 3);
}

#[test]
fn test_immediate_child_demo() {
    let context = load_solidity_source_unit(
        "../tests/contract-playground/src/parent_chain/ParentChainContract.sol",
    );

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

    println!("Total number of instances: {:?}", detector.instances().len());
    assert!(detector.instances().len() == 1);
}

#[test]
fn test_closest_ancestor() {
    let context = load_solidity_source_unit(
        "../tests/contract-playground/src/parent_chain/ParentChainContract.sol",
    );

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

    println!("Total number of instances: {:?}", detector.instances().len());
    assert!(detector.instances().len() == 4);
}

#[test]
fn test_ancestral_line_demo() {
    let context = load_solidity_source_unit(
        "../tests/contract-playground/src/parent_chain/ParentChainContract.sol",
    );

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

    println!("Total number of instances: {:?}", detector.instances().len());
    assert!(detector.instances().len() == 4);
}

#[test]
fn test_new_ast_nodes() {
    let context = load_solidity_source_unit("../tests/adhoc-sol-files/DemoASTNodes.sol");

    let mut detector = NewASTNodesDemonstrator::default();
    let _ = detector.detect(&context).unwrap();

    let instances = detector.instances();
    //println!("{:?}", instances);

    assert!(instances.len() == 4);
}

#[test]
fn transient_can_compile() {
    load_solidity_source_unit("../tests/contract-playground/src/TransientKeyword.sol");
}

#[test]
fn test_peek_over() {
    let context =
        load_solidity_source_unit("../tests/contract-playground/src/StorageConditionals.sol");
    let mut detector = PeekOverDemonstrator::default();
    let _ = detector.detect(&context).unwrap();

    let instances = detector.instances();
    assert!(instances.len() == 2);
}

#[test]
fn test_siblings() {
    let context =
        load_solidity_source_unit("../tests/contract-playground/src/StorageConditionals.sol");

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

```

--------------------------------------------------------------------------------
/tests/ast/used_errors.json:
--------------------------------------------------------------------------------

```json
{"absolutePath":"a","exportedSymbols":{"C":[19],"X":[2],"f":[9]},"id":20,"nodeType":"SourceUnit","nodes":[{"errorSelector":"c1599bd9","id":2,"name":"X","nameLocation":"6:1:1","nodeType":"ErrorDefinition","parameters":{"id":1,"nodeType":"ParameterList","parameters":[],"src":"7:2:1"},"src":"0:10:1"},{"body":{"id":8,"nodeType":"Block","src":"29:15:1","statements":[{"errorCall":{"arguments":[],"expression":{"argumentTypes":[],"id":5,"name":"X","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":2,"src":"38:1:1","typeDescriptions":{"typeIdentifier":"t_function_error_pure$__$returns$__$","typeString":"function () pure"}},"id":6,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"nameLocations":[],"names":[],"nodeType":"FunctionCall","src":"38:3:1","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":7,"nodeType":"RevertStatement","src":"31:10:1"}]},"id":9,"implemented":true,"kind":"freeFunction","modifiers":[],"name":"f","nameLocation":"20:1:1","nodeType":"FunctionDefinition","parameters":{"id":3,"nodeType":"ParameterList","parameters":[],"src":"21:2:1"},"returnParameters":{"id":4,"nodeType":"ParameterList","parameters":[],"src":"29:0:1"},"scope":20,"src":"11:33:1","stateMutability":"pure","virtual":false,"visibility":"internal"},{"abstract":false,"baseContracts":[],"canonicalName":"C","contractDependencies":[],"contractKind":"contract","fullyImplemented":true,"id":19,"linearizedBaseContracts":[19],"name":"C","nameLocation":"54:1:1","nodeType":"ContractDefinition","nodes":[{"errorSelector":"2bc80f3a","id":11,"name":"T","nameLocation":"68:1:1","nodeType":"ErrorDefinition","parameters":{"id":10,"nodeType":"ParameterList","parameters":[],"src":"69:2:1"},"src":"62:10:1"},{"body":{"id":17,"nodeType":"Block","src":"97:8:1","statements":[{"expression":{"arguments":[],"expression":{"argumentTypes":[],"id":14,"name":"f","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":9,"src":"99:1:1","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$__$returns$__$","typeString":"function () pure"}},"id":15,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"nameLocations":[],"names":[],"nodeType":"FunctionCall","src":"99:3:1","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":16,"nodeType":"ExpressionStatement","src":"99:3:1"}]},"functionSelector":"b8c9d365","id":18,"implemented":true,"kind":"function","modifiers":[],"name":"h","nameLocation":"86:1:1","nodeType":"FunctionDefinition","parameters":{"id":12,"nodeType":"ParameterList","parameters":[],"src":"87:2:1"},"returnParameters":{"id":13,"nodeType":"ParameterList","parameters":[],"src":"97:0:1"},"scope":19,"src":"77:28:1","stateMutability":"nonpayable","virtual":false,"visibility":"public"}],"scope":20,"src":"45:62:1","usedErrors":[2,11]}],"src":"0:108:1"}

```

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

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

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

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

#[derive(Default)]
pub struct MultipleConstructorsDetector {
    // 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 MultipleConstructorsDetector {
    fn detect(&mut self, context: &WorkspaceContext) -> Result<bool, Box<dyn Error>> {
        let contracts_with_multiple_constructors = context
            .contract_definitions()
            .into_iter()
            .filter(|&contract| {
                ExtractFunctionDefinitions::from(contract)
                    .extracted
                    .iter()
                    .filter(|function| function.kind() == &FunctionKind::Constructor)
                    .count()
                    > 1
            })
            .collect::<Vec<_>>();

        for contract in contracts_with_multiple_constructors {
            capture!(self, context, contract);
        }

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

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

    fn title(&self) -> String {
        String::from("Contract Has Multiple Constructors")
    }

    fn description(&self) -> String {
        String::from(
            "In some versions of Solidity, contracts compile with multiple constructors. The first constructor takes precedence. This can lead to unexpected behavior.",
        )
    }

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

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

#[cfg(test)]
mod multiple_constructors_detector_tests {

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

    #[test]

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

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

    #[test]

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

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

```

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

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

use crate::ast::{ASTNode, ContractKind, FunctionKind, NodeID, NodeType, Visibility};

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

#[derive(Default)]
pub struct DeadCodeDetector {
    // 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 DeadCodeDetector {
    fn detect(&mut self, context: &WorkspaceContext) -> Result<bool, Box<dyn Error>> {
        // Heuristic:
        // Internal non overriding functions inside of non abstract contracts that have a body
        // (implemented) and are not used If an internal function is marked override then,
        // it may still be used even if it doesn't have a direct referencedDeclaration
        // pointing to it.

        for func in context
            .function_definitions()
            .into_iter()
            .filter(|&f| {
                f.overrides.is_none()
                    && f.implemented
                    && f.visibility == Visibility::Internal
                    && f.kind() != &FunctionKind::Constructor
            })
            .filter(|&f| {
                if let Some(ASTNode::ContractDefinition(contract)) =
                    f.closest_ancestor_of_type(context, NodeType::ContractDefinition)
                    && contract.kind == ContractKind::Contract
                    && !contract.is_abstract
                {
                    return true;
                }
                false
            })
        {
            if helpers::count_identifiers_that_reference_an_id(context, func.id) == 0 {
                capture!(self, context, func);
            }
        }

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

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

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

    fn description(&self) -> String {
        String::from("Functions that are not used. Consider removing them.")
    }

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

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

#[cfg(test)]
mod dead_code_tests {

    use crate::detect::{detector::IssueDetector, low::dead_code::DeadCodeDetector};

    #[test]

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

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

```

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

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

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

#[derive(Default)]
pub struct ImmediateParentDemonstrator {
    // 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 ImmediateParentDemonstrator {
    fn detect(&mut self, context: &WorkspaceContext) -> Result<bool, Box<dyn Error>> {
        for assignment in context.assignments() {
            println!("0 {}", assignment);
            capture!(self, context, assignment);
            if let Some(first_parent) = assignment.parent(context)
                && let ASTNode::ExpressionStatement(expr_stmnt) = first_parent
            {
                println!("1 {}", expr_stmnt);
                if let Some(second_parent) = first_parent.parent(context)
                    && let ASTNode::Block(for_statement) = second_parent
                {
                    println!("2 {}", for_statement);
                    capture!(self, context, second_parent);
                    if let Some(third_parent) = for_statement.parent(context) {
                        if let ASTNode::ForStatement(block) = third_parent {
                            println!("3 {}", block);
                            capture!(self, context, third_parent);
                        }

                        assert!(first_parent.appears_after(context, second_parent).unwrap());
                        assert!(first_parent.appears_after(context, for_statement).unwrap());
                        assert!(expr_stmnt.appears_after(context, for_statement).unwrap());
                        assert!(second_parent.appears_after(context, third_parent).unwrap());
                        assert!(second_parent.appears_before(context, first_parent).unwrap());
                        assert!(third_parent.appears_before(context, second_parent).unwrap());
                    }
                }
            }
        }

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

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

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

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

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

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

```

--------------------------------------------------------------------------------
/tests/ast/slot_offset.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":[{"canonicalName":"C.S","id":3,"members":[{"constant":false,"id":2,"mutability":"mutable","name":"x","nameLocation":"33:1:1","nodeType":"VariableDeclaration","scope":3,"src":"28:6:1","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"},"typeName":{"id":1,"name":"uint","nodeType":"ElementaryTypeName","src":"28:4:1","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"visibility":"internal"}],"name":"S","nameLocation":"24:1:1","nodeType":"StructDefinition","scope":12,"src":"17:20:1","visibility":"public"},{"constant":false,"id":6,"mutability":"mutable","name":"s","nameLocation":"44:1:1","nodeType":"VariableDeclaration","scope":12,"src":"42:3:1","stateVariable":true,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_struct$_S_$3_storage","typeString":"struct C.S"},"typeName":{"id":5,"nodeType":"UserDefinedTypeName","pathNode":{"id":4,"name":"S","nameLocations":["42:1:1"],"nodeType":"IdentifierPath","referencedDeclaration":3,"src":"42:1:1"},"referencedDeclaration":3,"src":"42:1:1","typeDescriptions":{"typeIdentifier":"t_struct$_S_$3_storage_ptr","typeString":"struct C.S"}},"visibility":"internal"},{"body":{"id":10,"nodeType":"Block","src":"76:70:1","statements":[{"AST":{"nodeType":"YulBlock","src":"95:45:1","statements":[{"nodeType":"YulVariableDeclaration","src":"97:17:1","value":{"name":"s.offset","nodeType":"YulIdentifier","src":"106:8:1"},"variables":[{"name":"x","nodeType":"YulTypedName","src":"101:1:1","type":""}]},{"nodeType":"YulVariableDeclaration","src":"115:23:1","value":{"arguments":[{"name":"s.slot","nodeType":"YulIdentifier","src":"128:6:1"},{"kind":"number","nodeType":"YulLiteral","src":"136:1:1","type":"","value":"2"}],"functionName":{"name":"mul","nodeType":"YulIdentifier","src":"124:3:1"},"nodeType":"YulFunctionCall","src":"124:14:1"},"variables":[{"name":"y","nodeType":"YulTypedName","src":"119:1:1","type":""}]}]},"evmVersion":"london","externalReferences":[{"declaration":6,"isOffset":true,"isSlot":false,"src":"106:8:1","suffix":"offset","valueSize":1},{"declaration":6,"isOffset":false,"isSlot":true,"src":"128:6:1","suffix":"slot","valueSize":1}],"id":9,"nodeType":"InlineAssembly","src":"86:54:1"}]},"functionSelector":"ffae15ba","id":11,"implemented":true,"kind":"function","modifiers":[],"name":"e","nameLocation":"60:1:1","nodeType":"FunctionDefinition","parameters":{"id":7,"nodeType":"ParameterList","parameters":[],"src":"61:2:1"},"returnParameters":{"id":8,"nodeType":"ParameterList","parameters":[],"src":"76:0:1"},"scope":12,"src":"51:95:1","stateMutability":"pure","virtual":false,"visibility":"public"}],"scope":13,"src":"0:148:1","usedErrors":[]}],"src":"0:149:1"}

```

--------------------------------------------------------------------------------
/tests/ast/do_while.json:
--------------------------------------------------------------------------------

```json
{"absolutePath":"script/SomeScript.sol","id":39709,"exportedSymbols":{"Script":[113],"ScriptBase":[74],"SomeScript":[39708],"StdChains":[877],"StdCheatsSafe":[2937],"StdStorage":[4496],"StdStyle":[7346],"StdUtils":[8073],"VmSafe":[9693],"console":[18328],"console2":[26453],"safeconsole":[39691],"stdJson":[4322],"stdMath":[4464],"stdStorageSafe":[5544]},"nodeType":"SourceUnit","src":"0:188:14","nodes":[{"id":39693,"nodeType":"PragmaDirective","src":"0:23:14","nodes":[],"literals":["solidity","0.8",".23"]},{"id":39694,"nodeType":"ImportDirective","src":"25:30:14","nodes":[],"absolutePath":"lib/forge-std/src/Script.sol","file":"forge-std/Script.sol","nameLocation":"-1:-1:-1","scope":39709,"sourceUnit":114,"symbolAliases":[],"unitAlias":""},{"id":39708,"nodeType":"ContractDefinition","src":"57:131:14","nodes":[{"id":39707,"nodeType":"FunctionDefinition","src":"93:93:14","nodes":[],"body":{"id":39706,"nodeType":"Block","src":"115:71:14","nodes":[],"statements":[{"body":{"id":39703,"nodeType":"Block","src":"128:38:14","statements":[{"assignments":[39700],"declarations":[{"constant":false,"id":39700,"mutability":"mutable","name":"a","nameLocation":"150:1:14","nodeType":"VariableDeclaration","scope":39703,"src":"142:9:14","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"},"typeName":{"id":39699,"name":"uint256","nodeType":"ElementaryTypeName","src":"142:7:14","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"visibility":"internal"}],"id":39702,"initialValue":{"hexValue":"31","id":39701,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"154:1:14","typeDescriptions":{"typeIdentifier":"t_rational_1_by_1","typeString":"int_const 1"},"value":"1"},"nodeType":"VariableDeclarationStatement","src":"142:13:14"}]},"condition":{"hexValue":"66616c7365","id":39704,"isConstant":false,"isLValue":false,"isPure":true,"kind":"bool","lValueRequested":false,"nodeType":"Literal","src":"173:5:14","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"},"value":"false"},"id":39705,"nodeType":"DoWhileStatement","src":"125:55:14"}]},"functionSelector":"c0406226","implemented":true,"kind":"function","modifiers":[],"name":"run","nameLocation":"102:3:14","parameters":{"id":39697,"nodeType":"ParameterList","parameters":[],"src":"105:2:14"},"returnParameters":{"id":39698,"nodeType":"ParameterList","parameters":[],"src":"115:0:14"},"scope":39708,"stateMutability":"nonpayable","virtual":false,"visibility":"public"}],"abstract":false,"baseContracts":[{"baseName":{"id":39695,"name":"Script","nameLocations":["80:6:14"],"nodeType":"IdentifierPath","referencedDeclaration":113,"src":"80:6:14"},"id":39696,"nodeType":"InheritanceSpecifier","src":"80:6:14"}],"canonicalName":"SomeScript","contractDependencies":[],"contractKind":"contract","fullyImplemented":true,"linearizedBaseContracts":[39708,113,8073,2937,877,74,62],"name":"SomeScript","nameLocation":"66:10:14","scope":39709,"usedErrors":[],"usedEvents":[]}]}
```

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

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

use crate::ast::{ASTNode, FunctionKind, ModifierInvocationKind, NodeID};

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

#[derive(Default)]
pub struct VoidConstructorDetector {
    // 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 VoidConstructorDetector {
    fn detect(&mut self, context: &WorkspaceContext) -> Result<bool, Box<dyn Error>> {
        // PLAN
        // Gather all the invocations of base constructors
        // For each, inspect the contract and see if there is a constructor defined. If there isn't,
        // capture the invocation

        for modifier_invocation in context.modifier_invocations() {
            if modifier_invocation.kind != Some(ModifierInvocationKind::BaseConstructorSpecifier) {
                continue;
            }
            if let Some(reference_declaration) = match &modifier_invocation.modifier_name {
                crate::ast::IdentifierOrIdentifierPath::Identifier(identifier) => {
                    identifier.referenced_declaration
                }
                crate::ast::IdentifierOrIdentifierPath::IdentifierPath(identifier_path) => {
                    Some(identifier_path.referenced_declaration)
                }
            } && let Some(ASTNode::ContractDefinition(contract)) =
                context.nodes.get(&reference_declaration)
                && contract
                    .function_definitions()
                    .into_iter()
                    .filter(|f| *f.kind() == FunctionKind::Constructor)
                    .count()
                    == 0
            {
                capture!(self, context, modifier_invocation);
            }
        }

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

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

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

    fn description(&self) -> String {
        String::from("Call to a constructor that is not implemented.")
    }

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

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

#[cfg(test)]
mod template_void_constructors {

    use crate::detect::{detector::IssueDetector, low::void_constructor::VoidConstructorDetector};

    #[test]

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

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

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

```

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

```rust
use xshell::{Shell, cmd};

use crate::flags::Reportgen;

fn run_command(args: &str, release: bool) -> anyhow::Result<()> {
    let sh = Shell::new()?;
    sh.change_dir(env!("CARGO_MANIFEST_DIR"));
    sh.change_dir("../../");

    let mut cmd = cmd!(sh, "cargo run");
    if release {
        cmd = cmd.arg("--release");
    }
    cmd = cmd.arg("--").arg("--skip-update-check");
    cmd.args(args.split(" ")).run()?;
    Ok(())
}

fn run_command_with_env(args: &str, key: &str, val: &str, release: bool) -> anyhow::Result<()> {
    let sh = Shell::new()?;
    sh.change_dir(env!("CARGO_MANIFEST_DIR"));
    sh.change_dir("../../");

    let mut cmd = cmd!(sh, "cargo run");
    cmd = cmd.env(key, val);
    if release {
        cmd = cmd.arg("--release");
    }
    cmd = cmd.arg("--").arg("--skip-update-check");
    cmd.args(args.split(" ")).run()?;
    Ok(())
}

pub fn reportgen(choice: Reportgen) -> anyhow::Result<()> {
    if choice.all && choice.parallel {
        let sh = Shell::new()?;
        sh.change_dir(env!("CARGO_MANIFEST_DIR"));
        sh.change_dir("../../");

        let cmd = cmd!(sh, "chmod +x ./cli/reportgen.sh");
        cmd.run()?;
        let cmd = cmd!(sh, "./cli/reportgen.sh");
        cmd.run()?;

        return Ok(())
    }
    if choice.cpg || choice.all {
        run_command(
            "-i src/ -x lib/ ./tests/contract-playground -o ./reports/report.md",
            choice.release,
        )?;
    }
    if choice.adhoc || choice.all {
        run_command(
            "./tests/adhoc-sol-files -o ./reports/adhoc-sol-files-report.md",
            choice.release,
        )?;
    }
    if choice.sablier || choice.all {
        run_command(
            "./tests/2024-05-Sablier -o ./reports/sablier-aderyn-toml-nested-root.md",
            choice.release,
        )?;
    }
    if choice.fnft || choice.all {
        run_command(
            "./tests/foundry-nft-f23 -i src/ -x lib/ -o ./reports/nft-report.md",
            choice.release,
        )?;
    }
    if choice.fnft_icm || choice.all {
        run_command("./tests/foundry-nft-f23-icm -o ./reports/nft-report-icm.md", choice.release)?;
    }

    if choice.ccip || choice.all {
        run_command(
            "tests/ccip-contracts/contracts --src src/v0.8/functions/ -x tests/,test/,mocks/ -o ./reports/ccip-functions-report.md",
            choice.release,
        )?;
    }
    if choice.cpgu || choice.all {
        run_command_with_env(
            "tests/contract-playground/ -o ./reports/uniswap_profile.md",
            "FOUNDRY_PROFILE",
            "uniswap",
            choice.release,
        )?;
    }
    if choice.prb_math || choice.all {
        run_command("tests/prb-math -o reports/prb-math-report.md", choice.release)?;
    }
    if choice.tg || choice.all {
        run_command(
            "tests/2024-07-templegold/protocol -o reports/templegold-report.md",
            choice.release,
        )?;
    }
    if choice.hhpg || choice.all {
        run_command(
            "tests/hardhat-js-playground -o reports/hardhat-playground-report.md",
            choice.release,
        )?;
    }
    Ok(())
}

```

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

```rust
pub mod detector;
pub mod entrypoint;
pub mod helpers;
pub mod high;
pub mod low;

pub mod test_utils;

#[macro_export]
macro_rules! capture {
    ($self:ident, $context:ident, $item:expr_2021) => {
        if let Some(id) = $context.get_node_id_of_capturable(&$item.clone().into()) {
            $self
                .found_instances
                .insert($context.get_node_sort_key_from_capturable(&$item.clone().into()), id);
        } else {
            $self
                .found_instances
                .insert($context.get_node_sort_key_from_capturable(&$item.clone().into()), 0);
        }
    };
    ($self:ident, $context:ident, $item:expr_2021, $hint:tt) => {
        $self
            .hints
            .insert($context.get_node_sort_key_from_capturable(&$item.clone().into()), $hint);
        capture!($self, $context, $item);
    };
}

#[macro_export]
macro_rules! issue_detector {
    (
        $detector_struct:ident;

        severity: $detector_severity:ident,
        title: $detector_title:tt,
        desc: $detector_desc:tt,
        name: $detector_name:ident,

        |$context: ident| $e:expr_2021
    ) => {

        #[derive(Default)]
        pub struct $detector_struct {
            found_instances: std::collections::BTreeMap<(String, usize, String), $crate::ast::NodeID>,
        }

        impl $crate::detect::detector::IssueDetector for $detector_struct {

            fn detect(&mut self, context: &$crate::context::workspace::WorkspaceContext) -> Result<bool, Box<dyn std::error::Error>> {

                let $context = context;

                macro_rules! grab {
                    ($item:expr_2021) => {
                        if let Some(id) = context.get_node_id_of_capturable(&$item.clone().into()) {
                            self.found_instances.insert(
                                $context.get_node_sort_key_from_capturable(&$item.clone().into()),
                                id,
                            );
                        } else {
                            self.found_instances.insert(
                                $context.get_node_sort_key_from_capturable(&$item.clone().into()),
                                0,
                            );
                        }
                    };
                }

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

            fn severity(&self) -> $crate::detect::detector::IssueSeverity {
                $crate::detect::detector::IssueSeverity::$detector_severity
            }

            fn title(&self) -> String {
                String::from($detector_title)
            }

            fn description(&self) -> String {
                String::from($detector_desc)
            }

            fn instances(&self) -> std::collections::BTreeMap<(String, usize, String), $crate::ast::NodeID> {
                self.found_instances.clone()
            }

            fn name(&self) -> String {
                $crate::detect::detector::IssueDetectorNamePool::$detector_name.to_string()
            }
        }

    };
}

pub use capture;

pub use issue_detector;

```

--------------------------------------------------------------------------------
/aderyn_core/src/detect/low/centralization_risk.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 CentralizationRiskDetector {
    // 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 CentralizationRiskDetector {
    fn detect(&mut self, context: &WorkspaceContext) -> Result<bool, Box<dyn Error>> {
        for contract_definition in context.contract_definitions().iter() {
            for bc in contract_definition.base_contracts.iter() {
                if let Some(base_name) = bc.base_name.name()
                    && matches!(
                        base_name.as_str(),
                        "Owned"
                            | "Ownable"
                            | "Ownable2Step"
                            | "AccessControl"
                            | "AccessControlCrossChain"
                            | "AccessControlEnumerable"
                            | "Auth"
                            | "RolesAuthority"
                            | "MultiRolesAuthority"
                    )
                {
                    capture!(self, context, bc);
                }
            }
        }

        for modifier_invocation in context.modifier_invocations().iter().filter(|&&mi| {
            mi.modifier_name.name() == "onlyOwner"
                || mi.modifier_name.name() == "requiresAuth"
                || mi.modifier_name.name().contains("onlyRole")
        }) {
            capture!(self, context, modifier_invocation);
        }

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

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

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

    fn description(&self) -> String {
        String::from(
            "Contracts have owners with privileged rights to perform admin tasks and need to be trusted to not perform malicious updates or drain funds.",
        )
    }

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

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

#[cfg(test)]
mod centralization_risk_detector_tests {

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

    use super::CentralizationRiskDetector;

    #[test]

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

        let mut detector = CentralizationRiskDetector::default();
        let found = detector.detect(&context).unwrap();
        assert!(found);
        // assert that the number of instances found is 3
        assert_eq!(detector.instances().len(), 3);
    }
}

```

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

```rust
use super::render;
use crate::context::{
    macros::mcp_success,
    mcp::{
        MCPToolNamePool, ModelContextProtocolState, ModelContextProtocolTool,
        project_overview::render::*,
    },
};
use indoc::indoc;
use rmcp::{ErrorData as McpError, handler::server::wrapper::Parameters, model::CallToolResult};
use std::{path::PathBuf, str::FromStr, sync::Arc};

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

impl ModelContextProtocolTool for ProjectOverviewTool {
    type Input = rmcp::model::EmptyObject;

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

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

    fn description(&self) -> String {
        indoc! {
            "It returns project configuration such as the root directory, source directory \
            (where the contracts are kept), 3rd party libraries, remappings, list of source \
            files, user preference for included and excluded files, etc."
        }
        .to_string()
    }

    fn execute(&self, _input: Parameters<Self::Input>) -> Result<CallToolResult, McpError> {
        // remappings
        let mut remapping_strings = vec![];
        for r in self.state.project_config.project_paths.remappings.iter() {
            remapping_strings.push(r.to_string());
        }
        // compilation units
        let mut compilation_units = vec![];
        for context in self.state.contexts.iter() {
            let mut file_entries = vec![];
            let mut included_count = 0;
            for file in context.src_filepaths.iter() {
                let file_entry;
                if context.included.contains(&PathBuf::from_str(file).unwrap()) {
                    file_entry = FileEntryBuilder::default()
                        .path(file.clone())
                        .included(true)
                        .build()
                        .expect("failed to build file entry");
                    included_count += 1;
                } else {
                    file_entry = FileEntryBuilder::default()
                        .path(file.clone())
                        .included(false)
                        .build()
                        .expect("failed to build file entry");
                }
                file_entries.push(file_entry);
            }
            let compilation_unit = CompilationUnitBuilder::default()
                .files(file_entries)
                .included_count(included_count)
                .build()
                .expect("failed to build compilation unit");

            compilation_units.push(compilation_unit);
        }

        let project_overview = render::ProjectOverviewBuilder::default()
            .root(self.state.root_path.to_string_lossy().to_string())
            .source(self.state.project_config.project_paths.sources.to_string_lossy().to_string())
            .remappings(remapping_strings)
            .compilation_units(compilation_units)
            .build()
            .expect("failed to build project overview");

        mcp_success!(project_overview)
    }
}

```

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

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

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

#[derive(Default)]
pub struct AncestralLineDemonstrator {
    // 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 AncestralLineDemonstrator {
    fn detect(&mut self, context: &WorkspaceContext) -> Result<bool, Box<dyn Error>> {
        for assignment in context.assignments() {
            capture!(self, context, assignment);

            if let Some(parent_chain) = assignment.ancestral_line(context) {
                if let ASTNode::ExpressionStatement(_) = parent_chain[1] {
                    capture!(self, context, parent_chain[1]);
                    //  NOTE: Above capture is redundant because assignment also shares the same
                    // location  (size and offset) with the expression statement. Therefore the
                    // number of found_instances doesn't increase here
                }
                if let ASTNode::Block(_) = parent_chain[2] {
                    capture!(self, context, parent_chain[2]);
                }
                if let ASTNode::ForStatement(_) = parent_chain[3] {
                    capture!(self, context, parent_chain[3]);
                }
                if let ASTNode::Block(block) = parent_chain[4] {
                    capture!(self, context, block);
                }
            }

            if let Some(mut parent_chain) = assignment.ancestral_line(context) {
                let _sorted_chain = parent_chain.sort_by_src_position(context).unwrap();

                //println!("Sorted Chain");
                //for i in &sorted_chain[..sorted_chain.len() - 2] {
                //    print!("{:?}, ", i.node_type());
                //}
                parent_chain.reverse();

                //println!("Reverse parent chain");
                //for i in &parent_chain[..parent_chain.len() - 2] {
                //    print!("{:?}, ", i.node_type());
                //}
                // assert_eq!(sorted_chain, parent_chain);
            }
        }

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

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

    fn title(&self) -> String {
        String::from("Parent Chain Demonstration")
    }

    fn description(&self) -> String {
        String::from("Parent Chain Demonstration")
    }

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

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

```

--------------------------------------------------------------------------------
/aderyn_core/src/detect/low/solmate_safe_transfer_lib.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 SolmateSafeTransferLibDetector {
    // 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 SolmateSafeTransferLibDetector {
    fn detect(&mut self, context: &WorkspaceContext) -> Result<bool, Box<dyn Error>> {
        for import_directive in context.import_directives() {
            // If the import directive absolute_path contains the strings "solmate" and
            // "SafeTransferLib", flip the found_solmate_import flag to true
            if import_directive.absolute_path.as_ref().unwrap().contains("solmate")
                && import_directive.absolute_path.as_ref().unwrap().contains("SafeTransferLib")
            {
                capture!(self, context, import_directive);
            }
        }

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

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

    fn title(&self) -> String {
        String::from("Solmate\'s SafeTransferLib")
    }

    fn description(&self) -> String {
        String::from(
            "There is a subtle difference between the implementation of solmate's SafeTransferLib and OZ's SafeERC20: OZ's SafeERC20 checks if the token is a contract or not, solmate's SafeTransferLib does not.\nhttps://github.com/transmissions11/solmate/blob/main/src/utils/SafeTransferLib.sol#L9 \n`@dev Note that none of the functions in this library check that a token has code at all! That responsibility is delegated to the caller`\n",
        )
    }

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

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

#[cfg(test)]
mod solmate_safe_transfer_lib_tests {

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

    #[test]

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

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

    #[test]

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

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

```

--------------------------------------------------------------------------------
/tests/ast/two_base_functions.json:
--------------------------------------------------------------------------------

```json
{"absolutePath":"a","exportedSymbols":{"A":[5],"B":[10],"C":[22]},"id":23,"nodeType":"SourceUnit","nodes":[{"abstract":false,"baseContracts":[],"canonicalName":"A","contractDependencies":[],"contractKind":"contract","fullyImplemented":true,"id":5,"linearizedBaseContracts":[5],"name":"A","nameLocation":"9:1:1","nodeType":"ContractDefinition","nodes":[{"body":{"id":3,"nodeType":"Block","src":"45:2:1","statements":[]},"functionSelector":"26121ff0","id":4,"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":"45:0:1"},"scope":5,"src":"17:30:1","stateMutability":"nonpayable","virtual":true,"visibility":"public"}],"scope":23,"src":"0:49:1","usedErrors":[]},{"abstract":false,"baseContracts":[],"canonicalName":"B","contractDependencies":[],"contractKind":"contract","fullyImplemented":true,"id":10,"linearizedBaseContracts":[10],"name":"B","nameLocation":"59:1:1","nodeType":"ContractDefinition","nodes":[{"body":{"id":8,"nodeType":"Block","src":"95:2:1","statements":[]},"functionSelector":"26121ff0","id":9,"implemented":true,"kind":"function","modifiers":[],"name":"f","nameLocation":"76:1:1","nodeType":"FunctionDefinition","parameters":{"id":6,"nodeType":"ParameterList","parameters":[],"src":"77:2:1"},"returnParameters":{"id":7,"nodeType":"ParameterList","parameters":[],"src":"95:0:1"},"scope":10,"src":"67:30:1","stateMutability":"nonpayable","virtual":true,"visibility":"public"}],"scope":23,"src":"50:49:1","usedErrors":[]},{"abstract":false,"baseContracts":[{"baseName":{"id":11,"name":"A","nameLocations":["114:1:1"],"nodeType":"IdentifierPath","referencedDeclaration":5,"src":"114:1:1"},"id":12,"nodeType":"InheritanceSpecifier","src":"114:1:1"},{"baseName":{"id":13,"name":"B","nameLocations":["117:1:1"],"nodeType":"IdentifierPath","referencedDeclaration":10,"src":"117:1:1"},"id":14,"nodeType":"InheritanceSpecifier","src":"117:1:1"}],"canonicalName":"C","contractDependencies":[],"contractKind":"contract","fullyImplemented":true,"id":22,"linearizedBaseContracts":[22,10,5],"name":"C","nameLocation":"109:1:1","nodeType":"ContractDefinition","nodes":[{"baseFunctions":[4,9],"body":{"id":20,"nodeType":"Block","src":"160:2:1","statements":[]},"functionSelector":"26121ff0","id":21,"implemented":true,"kind":"function","modifiers":[],"name":"f","nameLocation":"134:1:1","nodeType":"FunctionDefinition","overrides":{"id":18,"nodeType":"OverrideSpecifier","overrides":[{"id":16,"name":"A","nameLocations":["154:1:1"],"nodeType":"IdentifierPath","referencedDeclaration":5,"src":"154:1:1"},{"id":17,"name":"B","nameLocations":["157:1:1"],"nodeType":"IdentifierPath","referencedDeclaration":10,"src":"157:1:1"}],"src":"145:14:1"},"parameters":{"id":15,"nodeType":"ParameterList","parameters":[],"src":"135:2:1"},"returnParameters":{"id":19,"nodeType":"ParameterList","parameters":[],"src":"160:0:1"},"scope":22,"src":"125:37:1","stateMutability":"nonpayable","virtual":false,"visibility":"public"}],"scope":23,"src":"100:64:1","usedErrors":[]}],"src":"0:165:1"}

```

--------------------------------------------------------------------------------
/aderyn_core/src/stats/cloc.rs:
--------------------------------------------------------------------------------

```rust
use super::token::*;

pub fn count_code_lines(token_descriptors: &[TokenDescriptor]) -> usize {
    let mut code_lines = 0;

    let insights =
        token_descriptors.iter().map(|tok_dsc| tok_dsc.into()).collect::<Vec<TokenInsight>>();

    let mut token_insight_groups = vec![];

    for insight in &insights {
        if token_insight_groups.is_empty() {
            let new_token_insight_group = TokenInsightGroup {
                token_insights: vec![insight.clone()],
                start_line: insight.start_line,
                end_line: insight.end_line,
                token_type: insight.token_type.clone().into(),
            };
            token_insight_groups.push(new_token_insight_group);
            continue;
        }
        let prev_group = token_insight_groups.last_mut().unwrap();

        if insight.start_line == prev_group.end_line
            && insight.code_lines.actual_first_line == 0
            && prev_group.last_token_insight_has_code_in_its_last_line()
            && prev_group.token_type == insight.token_type.clone().into()
        {
            prev_group.token_insights.push(insight.clone());
            prev_group.end_line = insight.end_line;
        } else {
            let new_token_insight_group = TokenInsightGroup {
                token_insights: vec![insight.clone()],
                start_line: insight.start_line,
                end_line: insight.end_line,
                token_type: insight.token_type.clone().into(),
            };
            token_insight_groups.push(new_token_insight_group);
        }
    }

    let groups = token_insight_groups
        .iter()
        .filter(|g| g.token_type == HighLevelType::Code)
        .collect::<Vec<_>>();

    if groups.is_empty() {
        return 0;
    }

    let len = groups.len();
    let mut prev = &groups[0];

    code_lines += prev.total_contribution();

    #[allow(clippy::needless_range_loop)]
    for i in 1..len {
        let curr = &groups[i];
        let grp_contrib = curr.total_contribution();
        code_lines += grp_contrib;

        // what line does the first contributing token start ?
        if curr.start_line == prev.end_line
            && (curr.token_insights[0].code_lines.actual_first_line == 0)
            && grp_contrib >= 1
            && prev.last_token_insight_has_code_in_its_last_line()
        {
            // println!("deducting {} {}", curr.start_line, prev.end_line);
            code_lines -= 1;
        }
        prev = curr;
    }

    code_lines
}

#[cfg(test)]
mod cloc_tests {
    use crate::stats::token::tokenize;

    use super::*;

    #[test]
    fn test_print_cloc_heavily_commented_contract() {
        let content = tokenize(include_str!(
            "../../../tests/contract-playground/src/cloc/HeavilyCommentedContract.sol"
        ));
        let stats = count_code_lines(&content);
        assert_eq!(stats, 21);
    }

    #[test]
    fn test_print_cloc_another_heavily_commented_contract() {
        let content = tokenize(include_str!(
            "../../../tests/contract-playground/src/cloc/AnotherHeavilyCommentedContract.sol"
        ));
        let stats = count_code_lines(&content);
        assert_eq!(stats, 32);
    }
}

```

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

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

impl Node for ParameterList {
    fn accept(&self, visitor: &mut impl ASTConstVisitor) -> Result<()> {
        if visitor.visit_parameter_list(self)? {
            list_accept(&self.parameters, visitor)?;
        }
        self.accept_metadata(visitor)?;
        visitor.end_visit_parameter_list(self)
    }
    fn accept_metadata(&self, visitor: &mut impl ASTConstVisitor) -> Result<()> {
        let parameters_ids = &self.parameters.iter().map(|x| x.id).collect::<Vec<_>>();
        visitor.visit_immediate_children(self.id, parameters_ids.clone())?;
        Ok(())
    }
    macros::accept_id!();
}

impl Node for OverrideSpecifier {
    fn accept(&self, visitor: &mut impl ASTConstVisitor) -> Result<()> {
        if visitor.visit_override_specifier(self)? {
            for overrider in &self.overrides {
                match overrider {
                    UserDefinedTypeNameOrIdentifierPath::UserDefinedTypeName(type_name) => {
                        type_name.accept(visitor)?
                    }
                    UserDefinedTypeNameOrIdentifierPath::IdentifierPath(identifier_path) => {
                        identifier_path.accept(visitor)?
                    }
                }
            }
        }
        self.accept_metadata(visitor)?;
        visitor.end_visit_override_specifier(self)
    }
    fn accept_metadata(&self, visitor: &mut impl ASTConstVisitor) -> Result<()> {
        let overrides_ids =
            &self.overrides.iter().filter_map(|x| x.get_node_id()).collect::<Vec<_>>();
        visitor.visit_immediate_children(self.id, overrides_ids.clone())?;
        Ok(())
    }
    macros::accept_id!();
}

impl Node for FunctionDefinition {
    fn accept(&self, visitor: &mut impl ASTConstVisitor) -> Result<()> {
        if visitor.visit_function_definition(self)? {
            if self.documentation.is_some() {
                self.documentation.as_ref().unwrap().accept(visitor)?;
            }
            if self.overrides.is_some() {
                self.overrides.as_ref().unwrap().accept(visitor)?;
            }
            self.parameters.accept(visitor)?;
            self.return_parameters.accept(visitor)?;
            list_accept(&self.modifiers, visitor)?;
            if self.body.is_some() {
                self.body.as_ref().unwrap().accept(visitor)?;
            }
        }
        self.accept_metadata(visitor)?;
        visitor.end_visit_function_definition(self)
    }
    fn accept_metadata(&self, visitor: &mut impl ASTConstVisitor) -> Result<()> {
        // TODO: documentation
        if let Some(overrides) = &self.overrides {
            visitor.visit_immediate_children(self.id, vec![overrides.id])?;
        }
        visitor.visit_immediate_children(self.id, vec![self.parameters.id])?;
        visitor.visit_immediate_children(self.id, vec![self.return_parameters.id])?;
        let modifiers_ids = &self.modifiers.iter().map(|x| x.id).collect::<Vec<_>>();
        visitor.visit_immediate_children(self.id, modifiers_ids.clone())?;
        if let Some(body) = &self.body {
            visitor.visit_immediate_children(self.id, vec![body.id])?;
        }
        Ok(())
    }
    macros::accept_id!();
}

```

--------------------------------------------------------------------------------
/aderyn_driver/src/display.rs:
--------------------------------------------------------------------------------

```rust
use std::{
    collections::{BTreeMap, HashSet},
    path::PathBuf,
};

use solidity_ast::{AstSourceFile, ProjectConfigInput};

pub fn display_header(project_config: &ProjectConfigInput, header: &str) {
    let say_header = |message: &str| {
        let say = |message: &str| {
            println!("{}", message);
        };
        let longest_str_len = project_config.project_paths.sources.display().to_string().len();
        say(&format!("---------{}", &"-".repeat(longest_str_len)));
        say(&format!("# {}", message));
        say(&format!("---------{}", &"-".repeat(longest_str_len)));
    };
    say_header(header);
}

pub fn display_ingesting_message(
    sources_ast: &BTreeMap<PathBuf, AstSourceFile>,
    included: &HashSet<PathBuf>,
    solc_version: &str,
) {
    let ingestion_keys = sources_ast.keys().filter(|&key| included.contains(key)).count();

    if ingestion_keys > 0 {
        println!("Ingesting {} compiled files [solc : v{}]", ingestion_keys, solc_version);
    } else {
        eprintln!("No files found for context [solc : v{}]", solc_version);
    }
}

pub fn display_configuration_info(project_config: &ProjectConfigInput) {
    let say = |message: &str| {
        println!("{}", message);
    };

    let say_header = |message: &str| {
        let longest_str_len = project_config.project_paths.sources.display().to_string().len();
        say(&format!("---------{}", &"-".repeat(longest_str_len)));
        say(&format!("# {}", message));
        say(&format!("---------{}", &"-".repeat(longest_str_len)));
    };

    say("");
    say_header("Configuration");
    say(&format!("Root - {}", project_config.project_paths.root.display()));
    say(&format!("Source - {}", project_config.project_paths.sources.display()));
    say(&format!(
        "Remappings - {:#?}",
        project_config
            .project_paths
            .remappings
            .iter()
            .map(|r| {
                let mut rel = r.clone();
                rel.strip_prefix(&project_config.project_paths.root);
                rel.to_string()
            })
            .collect::<Vec<_>>()
    ));
    say(&format!("EVM version - {}", project_config.evm_version));

    say_header("Source Scope");
    if project_config.include_containing.clone() != vec!["".to_string()] {
        say(&format!("Include Filepaths Containing - {:#?}", project_config.include_containing));
    } else {
        say("Include Filepaths Containing - No specific criteria.");
    }
    if !project_config.exclude_containing.is_empty() {
        say(&format!("Exclude Filepaths Containing - {:#?}", project_config.exclude_containing));
    } else {
        say("Exclude Filepaths Containing - No specific criteria.");
    }

    if !project_config.exclude_starting.is_empty() {
        say(&format!(
            "Auto Excluding Files - {:#?}",
            project_config
                .exclude_starting
                .iter()
                .map(|r| {
                    r.strip_prefix(&project_config.project_paths.sources)
                        .unwrap_or(r)
                        .to_string_lossy()
                        .to_string()
                })
                .collect::<Vec<_>>()
        ));
    } else {
        say("Auto Excluding - No Files.");
    }
}

```

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

```rust
//! This module helps us detect whether a given AST Node has any external calls inside of it

use super::ExtractMemberAccesses;
use crate::context::workspace::ASTNode;

pub fn is_extcallish(ast_node: ASTNode) -> bool {
    // This is so we can skip the FunctionCallOptions layer which solidity compiler inserts
    // when there are options passed to function calls
    for member_access in ExtractMemberAccesses::from(&ast_node).extracted {
        // address(..).call("...") pattern
        let is_call = member_access.member_name == "call";
        if is_call {
            return true;
        }

        // payable(address(..)).transfer(100)
        // payable(address(..)).send(100)
        // address.sendValue(..) (from openzeppelin)
        if (member_access.member_name == "transfer"
            || member_access.member_name == "send"
            || member_access.member_name == "sendValue")
            && let Some(type_description) = member_access.expression.type_descriptions()
            && type_description
                .type_string
                .as_ref()
                .is_some_and(|type_string| type_string.starts_with("address"))
        {
            return true;
        }

        // Any external call
        if member_access
            .type_descriptions
            .type_identifier
            .is_some_and(|type_identifier| type_identifier.contains("function_external"))
        {
            return true;
        }
    }

    false
}

#[cfg(test)]
mod external_calls_detector {

    use crate::{
        ast::*, context::browser::ExtractFunctionCalls,
        detect::test_utils::load_solidity_source_unit,
    };

    impl FunctionDefinition {
        pub fn makes_external_calls(&self) -> bool {
            let func_calls = ExtractFunctionCalls::from(self).extracted;
            func_calls.iter().any(|f| f.is_extcallish())
        }
    }

    #[test]

    fn test_direct_call_on_address() {
        let context =
            load_solidity_source_unit("../tests/contract-playground/src/ExternalCalls.sol");

        let childex = context.find_contract_by_name("ChildEx");

        let ext1 = childex.find_function_by_name("ext1");
        let ext2 = childex.find_function_by_name("ext2");
        let ext3 = childex.find_function_by_name("ext3");
        let ext4 = childex.find_function_by_name("ext4");
        let ext5 = childex.find_function_by_name("ext5");
        let ext6 = childex.find_function_by_name("ext6");
        let ext7 = childex.find_function_by_name("ext7");
        let ext8 = childex.find_function_by_name("ext8");
        let ext9 = childex.find_function_by_name("ext9");

        assert!(ext1.makes_external_calls());
        assert!(ext2.makes_external_calls());
        assert!(ext3.makes_external_calls());
        assert!(ext4.makes_external_calls());
        assert!(ext5.makes_external_calls());
        assert!(ext6.makes_external_calls());
        assert!(ext7.makes_external_calls());
        assert!(ext8.makes_external_calls());
        assert!(ext9.makes_external_calls());

        let notext1 = childex.find_function_by_name("notExt1");
        let notext2 = childex.find_function_by_name("notExt2");

        assert!(!notext1.makes_external_calls());
        assert!(!notext2.makes_external_calls());
    }
}

```

--------------------------------------------------------------------------------
/tests/ast/non_utf8.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":[{"body":{"id":13,"nodeType":"Block","src":"33:45:1","statements":[{"assignments":[4],"declarations":[{"constant":false,"id":4,"mutability":"mutable","name":"x","nameLocation":"49:1:1","nodeType":"VariableDeclaration","scope":13,"src":"35:15:1","stateVariable":false,"storageLocation":"memory","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string"},"typeName":{"id":3,"name":"string","nodeType":"ElementaryTypeName","src":"35:6:1","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"}],"id":12,"initialValue":{"arguments":[{"arguments":[{"hexValue":"ff","id":9,"isConstant":false,"isLValue":false,"isPure":true,"kind":"hexString","lValueRequested":false,"nodeType":"Literal","src":"66:7:1","typeDescriptions":{"typeIdentifier":"t_stringliteral_8b1a944cf13a9a1c08facb2c9e98623ef3254d2ddb48113885c3e8e97fec8db9","typeString":"literal_string hex\"ff\""}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_8b1a944cf13a9a1c08facb2c9e98623ef3254d2ddb48113885c3e8e97fec8db9","typeString":"literal_string hex\"ff\""}],"id":8,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"60:5:1","typeDescriptions":{"typeIdentifier":"t_type$_t_bytes_storage_ptr_$","typeString":"type(bytes storage pointer)"},"typeName":{"id":7,"name":"bytes","nodeType":"ElementaryTypeName","src":"60:5:1","typeDescriptions":{}}},"id":10,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"nameLocations":[],"names":[],"nodeType":"FunctionCall","src":"60:14:1","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes memory"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes memory"}],"id":6,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"53:6:1","typeDescriptions":{"typeIdentifier":"t_type$_t_string_storage_ptr_$","typeString":"type(string storage pointer)"},"typeName":{"id":5,"name":"string","nodeType":"ElementaryTypeName","src":"53:6:1","typeDescriptions":{}}},"id":11,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"nameLocations":[],"names":[],"nodeType":"FunctionCall","src":"53:22:1","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"}},"nodeType":"VariableDeclarationStatement","src":"35:40:1"}]},"functionSelector":"26121ff0","id":14,"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":15,"src":"13:65:1","stateMutability":"nonpayable","virtual":false,"visibility":"public"}],"scope":16,"src":"0:80:1","usedErrors":[]}],"src":"0:81:1"}

```

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

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

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

#[derive(Default)]
pub struct UnspecificSolidityPragmaDetector {
    // 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 UnspecificSolidityPragmaDetector {
    fn detect(&mut self, context: &WorkspaceContext) -> Result<bool, Box<dyn Error>> {
        for pragma_directive in context.pragma_directives() {
            let Some(source_unit) =
                pragma_directive.closest_ancestor_of_type(context, NodeType::SourceUnit)
            else {
                continue;
            };
            let contracts_in_source_unit = ExtractContractDefinitions::from(source_unit).extracted;
            if contracts_in_source_unit.iter().any(|c| c.kind == ContractKind::Library) {
                continue;
            }
            for literal in &pragma_directive.literals {
                if literal.contains('^') || literal.contains('>') || literal.contains('<') {
                    capture!(self, context, pragma_directive);
                    break;
                }
            }
        }
        Ok(!self.found_instances.is_empty())
    }

    fn title(&self) -> String {
        String::from("Unspecific Solidity Pragma")
    }

    fn description(&self) -> String {
        String::from(
            "Consider using a specific version of Solidity in your contracts instead of a wide version. For example, instead of `pragma solidity ^0.8.0;`, use `pragma solidity 0.8.0;`",
        )
    }

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

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

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

#[cfg(test)]
mod unspecific_solidity_pragma_tests {
    use crate::detect::{
        detector::IssueDetector, low::unspecific_solidity_pragma::UnspecificSolidityPragmaDetector,
    };

    #[test]

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

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

    #[test]

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

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

```

--------------------------------------------------------------------------------
/tests/ast/function_type.json:
--------------------------------------------------------------------------------

```json
{"absolutePath":"a","exportedSymbols":{"C":[17]},"id":18,"nodeType":"SourceUnit","nodes":[{"abstract":false,"baseContracts":[],"canonicalName":"C","contractDependencies":[],"contractKind":"contract","fullyImplemented":true,"id":17,"linearizedBaseContracts":[17],"name":"C","nameLocation":"9:1:1","nodeType":"ContractDefinition","nodes":[{"body":{"id":15,"nodeType":"Block","src":"127:2:1","statements":[]},"functionSelector":"d6cd4974","id":16,"implemented":true,"kind":"function","modifiers":[],"name":"f","nameLocation":"22:1:1","nodeType":"FunctionDefinition","parameters":{"id":7,"nodeType":"ParameterList","parameters":[{"constant":false,"id":6,"mutability":"mutable","name":"x","nameLocation":"67:1:1","nodeType":"VariableDeclaration","scope":16,"src":"24:44:1","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_function_external_payable$__$returns$_t_uint256_$","typeString":"function () payable external returns (uint256)"},"typeName":{"id":5,"nodeType":"FunctionTypeName","parameterTypes":{"id":1,"nodeType":"ParameterList","parameters":[],"src":"32:2:1"},"returnParameterTypes":{"id":4,"nodeType":"ParameterList","parameters":[{"constant":false,"id":3,"mutability":"mutable","name":"","nameLocation":"-1:-1:-1","nodeType":"VariableDeclaration","scope":5,"src":"61:4:1","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"},"typeName":{"id":2,"name":"uint","nodeType":"ElementaryTypeName","src":"61:4:1","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"visibility":"internal"}],"src":"60:6:1"},"src":"24:44:1","stateMutability":"payable","typeDescriptions":{"typeIdentifier":"t_function_external_payable$__$returns$_t_uint256_$","typeString":"function () payable external returns (uint256)"},"visibility":"external"},"visibility":"internal"}],"src":"23:46:1"},"returnParameters":{"id":14,"nodeType":"ParameterList","parameters":[{"constant":false,"id":13,"mutability":"mutable","name":"","nameLocation":"-1:-1:-1","nodeType":"VariableDeclaration","scope":16,"src":"86:40:1","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_function_external_view$__$returns$_t_uint256_$","typeString":"function () view external returns (uint256)"},"typeName":{"id":12,"nodeType":"FunctionTypeName","parameterTypes":{"id":8,"nodeType":"ParameterList","parameters":[],"src":"94:2:1"},"returnParameterTypes":{"id":11,"nodeType":"ParameterList","parameters":[{"constant":false,"id":10,"mutability":"mutable","name":"","nameLocation":"-1:-1:-1","nodeType":"VariableDeclaration","scope":12,"src":"120:4:1","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"},"typeName":{"id":9,"name":"uint","nodeType":"ElementaryTypeName","src":"120:4:1","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"visibility":"internal"}],"src":"119:6:1"},"src":"86:40:1","stateMutability":"view","typeDescriptions":{"typeIdentifier":"t_function_external_view$__$returns$_t_uint256_$","typeString":"function () view external returns (uint256)"},"visibility":"external"},"visibility":"internal"}],"src":"85:41:1"},"scope":17,"src":"13:116:1","stateMutability":"nonpayable","virtual":false,"visibility":"public"}],"scope":18,"src":"0:131:1","usedErrors":[]}],"src":"0:132:1"}

```

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

```rust
use crate::{
    ast::NodeID,
    context::{
        macros::{mcp_error, mcp_success},
        mcp::{
            MCPToolNamePool, ModelContextProtocolState, ModelContextProtocolTool,
            node_summarizer::{render, utils::*},
        },
    },
};
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 NodeSummarizerTool {
    state: Arc<ModelContextProtocolState>,
}

#[derive(Deserialize, schemars::JsonSchema)]
pub struct NodeSummarizerPayload {
    /// 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,
    /// The Node ID for which you want to see the code snippet and some basic summary about it,
    /// such as parent contract ID, etc.
    pub node_id: NodeID,
}

impl ModelContextProtocolTool for NodeSummarizerTool {
    type Input = NodeSummarizerPayload;

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

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

    fn description(&self) -> String {
        indoc! {
            "Given a compilation unit index and a Node ID, returns a focused summary of that exact AST node\
            (e.g. function, modifier, event, variable, struct) and the source code snippet. Also in metadata show \
            the callgraphs that collide with the node if it is a function."
        }
        .to_string()
    }

    fn execute(&self, input: Parameters<Self::Input>) -> Result<CallToolResult, McpError> {
        let payload = input.0;

        if payload.compilation_unit_index < 1
            || payload.compilation_unit_index > self.state.contexts.len()
        {
            return mcp_error!(
                "Invalid compilation unit index: {}. Must be in range [1, {}]",
                payload.compilation_unit_index,
                self.state.contexts.len()
            );
        }

        let context = self
            .state
            .contexts
            .get(payload.compilation_unit_index - 1)
            .expect("Compilation unit index bounds check failed");

        let Some(node) = context.nodes.get(&payload.node_id) else {
            return mcp_error!(
                "Node with ID {} not found in compilation unit index {}",
                payload.node_id,
                payload.compilation_unit_index
            );
        };

        let (filepath, _, _) = context.get_node_sort_key_pure(node);
        let code_snippet = context.get_code_snippet(node);

        let summary = render::NodeSummaryBuilder::default()
            .compilation_unit_index(payload.compilation_unit_index)
            .node_id(payload.node_id)
            .filepath(filepath)
            .code(code_snippet)
            .containing_contract(get_containing_contract(context, node))
            .containing_function(get_containing_function(context, node))
            .containing_modifier(get_containing_modifier(context, node))
            .containing_callgraphs(get_containing_callgraphs(context, node))
            .build()
            .expect("failed to build node summary");

        mcp_success!(summary)
    }
}

```

--------------------------------------------------------------------------------
/aderyn_driver/tests/astgen.rs:
--------------------------------------------------------------------------------

```rust
#[cfg(test)]
mod project_compiler_grouping_tests {
    use std::{env::set_var, path::PathBuf, str::FromStr};

    use aderyn_driver::{compile, process::PreprocessedConfig};

    // Tester function
    fn test_grouping_files_to_compile(
        project_root_str: &str,
        src: &Option<PathBuf>,
        include: &Option<Vec<String>>,
        exclude: &Option<Vec<String>>,
    ) {
        let root_path = PathBuf::from_str(project_root_str).unwrap();
        let source = if src.is_some() {
            Some(src.clone().unwrap().to_string_lossy().to_string())
        } else {
            None
        };

        let preprocessed_config = PreprocessedConfig {
            root_path,
            src: source,
            include: include.clone(),
            exclude: exclude.clone(),
        };
        let (contexts, _) = compile::compile_project(preprocessed_config, false, true).unwrap();

        assert!(!contexts.is_empty());
        contexts.iter().for_each(|c| {
            assert!(!c.source_units().is_empty());
        });
    }

    #[test]
    fn foundry_nft_f23_only() {
        let project_root_str = "../tests/foundry-nft-f23";
        let src = &Some(PathBuf::from_str("src/").unwrap());
        test_grouping_files_to_compile(project_root_str, src, &None, &None);
    }

    #[test]
    fn foundry_nft_f23_icm() {
        let project_root_str = "../tests/foundry-nft-f23-icm";
        unsafe { set_var("FOUNDRY_PROFILE", "icm") };
        test_grouping_files_to_compile(project_root_str, &None, &None, &None);
    }

    #[test]
    fn adhoc_solidity_files() {
        let project_root_str = "../tests/adhoc-sol-files";
        test_grouping_files_to_compile(project_root_str, &None, &None, &None);
    }

    #[test]
    fn contract_playground() {
        let project_root_str = "../tests/contract-playground";
        let src = &Some(PathBuf::from_str("src/").unwrap());
        test_grouping_files_to_compile(project_root_str, src, &None, &None);
    }

    // INFO: This CCIP unit test takes too much time to run. Since we already have
    // an integration test, let's not have this.
    //
    //#[test]
    //fn ccip_develop() {
    //    let project_root_str = "../tests/ccip-contracts/contracts";
    //    set_var("FOUNDRY_PROFILE", "vrfv2plus_coordinator");
    //    test_grouping_files_to_compile(project_root_str, &None, &None, &None);
    //}

    #[test]
    fn test_no_files_found_in_scope_id_detected_by_context_src_filepaths() {
        let preprocessed_config = PreprocessedConfig {
            root_path: PathBuf::from("../tests/contract-playground").canonicalize().unwrap(),
            src: None,
            include: Some(vec!["NonExistentFile.sol".to_string()]),
            exclude: None,
        };
        let (contexts, _) = compile::compile_project(preprocessed_config, false, true).unwrap();
        assert!(contexts.iter().all(|c| c.src_filepaths.is_empty()));
    }

    #[test]
    fn test_compiler_input_returns_empty_vector_when_no_solidity_files_present() {
        let preprocessed_config = PreprocessedConfig {
            root_path: PathBuf::from_str("../tests/no-sol-files").unwrap(),
            src: None,
            include: None,
            exclude: Some(vec!["NonExistentFile.sol".to_string()]),
        };
        let (contexts, _) = compile::compile_project(preprocessed_config, false, true).unwrap();
        assert!(contexts.is_empty());
    }
}

```

--------------------------------------------------------------------------------
/aderyn_driver/src/driver.rs:
--------------------------------------------------------------------------------

```rust
use crate::{
    interface::lsp::LspReport,
    mcp::McpServer,
    process::make_context,
    runner::{run_auditor_mode, run_detector_mode, run_lsp_mode},
};
use aderyn_core::detect::detector::{IssueDetector, IssueSeverity, get_all_issue_detectors};
use field_access::FieldAccess;
use std::sync::Arc;
use tokio::sync::Mutex;

#[derive(Clone, FieldAccess)]
pub struct Args {
    pub input_config: CliArgsInputConfig,
    pub output_config: CliArgsOutputConfig,
    pub common_config: CliArgsCommonConfig,
}

#[derive(Debug, Clone)]
pub struct CliArgsInputConfig {
    pub root: String,
    pub src: Option<String>,
    pub path_excludes: Option<Vec<String>>,
    pub path_includes: Option<Vec<String>>,
}

#[derive(Debug, Clone)]
pub struct CliArgsOutputConfig {
    pub output: String,
    pub stdout: bool,
    pub no_snippets: bool,
}

#[derive(Debug, Clone)]
pub struct CliArgsCommonConfig {
    pub verbose: bool,
    pub lsp: bool,
    pub skip_cloc: bool,
    pub highs_only: bool,
}

/// One way pipeline to print details for auditors. (for CLI)
pub fn kick_off_audit_mode(args: Args) {
    let run_pipeline = || -> Result<(), Box<dyn std::error::Error>> {
        let cx_wrapper =
            make_context(&args.input_config, &args.common_config).unwrap_or_else(|e| {
                eprintln!("Error making context: {}", e);
                std::process::exit(1);
            });

        run_auditor_mode(&cx_wrapper.contexts)?;
        Ok(())
    };

    // Kick-off
    run_pipeline().unwrap_or_else(|e| {
        eprintln!("Error driving aderyn: {}", e);
        std::process::exit(1);
    });
}

/// One way pipeline to generate vulnerability reports. (for CLI)
pub fn kick_off_report_creation(args: Args) {
    let detectors = detector_list(&args);

    let run_pipeline = || -> Result<(), Box<dyn std::error::Error>> {
        let cx_wrapper =
            make_context(&args.input_config, &args.common_config).unwrap_or_else(|e| {
                eprintln!("Error making context: {}", e);
                std::process::exit(1);
            });

        // Load the workspace context into the run function, which runs the detectors
        run_detector_mode(&cx_wrapper, detectors, &args.output_config)?;
        Ok(())
    };

    // Kick-off
    run_pipeline().unwrap_or_else(|e| {
        eprintln!("Error driving aderyn: {}", e);
        std::process::exit(1);
    });
}

/// Identify and return vulnerability reports. (for LSP)
pub fn fetch_report_for_lsp(args: Args) -> Arc<Mutex<Option<LspReport>>> {
    let detectors = detector_list(&args);

    let ctx_wrapper = match make_context(&args.input_config, &args.common_config) {
        Ok(ctx_wrapper) => ctx_wrapper,
        Err(_) => {
            return Arc::new(tokio::sync::Mutex::new(None));
        }
    };

    let lsp_report = run_lsp_mode(&ctx_wrapper, detectors);

    Arc::new(tokio::sync::Mutex::new(lsp_report))
}

/// Create MCP server with context fed
pub fn create_mcp_server(args: Args) -> Option<McpServer> {
    let ctx_wrapper = match make_context(&args.input_config, &args.common_config) {
        Ok(ctx_wrapper) => ctx_wrapper,
        Err(_) => return None,
    };
    Some(McpServer::new(ctx_wrapper))
}

fn detector_list(args: &Args) -> Vec<Box<dyn IssueDetector>> {
    get_all_issue_detectors()
        .into_iter()
        .filter(|d| !args.common_config.highs_only || d.severity() == IssueSeverity::High)
        .collect()
}

```

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

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

use crate::ast::{ASTNode, Expression, Identifier, MemberAccess, NodeID, NodeType};

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

#[derive(Default)]
pub struct UncheckedReturnDetector {
    // 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 UncheckedReturnDetector {
    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 function_call in context.function_calls() {
            // Find the ID of FunctionDefinition that we're calling so that we may identify if there
            // are returned params
            match function_call.expression.as_ref() {
                Expression::Identifier(Identifier { referenced_declaration: Some(id), .. })
                | Expression::MemberAccess(MemberAccess {
                    referenced_declaration: Some(id), ..
                }) => {
                    if let Some(ASTNode::ExpressionStatement(func_call_parent)) =
                        function_call.parent(context)
                        && func_call_parent
                            .parent(context)
                            .is_some_and(|node| node.node_type() == NodeType::Block)
                    {
                        // Now, we know that the return value is unused
                        if let Some(ASTNode::FunctionDefinition(function)) = context.nodes.get(id)
                            && !function.return_parameters.parameters.is_empty()
                        {
                            // Now, we know that the function has no return value
                            capture!(self, context, function_call);
                        }
                    }
                }
                _ => (),
            };
        }

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

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

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

    fn description(&self) -> String {
        String::from(
            "Function returns a value but it is ignored. Consider checking the return value.",
        )
    }

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

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

#[cfg(test)]
mod unchecked_return_tests {

    use crate::detect::{detector::IssueDetector, low::unchecked_return::UncheckedReturnDetector};

    #[test]

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

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

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

```

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

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

use crate::{
    ast::{ASTNode, NodeID},
    capture,
    context::{
        browser::ExtractMemberAccesses,
        graph::{CallGraphConsumer, CallGraphDirection, CallGraphVisitor},
        workspace::WorkspaceContext,
    },
    detect::{
        detector::{IssueDetector, IssueDetectorNamePool, IssueSeverity},
        helpers::get_explore_centers_of_loops,
    },
};
use eyre::Result;

#[derive(Default)]
pub struct DelegatecallInLoopDetector {
    // 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 DelegatecallInLoopDetector {
    fn detect(&mut self, context: &WorkspaceContext) -> Result<bool, Box<dyn Error>> {
        // PLAN
        // Explore inward from loops and track all the `delegatecall` that you come across

        let loop_explore_centers = get_explore_centers_of_loops(context);

        for explore_center in loop_explore_centers {
            // TODO: capture hints!

            // All the ASTNodes that are potentially run in a loop
            let callgraphs =
                CallGraphConsumer::get(context, &[explore_center], CallGraphDirection::Inward)?;

            for callgraph in callgraphs {
                let mut delegate_call_tracker = DelegateCallTracker::default();
                callgraph.accept(context, &mut delegate_call_tracker)?;

                if delegate_call_tracker.has_delegate_call {
                    capture!(self, context, explore_center);
                }
            }
        }

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

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

    fn title(&self) -> String {
        String::from("`delegatecall` in loop")
    }

    fn description(&self) -> String {
        String::from(
            "Using `delegatecall` in loop may consume excessive gas, or worse, lead to more severe issues.",
        )
    }

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

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

#[derive(Default)]
struct DelegateCallTracker {
    has_delegate_call: bool,
}

impl CallGraphVisitor for DelegateCallTracker {
    fn visit_any(&mut self, node: &ASTNode) -> eyre::Result<()> {
        if self.has_delegate_call {
            return Ok(());
        }

        let dcalls = ExtractMemberAccesses::from(node)
            .extracted
            .into_iter()
            .filter(|ma| ma.member_name == "delegatecall")
            .count();

        self.has_delegate_call = dcalls > 0;

        Ok(())
    }
}

#[cfg(test)]
mod delegate_call_in_loop_detector_tests {

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

    #[test]

    fn test_delegate_call_in_loop_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 = DelegatecallInLoopDetector::default();
        let found = detector.detect(&context).unwrap();
        assert!(found);
        assert_eq!(detector.instances().len(), 1);
    }
}

```

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

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

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

#[derive(Default)]
pub struct EmptyBlockDetector {
    // 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 EmptyBlockDetector {
    fn detect(&mut self, context: &WorkspaceContext) -> Result<bool, Box<dyn Error>> {
        for empty_block in context.blocks().iter().filter(|b| b.statements.is_empty()) {
            if let Some(ASTNode::FunctionDefinition(f)) =
                &empty_block.closest_ancestor_of_type(context, NodeType::FunctionDefinition)
            {
                // It's okay to have empty block if it's a constructor, receive, or fallback
                if *f.kind() == FunctionKind::Function {
                    capture!(self, context, f);
                } else if *f.kind() == FunctionKind::Constructor
                    || *f.kind() == FunctionKind::Receive
                    || *f.kind() == FunctionKind::Fallback
                {
                    // It's not okay to have empty block nested somewhere inside constructor
                    if let Some(block_chain) = empty_block.ancestral_line(context) {
                        let function_definition_index = block_chain
                            .iter()
                            .position(|x| x.node_type() == NodeType::FunctionDefinition)
                            .unwrap(); // Remember, we know we are already inside a constructor Function

                        //We start from going up from first parent to the Function definition
                        if function_definition_index > 1 {
                            // 1 here, means the first parent.
                            // So if the constructor is NOT the immediate parent of this empty block
                            // capture it!
                            capture!(self, context, empty_block);
                        }
                    }
                }
            }
        }
        Ok(!self.found_instances.is_empty())
    }

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

    fn description(&self) -> String {
        String::from("Consider removing empty blocks.")
    }

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

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

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

#[cfg(test)]
mod empty_block_tests {

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

    use super::EmptyBlockDetector;

    #[test]

    fn test_empty_block_by_loading_contract_directly() {
        let context = load_solidity_source_unit("../tests/contract-playground/src/EmptyBlocks.sol");

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

```

--------------------------------------------------------------------------------
/aderyn_driver/src/interface/util.rs:
--------------------------------------------------------------------------------

```rust
/*
 * Helps you carve a path from one file to another
 *
 * use case:
 *  Wherever you chose to keep report.md, you need a rel. pathway to link back
 *  to solidity file. This is important because absolute paths are out of scope
 *  if you want to embed them as links in markdown.
 */

use std::{
    collections::HashSet,
    path::{Component, PathBuf},
};

use aderyn_core::{ast::SourceUnit, context::workspace::WorkspaceContext, report::*};

pub fn carve_shortest_path(from_file: PathBuf, to_file: PathBuf) -> PathBuf {
    assert!(from_file.exists());
    assert!(to_file.exists());
    assert!(from_file.is_file());
    assert!(to_file.is_file());
    assert!(from_file.is_absolute());
    assert!(to_file.is_absolute());

    let mut to_file_comps = to_file.components();
    let mut from_file_comps = from_file.components();

    // curr_tfc - `current` `t`o_`f`ile `c`omponent
    let mut curr_tfc = to_file_comps.next();

    // curr_ffc - `current` `f`rom_`f`ile `c`omponent
    let mut curr_ffc = from_file_comps.next();

    let mut buffer = PathBuf::new();

    // Hold the max length common starting path in the buffer
    while let (Some(tfc), Some(ffc)) = (curr_tfc, curr_ffc) {
        if tfc != ffc {
            break;
        }
        buffer.push(ffc);
        curr_tfc = to_file_comps.next();
        curr_ffc = from_file_comps.next();
    }

    // Now, we are at the common place

    // High level 2 step plan to get to the `to_file`
    // 1. Do '../' until you reach a common place |==> you can reverse this problem (since we only
    //    care about no. of steps) |==> ask how many directories forward you should go to reach
    //    `from_file` |==> That's how many times you must come back!
    // 2. Now, go forward till you reach the `to_file`

    // STEP 1
    // Calculate '../' count
    let mut count_back = 0;

    // Keep looking forward until you reach the to_file
    while let Some(ffc) = curr_ffc {
        buffer.push(ffc);
        if let Component::Normal(_) = ffc
            && buffer.is_file()
        {
            break;
        }
        count_back += 1;
        curr_ffc = from_file_comps.next();
    }

    let mut backward_comps = (0..count_back).map(|_| Component::ParentDir).collect::<Vec<_>>();

    // STEP 2
    // Now, let's capture the forward path for  `to_file`
    let mut forward_comps = vec![];

    while let Some(comp) = curr_tfc {
        forward_comps.push(comp);
        curr_tfc = to_file_comps.next();
    }

    // Finally, concatenate both components
    backward_comps.extend(forward_comps.iter());

    backward_comps.iter().map(|c| c.as_os_str()).collect::<PathBuf>()
}

pub fn files_details(context: &WorkspaceContext) -> FilesDetails {
    let sloc_stats = &context.sloc_stats;

    let mut source_units = context.source_units_context.clone();
    source_units
        .sort_by_key(|su: &SourceUnit| su.absolute_path.as_deref().unwrap_or("").to_string());

    let mut seen_paths = HashSet::new();
    let files_details = source_units
        .iter()
        .filter_map(|source_unit| {
            let filepath = source_unit.absolute_path.as_ref()?;
            if seen_paths.insert(filepath.clone()) {
                let report = sloc_stats.iter().find(|r| r.0.contains(filepath))?;
                Some(FilesDetail { file_path: filepath.to_owned(), n_sloc: *report.1 })
            } else {
                None
            }
        })
        .collect::<Vec<_>>();

    FilesDetails { files_details }
}

```

--------------------------------------------------------------------------------
/tests/ast/mappings.json:
--------------------------------------------------------------------------------

```json
{"absolutePath":"a","exportedSymbols":{"C":[19]},"id":20,"nodeType":"SourceUnit","nodes":[{"abstract":false,"baseContracts":[],"canonicalName":"C","contractDependencies":[],"contractKind":"contract","fullyImplemented":true,"id":19,"linearizedBaseContracts":[19],"name":"C","nameLocation":"9:1:1","nodeType":"ContractDefinition","nodes":[{"canonicalName":"C.E","id":4,"members":[{"id":1,"name":"A","nameLocation":"26:1:1","nodeType":"EnumValue","src":"26:1:1"},{"id":2,"name":"B","nameLocation":"29:1:1","nodeType":"EnumValue","src":"29:1:1"},{"id":3,"name":"C","nameLocation":"32:1:1","nodeType":"EnumValue","src":"32:1:1"}],"name":"E","nameLocation":"22:1:1","nodeType":"EnumDefinition","src":"17:18:1"},{"constant":false,"id":9,"mutability":"mutable","name":"a","nameLocation":"59:1:1","nodeType":"VariableDeclaration","scope":19,"src":"40:20:1","stateVariable":true,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_mapping$_t_contract$_C_$19_$_t_bool_$","typeString":"mapping(contract C => bool)"},"typeName":{"id":8,"keyType":{"id":6,"nodeType":"UserDefinedTypeName","pathNode":{"id":5,"name":"C","nameLocations":["48:1:1"],"nodeType":"IdentifierPath","referencedDeclaration":19,"src":"48:1:1"},"referencedDeclaration":19,"src":"48:1:1","typeDescriptions":{"typeIdentifier":"t_contract$_C_$19","typeString":"contract C"}},"nodeType":"Mapping","src":"40:18:1","typeDescriptions":{"typeIdentifier":"t_mapping$_t_contract$_C_$19_$_t_bool_$","typeString":"mapping(contract C => bool)"},"valueType":{"id":7,"name":"bool","nodeType":"ElementaryTypeName","src":"53:4:1","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}}},"visibility":"internal"},{"constant":false,"id":13,"mutability":"mutable","name":"b","nameLocation":"91:1:1","nodeType":"VariableDeclaration","scope":19,"src":"66:26:1","stateVariable":true,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_mapping$_t_address_$_t_bool_$","typeString":"mapping(address => bool)"},"typeName":{"id":12,"keyType":{"id":10,"name":"address","nodeType":"ElementaryTypeName","src":"74:7:1","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"nodeType":"Mapping","src":"66:24:1","typeDescriptions":{"typeIdentifier":"t_mapping$_t_address_$_t_bool_$","typeString":"mapping(address => bool)"},"valueType":{"id":11,"name":"bool","nodeType":"ElementaryTypeName","src":"85:4:1","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}}},"visibility":"internal"},{"constant":false,"id":18,"mutability":"mutable","name":"c","nameLocation":"117:1:1","nodeType":"VariableDeclaration","scope":19,"src":"98:20:1","stateVariable":true,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_mapping$_t_enum$_E_$4_$_t_bool_$","typeString":"mapping(enum C.E => bool)"},"typeName":{"id":17,"keyType":{"id":15,"nodeType":"UserDefinedTypeName","pathNode":{"id":14,"name":"E","nameLocations":["106:1:1"],"nodeType":"IdentifierPath","referencedDeclaration":4,"src":"106:1:1"},"referencedDeclaration":4,"src":"106:1:1","typeDescriptions":{"typeIdentifier":"t_enum$_E_$4","typeString":"enum C.E"}},"nodeType":"Mapping","src":"98:18:1","typeDescriptions":{"typeIdentifier":"t_mapping$_t_enum$_E_$4_$_t_bool_$","typeString":"mapping(enum C.E => bool)"},"valueType":{"id":16,"name":"bool","nodeType":"ElementaryTypeName","src":"111:4:1","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}}},"visibility":"internal"}],"scope":20,"src":"0:121:1","usedErrors":[]}],"src":"0:122:1"}

```

--------------------------------------------------------------------------------
/.github/workflows/cargo.yml:
--------------------------------------------------------------------------------

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

name: Aderyn

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

jobs:
  check:
    name: Check
    runs-on: ubuntu-latest
    steps:
      - name: Checkout Sources
        uses: actions/checkout@v4

      - 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: Run checks
        run: |
          cargo check

  test:
    name: Tests
    runs-on: ubuntu-latest
    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: Run tests
        run: |
          cargo build
          cargo test -- --test-threads 1

  lints:
    name: Lints
    runs-on: ubuntu-latest
    steps:
      - name: Checkout Sources
        uses: actions/checkout@v4

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

      - name: Run cargo fmt
        run: |
          rustup component add --toolchain nightly-2025-09-20-x86_64-unknown-linux-gnu rustfmt
          cargo fmt --all --check

      - name: Run cargo clippy
        run: |
          rustup component add --toolchain nightly-2025-09-20-x86_64-unknown-linux-gnu clippy
          cargo clippy -- -D warnings


  decline-openssl-dependencies:
    name: Decline openssl
    runs-on: ubuntu-latest
    steps:

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

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

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

      - name: Run tests
        run: |
          ! cargo tree -i openssl --target all

  validate:
    name: validate
    runs-on: ubuntu-latest
    timeout-minutes: 10
    steps:
      - name: Checkout repository
        uses: actions/checkout@v4

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

      - name: Install cargo-deny
        run: |
          set -e
          curl -L https://github.com/EmbarkStudios/cargo-deny/releases/download/0.14.18/cargo-deny-0.14.18-x86_64-unknown-linux-musl.tar.gz | tar xzf -
          mv cargo-deny-*-x86_64-unknown-linux-musl/cargo-deny cargo-deny
          echo `pwd` >> $GITHUB_PATH
      - name: Validate deps
        run: |
          cargo deny check bans
          cargo deny check sources

```

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

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

use crate::ast::{Expression, LiteralKind, Mutability, NodeID};

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

#[derive(Default)]
pub struct IncorrectUseOfCaretOperatorDetector {
    // 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 IncorrectUseOfCaretOperatorDetector {
    fn detect(&mut self, context: &WorkspaceContext) -> Result<bool, Box<dyn Error>> {
        // Copied Heuristic from Slither:
        // look for binary expressions with ^ operator where at least one of the operands is a
        // constant, and # the constant is not in hex, because hex typically is used with
        // bitwise xor and not exponentiation

        for binary_operation in
            context.binary_operations().into_iter().filter(|op| op.operator == "^")
        {
            for expr in [
                binary_operation.left_expression.as_ref(),
                binary_operation.right_expression.as_ref(),
            ] {
                if let Expression::Literal(literal) = expr
                    && literal.kind == LiteralKind::Number
                    && literal.value.as_ref().is_some_and(|v| !v.starts_with("0x"))
                {
                    capture!(self, context, binary_operation);
                }
                if let Expression::Identifier(identifier) = expr
                    && let Some(ref_decl) = identifier.referenced_declaration
                    && let Some(ASTNode::VariableDeclaration(v)) = context.nodes.get(&ref_decl)
                    && v.mutability() == Some(&Mutability::Constant)
                    && let Some(Expression::Literal(literal)) = v.value.as_ref()
                    && literal.kind == LiteralKind::Number
                    && literal.value.as_ref().is_some_and(|v| !v.starts_with("0x"))
                {
                    capture!(self, context, binary_operation);
                }
            }
        }

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

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

    fn title(&self) -> String {
        String::from("Incorrect use of caret operator")
    }

    fn description(&self) -> String {
        String::from(
            "The caret operator is usually mistakenly thought of as an exponentiation operator but actually, it's a bitwise xor operator.",
        )
    }

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

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

#[cfg(test)]
mod incorrect_use_of_caret_operator_tests {

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

    #[test]

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

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

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

```

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

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

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

#[derive(Default)]
pub struct UnsafeERC721MintDetector {
    // 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 UnsafeERC721MintDetector {
    fn detect(&mut self, context: &WorkspaceContext) -> Result<bool, Box<dyn Error>> {
        for identifier in context.identifiers() {
            // if source_unit has any ImportDirectives with absolute_path containing "openzeppelin"
            // call identifier.accept(self)
            if let Some(ASTNode::SourceUnit(source_unit)) =
                identifier.closest_ancestor_of_type(context, NodeType::SourceUnit)
            {
                let import_directives = source_unit.import_directives();
                if import_directives.iter().any(|directive| {
                    directive
                        .absolute_path
                        .as_ref()
                        .is_some_and(|path| path.contains("openzeppelin"))
                }) && identifier.name == "_mint"
                {
                    let this_contract_definition = identifier
                        .closest_ancestor_of_type(context, NodeType::ContractDefinition)
                        .unwrap();
                    if let ASTNode::ContractDefinition(contract_definition) =
                        this_contract_definition
                    {
                        for base_contract in contract_definition.base_contracts.iter() {
                            if let Some(base_name) = base_contract.base_name.name()
                                && base_name.contains("ERC721")
                            {
                                capture!(self, context, identifier);
                            }
                        }
                    }
                }
            }
        }
        Ok(!self.found_instances.is_empty())
    }

    fn title(&self) -> String {
        String::from("Unsafe `ERC721::_mint()`")
    }

    fn description(&self) -> String {
        String::from(
            "Using `ERC721::_mint()` can mint ERC721 tokens to addresses which don't support ERC721 tokens. Use `_safeMint()` instead of `_mint()` for ERC721 tokens.",
        )
    }

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

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

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

#[cfg(test)]
mod unsafe_erc721_mint_tests {
    use crate::detect::{detector::IssueDetector, low::UnsafeERC721MintDetector};

    #[test]

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

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

```

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

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

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

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

#[derive(Default)]
pub struct StorageArrayMemoryEditDetector {
    // 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 StorageArrayMemoryEditDetector {
    fn detect(&mut self, context: &WorkspaceContext) -> Result<bool, Box<dyn Error>> {
        // get all Identifiers with argumentTypes
        // If any of them are of the type storage,
        //  grab the index of that param in the array of argument types
        //  get the referreddeclaration node of the identifier (a function)
        //  get parameter at that index and check if the storageLocation is not storage
        //  if not, capture it.

        for identifier in context
            .identifiers()
            .into_iter()
            .filter(|identifier| identifier.argument_types.is_some())
        {
            for (index, argument_type) in
                identifier.argument_types.as_ref().unwrap().iter().enumerate()
            {
                if let Some(type_string) = &argument_type.type_string
                    && type_string.contains("storage ref")
                {
                    let definition_ast =
                        context.nodes.get(&identifier.referenced_declaration.unwrap());
                    if let Some(ASTNode::FunctionDefinition(definition)) = definition_ast {
                        let parameter = definition
                            .parameters
                            .parameters
                            .get(index)
                            .ok_or_else(|| eyre::eyre!("Parameter not found"))?;
                        if parameter.storage_location != StorageLocation::Storage {
                            capture!(self, context, identifier);
                        }
                    }
                }
            }
        }

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

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

    fn title(&self) -> String {
        String::from("Storage Array Edited with Memory")
    }

    fn description(&self) -> String {
        String::from(
            "Storage reference is passed to a function with a memory parameter. This will not update the storage variable as expected. Consider using storage parameters instead.",
        )
    }

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

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

#[cfg(test)]
mod storage_array_edit_with_memory_tests {

    use crate::detect::{
        detector::IssueDetector, high::storage_array_memory_edit::StorageArrayMemoryEditDetector,
    };

    #[test]

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

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

```

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

```rust
use crate::{
    ast::{NodeID, NodeType},
    context::{
        browser::{ExtractFunctionCalls, ExtractModifierInvocations, GetClosestAncestorOfTypeX},
        workspace::{ASTNode, WorkspaceContext},
    },
};
use std::collections::{HashMap, HashSet, hash_map::*};

#[derive(Debug, Default)]
pub struct CallgraphExplorationPoints {
    pub points: HashMap<NodeID, GraphPoints>,
}

#[derive(Debug, Default)]
pub struct GraphPoints {
    pub entry: HashSet<NodeID>,
    pub inward: HashSet<NodeID>,
    pub outward: HashSet<NodeID>,
}

pub enum GraphPointType {
    Entry,
    Inward,
    Outward,
}

impl CallgraphExplorationPoints {
    pub fn new() -> Self {
        Default::default()
    }
    pub fn add(&mut self, graph_type: GraphPointType, contract_id: NodeID, point: NodeID) {
        match self.points.entry(contract_id) {
            Entry::Occupied(mut o) => match graph_type {
                GraphPointType::Entry => {
                    o.get_mut().entry.insert(point);
                }
                GraphPointType::Inward => {
                    o.get_mut().inward.insert(point);
                }
                GraphPointType::Outward => {
                    o.get_mut().outward.insert(point);
                }
            },
            Entry::Vacant(v) => {
                v.insert(Default::default());
                self.add(graph_type, contract_id, point);
            }
        };
    }
}

pub(super) fn derive_surface_points(
    context: &WorkspaceContext,
    nodes: &[&ASTNode],
) -> CallgraphExplorationPoints {
    let mut cg_points = CallgraphExplorationPoints::new();

    let containing_function_or_modifier = |node: &ASTNode| -> Option<NodeID> {
        if matches!(node.node_type(), NodeType::FunctionDefinition | NodeType::ModifierDefinition) {
            return node.id();
        }
        node.closest_ancestor_of_type(context, NodeType::FunctionDefinition)
            .or_else(|| node.closest_ancestor_of_type(context, NodeType::ModifierDefinition))?
            .id()
    };

    for &node in nodes {
        let Some(containing_fm) = containing_function_or_modifier(node) else {
            continue;
        };
        let function_calls = ExtractFunctionCalls::from(node).extracted;
        let modifier_calls = ExtractModifierInvocations::from(node).extracted;

        let cg = context.callgraphs.as_ref().expect("callgraph not found");
        for (contract_id, graph) in &cg.inward_callgraphs {
            let Some(ASTNode::ContractDefinition(contract)) = context.nodes.get(contract_id) else {
                continue;
            };
            if graph.contains_key(&containing_fm) {
                // Entry
                if let Some(node_id) = node.id() {
                    cg_points.add(GraphPointType::Entry, *contract_id, node_id);
                }
                // Inward
                for function_call in function_calls.iter() {
                    if let Some(f) = context.resolve_internal_call(contract, function_call) {
                        cg_points.add(GraphPointType::Inward, *contract_id, f.id);
                    }
                }
                for modifier_call in modifier_calls.iter() {
                    if let Some(m) = context.resolve_modifier_call(contract, modifier_call) {
                        cg_points.add(GraphPointType::Inward, *contract_id, m.id);
                    }
                }
                // Outward
                cg_points.add(GraphPointType::Outward, *contract_id, containing_fm);
            }
        }
    }
    cg_points
}

```

--------------------------------------------------------------------------------
/tests/ast/try_catch.json:
--------------------------------------------------------------------------------

```json
{"absolutePath":"src/X.sol","id":40896,"exportedSymbols":{"SomeContract":[40895]},"nodeType":"SourceUnit","src":"0:243:17","nodes":[{"id":40895,"nodeType":"ContractDefinition","src":"0:243:17","nodes":[{"id":40894,"nodeType":"FunctionDefinition","src":"28:213:17","nodes":[],"body":{"id":40893,"nodeType":"Block","src":"50:191:17","nodes":[],"statements":[{"clauses":[{"block":{"id":40880,"nodeType":"Block","src":"75:30:17","statements":[]},"errorName":"","id":40881,"nodeType":"TryCatchClause","src":"75:30:17"},{"block":{"id":40885,"nodeType":"Block","src":"140:30:17","statements":[]},"errorName":"Error","id":40886,"nodeType":"TryCatchClause","parameters":{"id":40884,"nodeType":"ParameterList","parameters":[{"constant":false,"id":40883,"mutability":"mutable","name":"reason","nameLocation":"132:6:17","nodeType":"VariableDeclaration","scope":40886,"src":"118:20:17","stateVariable":false,"storageLocation":"memory","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string"},"typeName":{"id":40882,"name":"string","nodeType":"ElementaryTypeName","src":"118:6:17","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"}],"src":"117:22:17"},"src":"106:64:17"},{"block":{"id":40890,"nodeType":"Block","src":"205:30:17","statements":[]},"errorName":"","id":40891,"nodeType":"TryCatchClause","parameters":{"id":40889,"nodeType":"ParameterList","parameters":[{"constant":false,"id":40888,"mutability":"mutable","name":"lowLevelData","nameLocation":"191:12:17","nodeType":"VariableDeclaration","scope":40891,"src":"178:25:17","stateVariable":false,"storageLocation":"memory","typeDescriptions":{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes"},"typeName":{"id":40887,"name":"bytes","nodeType":"ElementaryTypeName","src":"178:5:17","typeDescriptions":{"typeIdentifier":"t_bytes_storage_ptr","typeString":"bytes"}},"visibility":"internal"}],"src":"177:27:17"},"src":"171:64:17"}],"externalCall":{"arguments":[],"expression":{"argumentTypes":[],"expression":{"id":40877,"name":"this","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-28,"src":"64:4:17","typeDescriptions":{"typeIdentifier":"t_contract$_SomeContract_$40895","typeString":"contract SomeContract"}},"id":40878,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberLocation":"69:3:17","memberName":"foo","nodeType":"MemberAccess","referencedDeclaration":40894,"src":"64:8:17","typeDescriptions":{"typeIdentifier":"t_function_external_nonpayable$__$returns$__$","typeString":"function () external"}},"id":40879,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"nameLocations":[],"names":[],"nodeType":"FunctionCall","src":"64:10:17","tryCall":true,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":40892,"nodeType":"TryStatement","src":"60:175:17"}]},"functionSelector":"c2985578","implemented":true,"kind":"function","modifiers":[],"name":"foo","nameLocation":"37:3:17","parameters":{"id":40875,"nodeType":"ParameterList","parameters":[],"src":"40:2:17"},"returnParameters":{"id":40876,"nodeType":"ParameterList","parameters":[],"src":"50:0:17"},"scope":40895,"stateMutability":"nonpayable","virtual":false,"visibility":"public"}],"abstract":false,"baseContracts":[],"canonicalName":"SomeContract","contractDependencies":[],"contractKind":"contract","fullyImplemented":true,"linearizedBaseContracts":[40895],"name":"SomeContract","nameLocation":"9:12:17","scope":40896,"usedErrors":[],"usedEvents":[]}]}
```

--------------------------------------------------------------------------------
/reports/nft-report.md:
--------------------------------------------------------------------------------

```markdown
# Aderyn Analysis Report

This report was generated by [Aderyn](https://github.com/Cyfrin/aderyn), a static analysis tool built by [Cyfrin](https://cyfrin.io), a blockchain security company. This report is not a substitute for manual audit or security review. It should not be relied upon for any purpose other than to assist in the identification of potential security vulnerabilities.
# Table of Contents

- [Summary](#summary)
  - [Files Summary](#files-summary)
  - [Files Details](#files-details)
  - [Issue Summary](#issue-summary)
- [Low Issues](#low-issues)
  - [L-1: Unspecific Solidity Pragma](#l-1-unspecific-solidity-pragma)
  - [L-2: Public Function Not Used Internally](#l-2-public-function-not-used-internally)
  - [L-3: PUSH0 Opcode](#l-3-push0-opcode)
  - [L-4: Unused Import](#l-4-unused-import)
  - [L-5: State Variable Could Be Constant](#l-5-state-variable-could-be-constant)


# Summary

## Files Summary

| Key | Value |
| --- | --- |
| .sol Files | 5 |
| Total nSLOC | 34 |


## Files Details

| Filepath | nSLOC |
| --- | --- |
| src/BasicNft.sol | 15 |
| src/F1.sol | 4 |
| src/F2.sol | 3 |
| src/Initializer.sol | 7 |
| src/inner-core-modules/ICM.sol | 5 |
| **Total** | **34** |


## Issue Summary

| Category | No. of Issues |
| --- | --- |
| High | 0 |
| Low | 5 |


# Low Issues

## L-1: Unspecific Solidity Pragma

Consider using a specific version of Solidity in your contracts instead of a wide version. For example, instead of `pragma solidity ^0.8.0;`, use `pragma solidity 0.8.0;`

<details><summary>1 Found Instances</summary>


- Found in src/F1.sol [Line: 3](../tests/foundry-nft-f23/src/F1.sol#L3)

	```solidity
	pragma solidity ^0.8.10;
	```

</details>



## L-2: Public Function Not Used Internally

If a function is marked public but is not used internally, consider marking it as `external`.

<details><summary>2 Found Instances</summary>


- Found in src/BasicNft.sol [Line: 18](../tests/foundry-nft-f23/src/BasicNft.sol#L18)

	```solidity
	    function mint() public {
	```

- Found in src/Initializer.sol [Line: 8](../tests/foundry-nft-f23/src/Initializer.sol#L8)

	```solidity
	    function get_start_token_id() public pure returns(uint256) {
	```

</details>



## L-3: PUSH0 Opcode

Solc compiler version 0.8.20 switches the default target EVM version to Shanghai, which means that the generated bytecode will include PUSH0 opcodes. Be sure to select the appropriate EVM version in case you intend to deploy on a chain other than mainnet like L2 chains that may not support PUSH0, otherwise deployment of your contracts will fail.

<details><summary>1 Found Instances</summary>


- Found in src/F1.sol [Line: 3](../tests/foundry-nft-f23/src/F1.sol#L3)

	```solidity
	pragma solidity ^0.8.10;
	```

</details>



## L-4: Unused Import

Redundant import statement. Consider removing it.

<details><summary>1 Found Instances</summary>


- Found in src/F1.sol [Line: 5](../tests/foundry-nft-f23/src/F1.sol#L5)

	```solidity
	import "./F2.sol";
	```

</details>



## L-5: State Variable Could Be Constant

State variables that are not updated following deployment should be declared constant to save gas. Add the `constant` attribute to state variables that never change.

<details><summary>2 Found Instances</summary>


- Found in src/inner-core-modules/ICM.sol [Line: 6](../tests/foundry-nft-f23/src/inner-core-modules/ICM.sol#L6)

	```solidity
	    string public PROJECT_NAME = "Dogie";
	```

- Found in src/inner-core-modules/ICM.sol [Line: 7](../tests/foundry-nft-f23/src/inner-core-modules/ICM.sol#L7)

	```solidity
	    string public PROJECT_SYMBOL = "DOG";
	```

</details>




```

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

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

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

impl Display for ContractDefinitionNode {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self {
            ContractDefinitionNode::UsingForDirective(using_for_directive) => {
                using_for_directive.fmt(f)
            }
            ContractDefinitionNode::StructDefinition(struct_definition) => struct_definition.fmt(f),
            ContractDefinitionNode::EnumDefinition(enum_definition) => enum_definition.fmt(f),
            ContractDefinitionNode::VariableDeclaration(variable_declaration) => {
                variable_declaration.fmt(f)
            }
            ContractDefinitionNode::EventDefinition(event_definition) => event_definition.fmt(f),
            ContractDefinitionNode::FunctionDefinition(function_definition) => {
                function_definition.fmt(f)
            }
            ContractDefinitionNode::ModifierDefinition(modifier_definition) => {
                modifier_definition.fmt(f)
            }
            ContractDefinitionNode::ErrorDefinition(error_definition) => error_definition.fmt(f),
            ContractDefinitionNode::UserDefinedValueTypeDefinition(
                user_defined_value_type_definition,
            ) => user_defined_value_type_definition.fmt(f),
        }
    }
}

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

        if let Some(arguments) = self.arguments.as_ref() {
            f.write_str("(")?;

            for (i, argument) in arguments.iter().enumerate() {
                f.write_fmt(format_args!(
                    "{}{}",
                    match i {
                        0 => "",
                        _ => ", ",
                    },
                    argument,
                ))?;
            }

            f.write_str(")")?;
        }

        Ok(())
    }
}

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

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

        for (i, base_contract) in self.base_contracts.iter().enumerate() {
            f.write_fmt(format_args!(
                "{}{}",
                match i {
                    0 => " is ",
                    _ => ", ",
                },
                base_contract
            ))?;
        }

        f.write_str(" {\n")?;

        for node in self.nodes.iter() {
            f.write_fmt(format_args!(
                "\t{}{}\n",
                node,
                match node {
                    ContractDefinitionNode::UsingForDirective(_)
                    | ContractDefinitionNode::EventDefinition(_)
                    | ContractDefinitionNode::ErrorDefinition(_)
                    | ContractDefinitionNode::VariableDeclaration(_)
                    | ContractDefinitionNode::UserDefinedValueTypeDefinition(_) => ";",

                    ContractDefinitionNode::StructDefinition(_)
                    | ContractDefinitionNode::EnumDefinition(_)
                    | ContractDefinitionNode::FunctionDefinition(_)
                    | ContractDefinitionNode::ModifierDefinition(_) => "",
                }
            ))?;
        }

        f.write_str("}")?;

        Ok(())
    }
}

```

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

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

use crate::ast::NodeID;

use crate::capture;

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

#[derive(Default)]
pub struct DelegateCallUncheckedAddressDetector {
    // 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 DelegateCallUncheckedAddressDetector {
    fn detect(&mut self, context: &WorkspaceContext) -> Result<bool, Box<dyn Error>> {
        struct DelegateCallNoAddressChecksTracker<'a> {
            has_address_checks: bool,
            has_delegate_call_on_non_state_variable_address: bool,
            context: &'a WorkspaceContext,
        }

        impl CallGraphVisitor for DelegateCallNoAddressChecksTracker<'_> {
            fn visit_any(&mut self, node: &crate::context::workspace::ASTNode) -> eyre::Result<()> {
                if !self.has_address_checks && helpers::has_binary_checks_on_some_address(node) {
                    self.has_address_checks = true;
                }
                if !self.has_delegate_call_on_non_state_variable_address
                    && helpers::has_delegate_calls_on_non_state_variables(node, self.context)
                {
                    self.has_delegate_call_on_non_state_variable_address = true;
                }
                eyre::Ok(())
            }
        }

        for (func, callgraphs) in context.entrypoints_with_callgraphs() {
            for callgraph in callgraphs {
                let mut tracker = DelegateCallNoAddressChecksTracker {
                    has_address_checks: false,
                    has_delegate_call_on_non_state_variable_address: false,
                    context,
                };
                callgraph.accept(context, &mut tracker)?;

                if tracker.has_delegate_call_on_non_state_variable_address
                    && !tracker.has_address_checks
                {
                    capture!(self, context, func)
                }
            }
        }
        Ok(!self.found_instances.is_empty())
    }

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

    fn title(&self) -> String {
        String::from("`delegatecall` to an Arbitrary Address")
    }

    fn description(&self) -> String {
        String::from(
            "Making a `delegatecall` to an arbitrary address without any checks is dangerous. Consider adding requirements on the target address.",
        )
    }

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

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

#[cfg(test)]
mod delegate_call_no_address_check_tests {

    use crate::detect::{
        detector::IssueDetector,
        high::delegate_call_unchecked_address::DelegateCallUncheckedAddressDetector,
    };

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

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

        assert!(found);

        assert_eq!(detector.instances().len(), 1);
    }
}

```
Page 6/94FirstPrevNextLast