private static bool GetFunction(AstRoot astRoot, ref int position, out FunctionCall functionCall, out Variable functionVariable) { // Note that we do not want just the deepest call since in abc(def()) // when position is over 'def' we actually want signature help for 'abc' // while simple depth search will find 'def'. functionVariable = null; int p = position; functionCall = astRoot.GetSpecificNodeFromPosition <FunctionCall>(p, (x) => { var fc = x as FunctionCall; // Take into account incompleted argument lists line in 'func(a|' return(fc != null && (fc.Arguments.Contains(p) || (fc.CloseBrace == null && fc.Arguments.End == p))); }); if (functionCall == null && position > 0) { // Retry in case caret is at the very end of function signature // that does not have final close brace yet. functionCall = astRoot.GetNodeOfTypeFromPosition <FunctionCall>(position - 1, includeEnd: true); if (functionCall != null) { // But if signature does have closing brace and caret // is beyond it, we are really otuside of the signature. if (functionCall.CloseBrace != null && position >= functionCall.CloseBrace.End) { return(false); } if (position > functionCall.SignatureEnd) { position = functionCall.SignatureEnd; } } } if (functionCall != null && functionCall.Children.Count > 0) { functionVariable = functionCall.Children[0] as Variable; if (functionVariable == null) { // Might be in a namespace var op = functionCall.Children[0] as IOperator; if (op != null && op.OperatorType == OperatorType.Namespace) { functionVariable = op.RightOperand as Variable; } } return(functionVariable != null); } return(false); }
/// <summary> /// Finds the outermost function call from given position. /// In abc(def()) when position is over 'def' finds 'abc' /// </summary> public static bool GetOuterFunction(this AstRoot astRoot, ref int position, out FunctionCall functionCall, out Variable functionVariable) { functionVariable = null; var p = position; functionCall = astRoot.GetSpecificNodeFromPosition <FunctionCall>(p, x => { if (x is FunctionCall fc && fc.OpenBrace.End <= p) { if (fc.CloseBrace != null) { return(p <= fc.CloseBrace.Start); // between ( and ) } // Take into account incomplete argument lists line in 'func(a|' return(fc.Arguments.End == p); } return(false); });