private bool IsMethodVisible(RubyMemberInfo/*!*/ method, RubyModule/*!*/ owner, VisibilityContext visibility, bool foundCallerSelf) {
// Visibility not constrained by a class:
// - call with implicit self => all methods are visible.
// - interop call => only public methods are visible.
if (visibility.Class == null) {
return visibility.IsVisible(method.Visibility);
}
if (method.Visibility == RubyMethodVisibility.Protected) {
// A protected method is visible if the caller's self immediate class is a descendant of the method owner.
if (foundCallerSelf) {
return true;
}
// walk ancestors from caller's self class (visibilityContext)
// until the method owner is found or this module is found (this module is a descendant of the owner):
return visibility.Class.ForEachAncestor((module) => module == owner || module == this);
}
return method.Visibility == RubyMethodVisibility.Public;
}