Prolog-powered static analyzer for Python code. Detects 13+ code smells through declarative pattern matching on ASTs.
About • Features • Quick Start • Usage • Detected Patterns • Testing
PrologLint leverages Prolog's logical inference capabilities to perform static analysis on Python source code. The tool converts Python's Abstract Syntax Tree (AST) into Prolog facts, enabling powerful declarative pattern matching to detect code smells and anti-patterns.
Python Source (.py) → JSON AST → Prolog Facts (.pl) → Pattern Analysis
↓ ↓ ↓ ↓
ast_parser.py ast2json json_to_prolog.pl analyzer.pl
- AST Parsing — Converts Python code to structured Prolog facts
- Tree Navigation — Hierarchical traversal with
parent/2,children/2,ancestor/2 - Tree Visualization — Pretty-print AST with configurable verbosity
- Pattern Detection — 13+ code smell detectors
- Accumulator Pattern Detection — Identifies proper accumulator usage in loops
- Infinite Loop Detection — Catches always-true conditions and unmodified loop variables
- Complexity Analysis — Flags excessive nesting, long functions, too many parameters
- Python 3.x
- SWI-Prolog 9.x
ast2jsonPython package
# Clone the repository
git clone https://github.com/mathisdelsart/PrologLint.git
cd PrologLint
# Install Python dependencies
pip install -r requirements.txt# Option 1: Using the automation script
./src/analyze.sh path/to/your_file.py
# Option 2: Using Make
make analyze FILE=path/to/your_file.py
# Option 3: Step by step (see Usage section)The easiest way to analyze a Python file:
./src/analyze.sh examples/demo/lot_of_bad_patterns.pyThis will:
- Parse the Python file to JSON
- Convert JSON to Prolog facts
- Launch SWI-Prolog with the analysis loaded
python3 src/ast_parser.py examples/demo/lot_of_bad_patterns.py
# Output: examples/demo/lot_of_bad_patterns.jsonswipl -g "consult('src/json_to_prolog.pl'), load_and_save_python('examples/demo/lot_of_bad_patterns.json')" -t halt
mv facts.pl examples/demo/lot_of_bad_patterns.plswipl src/analyzer.pl examples/demo/lot_of_bad_patterns.plOnce in the Prolog REPL:
% Check all patterns at once
?- check_all_patterns_respected.
% Visualize the AST
?- print_tree. % Condensed view
?- print_tree(verbose). % Detailed view
?- print_tree(12). % Subtree from node 12
% Specific pattern checks
?- has_accumulator_patterns.
?- has_all_functions_have_return_as_last_statement.
?- has_all_loop_have_used_vars.| Pattern | Description | Predicate |
|---|---|---|
| Empty Constructor | __init__ with only pass |
has_empty_constructor/0 |
| Constructor Returns | __init__ returning a value |
has_constructor_return/0 |
| Parameter Reassignment | Reassigning function parameters | has_parameters_reassignement/0 |
| Increment in For-Loop | Manual loop variable modification | has_increment_in_forloop/0 |
| Early Return | Return statements inside loops | has_early_return/0 |
| Too Much Indentation | 3+ levels of nesting | has_too_much_indent/0 |
| Print Instead of Return | Functions ending with print | has_print_instead_return/0 |
| Infinite Loop | Always-true while conditions | has_infinite_loop/0 |
| Too Long Function | Functions exceeding 15 statements | has_too_long_function/0 |
| Too Many Parameters | Functions with 5+ parameters | has_too_many_parameters/0 |
| Unused Loop Variables | Loop variables never used | has_all_loop_have_used_vars/0 |
| Missing Return | Functions not ending with return | has_all_functions_have_return_as_last_statement/0 |
| Accumulator Pattern | Proper accumulator usage | has_accumulator_patterns/0 |
PrologLint/
├── src/
│ ├── analyzer.pl # Main analysis engine (pattern detection)
│ ├── json_to_prolog.pl # JSON to Prolog facts converter
│ ├── ast_parser.py # Python AST to JSON parser
│ ├── tests.pl # Test suite (76 tests)
│ └── analyze.sh # Automation script
├── examples/
│ ├── demo/ # Good/bad practice demonstrations
│ ├── basic_predicates/ # Tree navigation examples
│ ├── accumulator_patterns/ # Accumulator pattern tests
│ ├── constructor_empty/ # Empty constructor tests
│ ├── constructor_return/ # Constructor return tests
│ ├── early_return/ # Early return tests
│ ├── increment_in_forloop/ # For-loop increment tests
│ ├── infinite_loop/ # Infinite loop tests
│ ├── parameters_reassignement/# Parameter reassignment tests
│ ├── print_instead_return/ # Print vs return tests
│ ├── return_last_statement/ # Return placement tests
│ ├── too_long_function/ # Function length tests
│ ├── too_many_parameters/ # Parameter count tests
│ ├── too_much_indent/ # Indentation depth tests
│ └── unused_loop_vars/ # Unused variable tests
├── Makefile # Build automation
├── requirements.txt # Python dependencies
└── README.md
Run the complete test suite:
make test
# or
swipl -g "consult('src/tests.pl'), run_tests" -t haltThe test suite includes 76 tests covering:
- Basic predicates (
parent/2,children/2,ancestor/2) - Tree visualization (
print_tree/0,print_tree/1) - All 13 pattern detection predicates
- Both positive (
yes.pl) and negative (no.pl) test cases
This project is developed for academic purposes as part of university coursework.
Built for LINFO2335 - Programming Paradigms @ UCLouvain (Université catholique de Louvain).
Leveraging declarative programming for smarter code analysis