Add StrictModuleDirectiveScope check
Summary
This PR adds a new opt-in readability check StrictModuleDirectiveScope that encourages declaring module directives (alias, require, import, use) at the module level rather than inside function bodies.
Closes #1222
Motivation
Inline directives can make code harder to follow and obscure module dependencies. By requiring all directives at the module level, readers can quickly understand a module's dependencies by looking at the top of the file.
This addresses the need described in #1222 for teams that value explicit, discoverable dependencies over tightly-scoped imports.
Implementation
The check detects directives in:
- All function types (def, defp, defmacro, defmacrop)
- All control structures (if/unless/case/cond/with/try)
- Anonymous functions
- For comprehensions
Configuration Options
-
directives- List of directive types to check (default: all four) -
allow_in_private_functions- Skip checking private functions (default: false) -
allow_in_test_macros- Skip checking test blocks (default: true) -
allow_in_quote_blocks- Skip checking quote blocks (default: true) -
exclude_functions- Regex patterns to exclude specific functions
Example
# Will trigger issue
defmodule MyModule do
def process_data(data) do
alias MyApp.DataProcessor
DataProcessor.process(data)
end
end
# Preferred style
defmodule MyModule do
alias MyApp.DataProcessor
def process_data(data) do
DataProcessor.process(data)
end
end
Configuration Example
# In .credo.exs
{Credo.Check.Readability.StrictModuleDirectiveScope, [
directives: [:alias, :require], # Only check these two
allow_in_private_functions: true,
exclude_functions: [~r/^render/] # Allow in LiveView render functions
]}
Test Coverage
- 37 test cases covering all directive types, control structures, and configuration options
- Tests for real-world patterns (LiveView, ExUnit test blocks)
- Edge case handling (anonymous functions, comprehensions, nested structures)
Checklist
- [x] Implementation follows Credo check patterns
- [x] Comprehensive test suite with 37+ test cases
- [x] Check registered in .credo.exs as disabled/opt-in
- [x] Extensive documentation with rationale and examples
- [x] Marked as controversial (disabled by default)
- [x] Configuration examples provided
Trying to discuss this in #1222 - surprised there is a PR for it already.
Out of curiosity: Did you AI generate this?