On Static Analysis + LLM
Source: Dev.to
Static analysis
Static analysis is understanding your code before running it.
def add(a, b):
return a + b
def main():
return add(1, 3)Above is a trivial program.
At a glance, you can tell that calling main() will return 4.
Questions to ponder
- What happens if you call
addwith non‑numeric types? e.g. what doesadd("foo", "bar")return? - How do you know about the above?
Static analysis is about answering these questions without having to run the code.
As human programmers we develop familiarity with the language and runtime, which lets us answer such questions easily.
But how does a machine figure out the answer?
Program representations
Programs have many representations (the human‑friendly syntax being just one of them). Below are a few alternative representations of the same Python program.
AST
Module(
body=[
FunctionDef(
name='add',
args=arguments(
args=[
arg(arg='a'),
arg(arg='b')]),
body=[
Return(
value=BinOp(
left=Name(id='a'),
op=Add(),
right=Name(id='b')))]),
FunctionDef(
name='main',
args=arguments(),
body=[
Return(
value=Call(
func=Name(id='add'),
args=[
Constant(value=1),
Constant(value=3)]))])])Bytecode
Disassembly of :
1 RESUME 0
2 LOAD_FAST 0 (a)
3 LOAD_FAST 1 (b)
4 BINARY_OP 0 (+)
5 RETURN_VALUE
Disassembly of :
1 RESUME 0
2 LOAD_GLOBAL 1 (add)
3 LOAD_SMALL_INT 1
4 LOAD_SMALL_INT 3
5 CALL 2
6 RETURN_VALUEThese representations are “closer to the machine”. They contain details relevant to a compiler or CPU trying to execute the program. Most human programmers never bother with these low‑level details, but they can be useful.
Call‑graph
example.py
[D] add
[D] main
main
[U] add[D] means “defined in”, and [U] means “uses”.
You can read the above as “add and main are defined in example.py, and add is used in main”.
Call graphs are very useful for understanding the chain of dependencies and data flow in a program. In large systems with hundreds of thousands of lines, thousands of functions, and many files, call graphs help answer questions such as:
- What functions and files does a particular piece of data pass through?
- If I need to refactor or rethink the data flow, which files and functions must I touch?
Static analysis is a powerful tool for engineers working on complex systems that cannot simply be rewritten from scratch. Many systems grow on top of shaky foundations, and understanding those foundations is essential.
Static analysis & LLMs in 2026
We now have large language models (LLMs).
Can we just use LLMs for refactors and rewrites?
There’s a perception that you can’t do “serious” engineering with LLMs because:
- Their context windows are too small.
- They tend to produce “slop”.
I disagree. I believe in a capability overhang: naive prompting and poor context management dramatically nerf a model’s ability, much like asking a competent engineer to look at code for only one second before solving a problem.
Tools such as Claude Code, Codex, and Opencode give models hands and environments to test and iterate, but they’re still limited by the permissions we grant and the patterns we encode in our prompts. Ultimately, a model + harness is limited by the engineer’s own competency.
Great engineers are not wizards.
They are good engineers who use great tools.
There are many analyses you can perform without running or profiling code: call‑graph analysis, control‑flow analysis, etc. Providing models access to these tools—tools that senior engineers already use—offers “low‑hanging fruit” for improving large‑scale refactors.
In my experience, giving models the ability to analyze codebases via static analysis enables them to plan and execute larger refactors more competently. They can reason about the codebase at a level comparable to a senior engineer.
I’m currently building better static‑analysis tools for Python. Because Python is dynamic (and many users aren’t programmers), the tooling is less mature than for languages like C/LLVM, but LLMs are turbocharging development here. I’ve already seen LLMs refactor and improve a 10 k LOC Python project simply by looking at call graphs and control‑flow graphs.
It seems to me that frontier models are probably as competent as senior engineers when equipped with the right static‑analysis data.
As a senior or staff‑level engineer, given the right prompt, tools, and enough time to reason, getting this right will “just” be a matter of building tools, formats, and representations that are highly amenable to LLM reasoning.