Thanks for this library! I've been looking for something like this for a while, and I'm glad I stumbled across it.
There were two issues:
The parent of a nested module would include all of the functions from its nested modules
A nested module wouldn't include any of its functions
The first issue occurred because ModuleInformation.load_user_defined_functions wasn't taking into account nested defmodule statements.
To fix this:
Add a nesting_level to the accumulator when looking for functions.
Switch to using Macro.traverse/4 so that we can properly keep track of the current module nesting level.
Ignore any def statements at nesting level > 1.
The second issue was caused because the modules map in Module.load_user_defined_functions was not using fully-qualified names for the nested modules. As a result, when attempting to find the nested module's functions (which uses the fully-qualified name), the module's AST wasn't found.
To fix this:
Convert the accumulator to include a module stack.
Switch to using Macro.traverse/4 so that we can properly maintain the stack as we enter and exit modules.
Compute the fully-qualified name of any nested module and use that as a key in the modules map.
Note that nested modules can also include defimpls, so we also check for those when looking for functions.
This was the best way I could find to fix the issues with nested modules, but I'm happy to consider better solutions now that I understand the root of the problem.
I ran this version against our codebase and it fixes all of the false positives we had that were caused by this bug.
Fixes #40
Thanks for this library! I've been looking for something like this for a while, and I'm glad I stumbled across it.
There were two issues:
The parent of a nested module would include all of the functions from its nested modules
A nested module wouldn't include any of its functions
The first issue occurred because
ModuleInformation.load_user_defined_functions
wasn't taking into account nesteddefmodule
statements.To fix this:
nesting_level
to the accumulator when looking for functions.Macro.traverse/4
so that we can properly keep track of the current module nesting level.def
statements at nesting level > 1.The second issue was caused because the
modules
map inModule.load_user_defined_functions
was not using fully-qualified names for the nested modules. As a result, when attempting to find the nested module's functions (which uses the fully-qualified name), the module's AST wasn't found.To fix this:
stack
.Macro.traverse/4
so that we can properly maintain the stack as we enter and exit modules.modules
map.Note that nested modules can also include
defimpl
s, so we also check for those when looking for functions.This was the best way I could find to fix the issues with nested modules, but I'm happy to consider better solutions now that I understand the root of the problem.
I ran this version against our codebase and it fixes all of the false positives we had that were caused by this bug.