private static bool IsUsedAsByRefParam(IEnumerable<Declaration> declarations, Declaration parameter)
{
// find the procedure calls in the procedure of the parameter.
// note: works harder than it needs to when procedure has more than a single procedure call...
// ...but caching [declarations] would be a memory leak
var items = declarations as List<Declaration> ?? declarations.ToList();
var procedureCalls = items.Where(item => item.DeclarationType.HasFlag(DeclarationType.Member))
.SelectMany(member => member.References.Where(reference => reference.ParentScoping.Equals(parameter.ParentScopeDeclaration)))
.GroupBy(call => call.Declaration)
.ToList(); // only check a procedure once. its declaration doesn't change if it's called 20 times anyway.
foreach (var item in procedureCalls)
{
var calledProcedureArgs = items
.Where(arg => arg.DeclarationType == DeclarationType.Parameter && arg.ParentScope == item.Key.Scope)
.OrderBy(arg => arg.Selection.StartLine)
.ThenBy(arg => arg.Selection.StartColumn)
.ToArray();
for (var i = 0; i < calledProcedureArgs.Count(); i++)
{
if (((VBAParser.ArgContext) calledProcedureArgs[i].Context).BYVAL() != null)
{
continue;
}
foreach (var reference in item)
{
if (reference.Context.Parent is VBAParser.ICS_S_VariableOrProcedureCallContext)
{
// parameterless call (what's this doing here?)
continue;
}
var context = ((dynamic)reference.Context.Parent).argsCall() as VBAParser.ArgsCallContext;
if (context == null)
{
continue;
}
if (parameter.IdentifierName == context.GetText())
{
return true;
}
}
}
}
return false;
}
}