Abstract Syntax Tree
A hierarchical tree representation of source code structure used by compilers and static analysis tools to understand and analyze programs.
An Abstract Syntax Tree (AST) is a tree-shaped data structure representing the hierarchical structure of source code. Each node in the tree represents a construct in the code—functions, expressions, statements, variables—with parent-child relationships showing how these constructs nest within each other. Compilers use ASTs as an intermediate representation during compilation, and static analysis tools like Aderyn traverse ASTs to detect vulnerabilities without executing code.
AST Structure for Solidity
When the Solidity compiler processes a contract, it generates an AST representing every element of the code. Consider this simple function:
1function calculate(uint a, uint b) public returns (uint) {2 return a * b / 100;3}
The AST represents this as a tree:
- FunctionDefinition node (the function itself)
- ParameterList node (function parameters)
- VariableDeclaration nodes (a and b)
- Block node (function body)
- Return node
- BinaryOperation node (division)
- BinaryOperation node (multiplication)
- Identifier node (a)
- Identifier node (b)
- Literal node (100)
- BinaryOperation node (multiplication)
- BinaryOperation node (division)
- Return node
- ParameterList node (function parameters)
Each node contains metadata like source location, type information, and node IDs that link related elements together.
Generating Solidity ASTs
The Solidity compiler can output AST in JSON format:
1solc --ast-compact-json Contract.sol > Contract.ast.json
Foundry and Hardhat also generate ASTs during compilation, stored alongside compiled artifacts. These JSON files contain the complete structural representation of your contracts.
ASTs in Static Analysis
Static analyzers traverse ASTs to identify vulnerability patterns. Rather than reading source code as text, analyzers work with the structured tree representation:
Pattern matching: Detectors look for specific node patterns. For example, a reentrancy attack detector might search for external calls (FunctionCall nodes) followed by state changes (Assignment nodes) without proper guards.
Data flow analysis: By following variable references through the AST, analyzers track how data moves through the contract, identifying potential taint paths.
Control flow analysis: The AST's structure reveals branching logic, loops, and function calls, enabling analysis of which code paths are reachable under what conditions.
Writing AST-Based Detectors
Custom detectors for tools like Aderyn work by:
-
Querying specific node types: Request all nodes of a particular type (e.g., all BinaryOperation nodes).
-
Filtering by properties: Narrow down to nodes matching specific criteria (e.g., operations using the division operator).
-
Examining relationships: Check parent, child, or sibling nodes to understand context.
-
Reporting findings: When a vulnerability pattern matches, record the source location for the report.
Example: Detecting integer division before multiplication:
1for op in context.binary_operations().filter(|op| op.operator == "*") {2 if let Expression::BinaryOperation(left) = op.left_expression.as_ref() {3 if left.operator == "/" {4 // Division before multiplication found5 capture!(self, context, left);6 }7 }8}
AST vs Source Code Analysis
Working with ASTs offers advantages over raw source code analysis:
Normalized structure: Different formatting styles produce identical ASTs. Whitespace, comments, and style choices don't affect analysis.
Type information: The AST includes resolved type information, enabling type-aware analysis that source text parsing cannot achieve.
Unambiguous parsing: The compiler has already resolved syntactic ambiguities. Analyzers don't need to handle edge cases in language grammar.
Efficient traversal: Tree structures support efficient queries for specific node types without scanning entire files.
AST Limitations
AST-based analysis has constraints:
Compile requirement: Code must compile successfully to generate an AST. Syntax errors or missing dependencies prevent analysis.
Static only: ASTs represent code structure, not runtime behavior. Dynamic values, external contract states, and runtime conditions aren't captured.
Single-contract view: Basic AST analysis examines contracts individually. Cross-contract analysis requires additional tooling to link ASTs together.
ASTs in Development Tooling
Beyond static analysis, ASTs power many development tools:
Code formatters: Read AST, apply formatting rules, regenerate source code.
Refactoring tools: Modify AST structure to rename variables, extract functions, or restructure code.
Documentation generators: Extract function signatures, NatSpec comments, and contract structure from ASTs.
IDE features: Code navigation, completion, and error highlighting often rely on AST analysis.
Understanding ASTs helps developers and auditors comprehend how security tools work internally and enables building custom tooling for specific needs.
Articles Using This Term
Learn more about Abstract Syntax Tree in these articles:
Related Terms
Static Analysis
Automated examination of smart contract code without executing it to identify potential vulnerabilities, bugs, and code quality issues.
Aderyn
An open-source Rust-based static analyzer for Solidity smart contracts that helps detect vulnerabilities before deployment.
Foundry
Fast, portable Ethereum development framework written in Rust, featuring advanced testing and debugging capabilities.
Need expert guidance on Abstract Syntax Tree?
Our team at Zealynx has deep expertise in blockchain security and DeFi protocols. Whether you need an audit or consultation, we're here to help.
Get a Quote

