public static IEnumerable <CompletionItem> CreateCompletionItemsForProcedures(IEnumerable <FunctionDeclaration> procedures, Node node, Dictionary <SignatureInformation, FunctionDeclaration> functionDeclarationSignatureDictionary, bool enablePublicFlag = true) { var completionItems = new List <CompletionItem>(); foreach (var proc in procedures) { string inputParams = null, outputParams = null, inoutParams = null; if (proc.Profile != null) { if (proc.Profile.InputParameters != null && proc.Profile.InputParameters.Count > 0) { inputParams = string.Format("INPUT {0}", string.Join(", ", proc.Profile.InputParameters.Select( p => string.Format("{0}({1})", p.DataName, p.DataType.Name)))); } if (proc.Profile.InoutParameters != null && proc.Profile.InoutParameters.Count > 0) { inoutParams = string.Format("IN-OUT {0}", string.Join(", ", proc.Profile.InoutParameters.Select( p => string.Format("{0}({1})", p.DataName, p.DataType.Name)))); } if (proc.Profile.OutputParameters != null && proc.Profile.OutputParameters.Count > 0) { outputParams = string.Format("OUTPUT {0}", string.Join(", ", proc.Profile.OutputParameters.Select( p => string.Format("{0}({1})", p.DataName, p.DataType.Name)))); } } bool procIsPublic = false; if (enablePublicFlag) { procIsPublic = ((FunctionDeclarationHeader)proc.CodeElement).Visibility == AccessModifier.Public && !(node.SymbolTable.GetTableFromScope(SymbolTable.Scope.Declarations) .Functions.Values.Any(t => t.Contains(proc)) //Ignore public if proc is in the current program || proc.IsFlagSet(Node.Flag.NodeIsIntrinsic)); //Ignore public if proc is in intrinsic; } var procDisplayName = procIsPublic ? proc.VisualQualifiedName.ToString() : proc.Name; var completionItem = new CompletionItem(string.Format("{0} {1} {2} {3}", procDisplayName, inputParams, inoutParams, outputParams)); completionItem.insertText = procIsPublic ? string.Format("{0}::{1}", proc.VisualQualifiedName.Tail, proc.VisualQualifiedName.Head) : proc.Name; completionItem.kind = proc.Profile != null && proc.Profile.IsFunction ? CompletionItemKind.Function : CompletionItemKind.Method; //Add specific data for eclipse completion & signatureHelper context completionItem.data = new object[3]; var signatureInformation = ProcedureSignatureHelper.SignatureHelperSignatureFormatter(proc); ((object[])completionItem.data)[1] = signatureInformation; //Store the link between the hash and the procedure. This will help to determine the procedure parameter completion context later. functionDeclarationSignatureDictionary.Add(signatureInformation, proc); completionItems.Add(completionItem); } return(completionItems); }
public override SignatureHelp OnSignatureHelp(TextDocumentPosition parameters) { AnalyticsWrapper.Telemetry.TrackEvent("[SignatureHelp]", EventType.Completion); //Send event to analytics var fileCompiler = GetFileCompilerFromStringUri(parameters.uri); if (fileCompiler?.CompilationResultsForProgram?.ProcessedTokensDocumentSnapshot == null) //Semantic snapshot is not available { return(null); } var wrappedCodeElement = CodeElementFinder(fileCompiler, parameters.position).FirstOrDefault(); if (wrappedCodeElement == null) //No codeelements found { return(null); } var node = CompletionFactory.GetMatchingNode(fileCompiler, wrappedCodeElement); //Get procedure name or qualified name string procedureName = CompletionFactoryHelpers.GetProcedureNameFromTokens(wrappedCodeElement.ArrangedConsumedTokens); //Try to get procedure by its name var calledProcedures = node.SymbolTable.GetFunctions( p => p.Name.Equals(procedureName) || p.QualifiedName.ToString().Equals(procedureName), new List <SymbolTable.Scope> { SymbolTable.Scope.Declarations, SymbolTable.Scope.Intrinsic, SymbolTable.Scope.Namespace }); var signatureHelp = new SignatureHelp(); if (calledProcedures == null) { return(null); } if (calledProcedures.Count() == 1) { var calledProcedure = calledProcedures.First(); //Create and return SignatureHelp object signatureHelp.signatures = new SignatureInformation[1]; signatureHelp.signatures[0] = ProcedureSignatureHelper.SignatureHelperSignatureFormatter(calledProcedure); signatureHelp.activeSignature = 0; //Set the active signature as the one just created //Select the current parameter the user is expecting signatureHelp.activeParameter = ProcedureSignatureHelper.SignatureHelperParameterSelecter(calledProcedure, wrappedCodeElement, parameters.position); //There is only one possibility so the context can be set right now _SignatureCompletionContext = calledProcedure; return(signatureHelp); } //Else try to find the best matching signature //Get all given INPUT var givenInputParameters = CompletionFactoryHelpers.AggregateTokens( wrappedCodeElement.ArrangedConsumedTokens.SkipWhile(t => t.TokenType != TokenType.INPUT) .Skip(1) //Ignore the INPUT Token .TakeWhile(t => !(t.TokenType == TokenType.OUTPUT || t.TokenType == TokenType.IN_OUT))).ToList(); //Get all given OUTPUT var givenOutputParameters = CompletionFactoryHelpers.AggregateTokens( wrappedCodeElement.ArrangedConsumedTokens.SkipWhile(t => t.TokenType != TokenType.OUTPUT) .Skip(1) //Ignore the INPUT Token .TakeWhile(t => !(t.TokenType == TokenType.INPUT || t.TokenType == TokenType.IN_OUT))).ToList(); //Get all given INOUT var givenInoutParameters = CompletionFactoryHelpers.AggregateTokens( wrappedCodeElement.ArrangedConsumedTokens.SkipWhile(t => t.TokenType != TokenType.IN_OUT) .Skip(1) //Ignore the INPUT Token .TakeWhile(t => !(t.TokenType == TokenType.OUTPUT || t.TokenType == TokenType.INPUT))).ToList(); var totalGivenParameters = givenInputParameters.Count + givenInoutParameters.Count + givenOutputParameters.Count; var signatureInformation = new List <SignatureInformation>(); _FunctionDeclarationSignatureDictionary.Clear(); FunctionDeclaration bestmatchingProcedure = null; int previousMatchingWeight = 0, selectedSignatureIndex = 0; if (totalGivenParameters == 0) { foreach (var procedure in calledProcedures) //No parameters given, return all possibilities { var formattedSignatureInformation = ProcedureSignatureHelper.SignatureHelperSignatureFormatter(procedure); signatureInformation.Add(formattedSignatureInformation); _FunctionDeclarationSignatureDictionary.Add(formattedSignatureInformation, procedure); } } else { foreach (var procedure in calledProcedures) { //The commented parts allow to restrict the potential compatible signature to return to the client int matchingWeight = 0; //Test INPUT parameters matchingWeight = matchingWeight + ProcedureSignatureHelper.ParametersTester(procedure.Profile.InputParameters, givenInputParameters, node); //Test OUTPUT parameters matchingWeight = matchingWeight + ProcedureSignatureHelper.ParametersTester(procedure.Profile.OutputParameters, givenOutputParameters, node); //Test INOUT parameters matchingWeight = matchingWeight + ProcedureSignatureHelper.ParametersTester(procedure.Profile.InoutParameters, givenInoutParameters, node); if (matchingWeight > 0 && matchingWeight >= previousMatchingWeight && totalGivenParameters > 0) { if (matchingWeight > previousMatchingWeight) { signatureInformation.Clear(); //If the matchingWeight is superior than previous, it means that the previous signature is not precise enough. } var formattedSignatureInformation = ProcedureSignatureHelper.SignatureHelperSignatureFormatter(procedure); signatureInformation.Add(formattedSignatureInformation); _FunctionDeclarationSignatureDictionary.Add(formattedSignatureInformation, procedure); previousMatchingWeight = matchingWeight; bestmatchingProcedure = procedure; } selectedSignatureIndex++; } } signatureHelp.signatures = signatureInformation.ToArray(); if (signatureInformation.Count == 1) { _SignatureCompletionContext = bestmatchingProcedure; //Set the completion context signatureHelp.activeSignature = 0; //Select the only signature for the client signatureHelp.activeParameter = ProcedureSignatureHelper.SignatureHelperParameterSelecter(bestmatchingProcedure, wrappedCodeElement, parameters.position); //Select the current parameter } return(signatureHelp); }