Beispiel #1
0
        private static CompletionResult GetResultFromImportSearch(IImportSearchResult importSearchResult, CompletionContext context, bool prependStar, SourceSpan?applicableSpan = null)
        {
            var document = context.Analysis.Document;
            var mres     = document.Interpreter.ModuleResolution;

            IPythonModule module;

            switch (importSearchResult)
            {
            case ModuleImport moduleImports:
                module = mres.GetImportedModule(moduleImports.FullName);
                break;

            case PossibleModuleImport possibleModuleImport:
                module = mres.GetImportedModule(possibleModuleImport.PossibleModuleFullName);
                break;

            case ImplicitPackageImport _:
                module = null;
                break;

            default:
                return(CompletionResult.Empty);
            }

            var completions = new List <CompletionItem>();

            if (prependStar)
            {
                completions.Add(CompletionItemSource.Star);
            }

            if (module != null)
            {
                completions.AddRange(module.GetMemberNames()
                                     .Where(n => !string.IsNullOrEmpty(n))
                                     .Select(n => context.ItemSource.CreateCompletionItem(n, module.GetMember(n))));
            }

            if (importSearchResult is IImportChildrenSource children)
            {
                foreach (var childName in children.GetChildrenNames())
                {
                    if (!children.TryGetChildImport(childName, out var imports))
                    {
                        continue;
                    }

                    switch (imports)
                    {
                    case ImplicitPackageImport packageImport:
                        completions.Add(CompletionItemSource.CreateCompletionItem(packageImport.Name, CompletionItemKind.Module));
                        break;

                    case ModuleImport moduleImport when !moduleImport.ModulePath.PathEquals(document.FilePath):
                        completions.Add(CompletionItemSource.CreateCompletionItem(moduleImport.Name, CompletionItemKind.Module));
                        break;
                    }
                }
            }

            return(new CompletionResult(completions, applicableSpan));
        }
Beispiel #2
0
        public static CompletionResult GetCompletionsInFromImport(FromImportStatement fromImport, CompletionContext context)
        {
            // No more completions after '*', ever!
            if (fromImport.Names != null && fromImport.Names.Any(n => n?.Name == "*" && context.Position > n.EndIndex))
            {
                return(CompletionResult.Empty);
            }

            var document = context.Analysis.Document;
            var mres     = document.Interpreter.ModuleResolution;

            foreach (var(name, asName) in ZipLongest(fromImport.Names, fromImport.AsNames).Reverse())
            {
                if (asName != null && context.Position >= asName.StartIndex)
                {
                    return(CompletionResult.Empty);
                }

                if (name != null)
                {
                    if (context.Position > name.EndIndex && name.EndIndex > name.StartIndex)
                    {
                        var applicableSpan = context.GetApplicableSpanFromLastToken(fromImport);
                        return(new CompletionResult(Enumerable.Repeat(CompletionItemSource.AsKeyword, 1), applicableSpan));
                    }

                    if (context.Position >= name.StartIndex)
                    {
                        var applicableSpan     = name.GetSpan(context.Ast);
                        var importSearchResult = mres.CurrentPathResolver.FindImports(document.FilePath, fromImport);
                        return(GetResultFromImportSearch(importSearchResult, context, false, applicableSpan));
                    }
                }
            }

            if (fromImport.ImportIndex > fromImport.StartIndex && context.Position > fromImport.ImportIndex + 6)
            {
                var importSearchResult = mres.CurrentPathResolver.FindImports(document.FilePath, fromImport);
                var result             = GetResultFromImportSearch(importSearchResult, context, true);
                if (result != CompletionResult.Empty)
                {
                    return(result);
                }
            }

            if (fromImport.ImportIndex > 0 && context.Position >= fromImport.ImportIndex)
            {
                var applicableSpan = new SourceSpan(
                    context.IndexToLocation(fromImport.ImportIndex),
                    context.IndexToLocation(Math.Min(fromImport.ImportIndex + 6, fromImport.EndIndex))
                    );
                return(new CompletionResult(Enumerable.Repeat(CompletionItemSource.ImportKeyword, 1), applicableSpan));
            }

            if (context.Position > fromImport.Root.EndIndex && fromImport.Root.EndIndex > fromImport.Root.StartIndex)
            {
                SourceSpan?applicableSpan = null;
                if (context.Position > fromImport.EndIndex)
                {
                    // Only end up here for "from ... imp", and "imp" is not counted
                    // as part of our span
                    var token = context.TokenSource.Tokens.LastOrDefault();
                    if (token.Key.End >= context.Position)
                    {
                        applicableSpan = context.TokenSource.GetTokenSpan(token.Key);
                    }
                }

                return(new CompletionResult(Enumerable.Repeat(CompletionItemSource.ImportKeyword, 1), applicableSpan));
            }

            if (context.Position > fromImport.Root.StartIndex && fromImport.Root is RelativeModuleName relativeName)
            {
                var rootNames          = relativeName.Names.Select(n => n.Name);
                var importSearchResult = mres.CurrentPathResolver.GetImportsFromRelativePath(document.FilePath, relativeName.DotCount, rootNames);
                return(GetResultFromImportSearch(importSearchResult, context, false));
            }

            if (fromImport.Root.Names.Count > 1 && context.Position > fromImport.Root.Names[0].EndIndex)
            {
                var rootNames          = fromImport.Root.Names.TakeWhile(n => n.EndIndex < context.Position).Select(n => n.Name);
                var importSearchResult = mres.CurrentPathResolver.GetImportsFromAbsoluteName(document.FilePath, rootNames, fromImport.ForceAbsolute);
                return(GetResultFromImportSearch(importSearchResult, context, false));
            }

            return(context.Position > fromImport.KeywordEndIndex
                ? new CompletionResult(GetAllImportableModules(context))
                : null);
        }
Beispiel #3
0
        public static CompletionResult GetCompletions(ScopeStatement scope, Node statement, Node expression, CompletionContext context)
        {
            if (!(expression is ErrorExpression))
            {
                return(CompletionResult.Empty);
            }

            if (statement is AssignmentStatement assign && expression == assign.Right)
            {
                return(CompletionResult.Empty);
            }

            var tokens = context.TokenSource.Tokens.Reverse().ToArray();
            var es     = new ExpressionSource(context.TokenSource);

            string         code;
            SourceLocation location;
            var            items = Enumerable.Empty <CompletionItem>();
            SourceSpan?    applicableSpan;
            Expression     e;

            var lastToken = tokens.FirstOrDefault();

            if (lastToken.Value == null)
            {
                return(CompletionResult.Empty);
            }

            var nextLast = tokens.ElementAtOrDefault(1).Value?.Kind ?? TokenKind.EndOfFile;

            switch (lastToken.Value.Kind)
            {
            case TokenKind.Dot:
                code           = es.ReadExpression(tokens.Skip(1));
                applicableSpan = new SourceSpan(context.Location, context.Location);
                e     = GetExpressionFromText(code, context, out var s1, out _);
                items = ExpressionCompletion.GetCompletionsFromMembers(e, s1, context);
                break;

            case TokenKind.KeywordDef when lastToken.Key.End < context.Position && scope is FunctionDefinition fd: {
                applicableSpan = new SourceSpan(context.Location, context.Location);
                location       = context.TokenSource.GetTokenSpan(lastToken.Key).Start;
                if (FunctionDefinitionCompletion.TryGetCompletionsForOverride(fd, context, location, out var result))
                {
                    items = result.Completions;
                }

                break;
            }

            case TokenKind.Name when nextLast == TokenKind.Dot:
                code           = es.ReadExpression(tokens.Skip(2));
                applicableSpan = new SourceSpan(context.TokenSource.GetTokenSpan(lastToken.Key).Start, context.Location);
                e     = GetExpressionFromText(code, context, out var s2, out _);
                items = ExpressionCompletion.GetCompletionsFromMembers(e, s2, context);
                break;

            case TokenKind.Name when nextLast == TokenKind.KeywordDef && scope is FunctionDefinition fd: {
                applicableSpan = new SourceSpan(context.TokenSource.GetTokenSpan(lastToken.Key).Start, context.Location);
                location       = context.TokenSource.GetTokenSpan(tokens.ElementAt(1).Key).Start;
                if (FunctionDefinitionCompletion.TryGetCompletionsForOverride(fd, context, location, out var result))
                {
                    items = result.Completions;
                }
                break;
            }

            case TokenKind.KeywordFor:
            case TokenKind.KeywordAs:
                return(lastToken.Key.Start <= context.Position && context.Position <= lastToken.Key.End ? null : CompletionResult.Empty);

            case TokenKind.Error:
                return(null);

            default:
                return(CompletionResult.Empty);
            }

            return(new CompletionResult(items, applicableSpan));
        }
Beispiel #4
0
        public static CompletionResult GetCompletions(Node statement, ScopeStatement scopeStatement, CompletionContext context)
        {
            SourceSpan?applicableSpan = null;
            var        eval           = context.Analysis.ExpressionEvaluator;

            var options = GetOptions(statement, context.Position, out var span);

            if (span.HasValue)
            {
                applicableSpan = new SourceSpan(context.IndexToLocation(span.Value.Start), context.IndexToLocation(span.Value.End));
            }

            var scope = context.Analysis.FindScope(context.Location);
            IEnumerable <CompletionItem> items;

            using (eval.OpenScope(scope)) {
                // Get variables declared in the module.
                var variables = eval.CurrentScope.EnumerateTowardsGlobal.SelectMany(s => s.Variables).ToArray();
                items = variables.Select(v => context.ItemSource.CreateCompletionItem(v.Name, v)).ToArray();
            }

            // Get builtins
            var builtins     = context.Analysis.Document.Interpreter.ModuleResolution.BuiltinsModule;
            var builtinItems = builtins.GetMemberNames()
                               .Select(n => {
                var m = builtins.GetMember(n);
                if ((options & CompletionListOptions.ExceptionsOnly) == CompletionListOptions.ExceptionsOnly && !IsExceptionType(m.GetPythonType()))
                {
                    return(null);
                }
                return(context.ItemSource.CreateCompletionItem(n, m));
            }).ExcludeDefault();

            items = items.Concat(builtinItems);

            // Add possible function arguments.
            var finder = new ExpressionFinder(context.Ast, new FindExpressionOptions {
                Calls = true
            });

            if (finder.GetExpression(context.Position) is CallExpression callExpr && callExpr.GetArgumentAtIndex(context.Ast, context.Position, out _))
            {
                var value = eval.GetValueFromExpression(callExpr.Target);
                if (value?.GetPythonType() is IPythonFunctionType ft)
                {
                    var arguments = ft.Overloads.SelectMany(o => o.Parameters).Select(p => p?.Name)
                                    .Where(n => !string.IsNullOrEmpty(n))
                                    .Distinct()
                                    .Except(callExpr.Args.MaybeEnumerate().Select(a => a.Name).Where(n => !string.IsNullOrEmpty(n)))
                                    .Select(n => CompletionItemSource.CreateCompletionItem($"{n}=", CompletionItemKind.Variable))
                                    .ToArray();

                    items = items.Concat(arguments).ToArray();
                }
            }

            var keywords = GetKeywordItems(context, options, scopeStatement);

            items = items.Concat(keywords);

            return(new CompletionResult(items, applicableSpan));
        }
 public static IEnumerable <CompletionItem> GetCompletionsFromMembers(Expression e, ScopeStatement scope, CompletionContext context)
 {
     using (context.Analysis.ExpressionEvaluator.OpenScope(context.Analysis.Document, scope)) {
         return(GetItemsFromExpression(e, context));
     }
 }
        private static IEnumerable <CompletionItem> GetItemsFromExpression(Expression e, CompletionContext context)
        {
            var value = context.Analysis.ExpressionEvaluator.GetValueFromExpression(e);

            if (!value.IsUnknown())
            {
                var items = new List <CompletionItem>();
                var type  = value.GetPythonType();
                var names = type.GetMemberNames().ToArray();
                foreach (var t in names)
                {
                    var m = type.GetMember(t);
                    if (m is IVariable v && v.Source != VariableSource.Declaration)
                    {
                        continue;
                    }
                    items.Add(context.ItemSource.CreateCompletionItem(t, m, type));
                }
                return(items);
            }
            return(Enumerable.Empty <CompletionItem>());
        }
Beispiel #7
0
 private static CompletionItem ToOverrideCompletionItem(IPythonFunctionOverload o, ClassDefinition cd, CompletionContext context, string indent)
 {
     return(new CompletionItem {
         label = o.Name,
         insertText = MakeOverrideCompletionString(indent, o, cd.Name, context),
         insertTextFormat = InsertTextFormat.PlainText,
         kind = CompletionItemKind.Method
     });
 }
Beispiel #8
0
        private static string MakeOverrideCompletionString(string indentation, IPythonFunctionOverload overload, string className, CompletionContext context)
        {
            var sb = new StringBuilder();

            var first = overload.Parameters.FirstOrDefault();
            var fn    = overload.ClassMember as IPythonFunctionType;
            var skipFirstParameters = fn?.IsStatic == true ? overload.Parameters : overload.Parameters.Skip(1);

            sb.AppendLine(overload.Name + "(" + string.Join(", ", overload.Parameters.Select(p => MakeOverrideParameter(p, p.DefaultValueString))) + "):");
            sb.Append(indentation);

            if (overload.Parameters.Count > 0)
            {
                var parameterString = string.Join(", ", skipFirstParameters.Select(p => MakeOverrideParameter(p, p.Name)));

                if (context.Ast.LanguageVersion.Is3x())
                {
                    sb.AppendFormat("return super().{0}({1})",
                                    overload.Name,
                                    parameterString);
                }
                else if (!string.IsNullOrEmpty(className))
                {
                    sb.AppendFormat("return super({0}, {1}).{2}({3})",
                                    className,
                                    first?.Name ?? string.Empty,
                                    overload.Name,
                                    parameterString);
                }
                else
                {
                    sb.Append("pass");
                }
            }
            else
            {
                sb.Append("pass");
            }

            return(sb.ToString());
        }
        private static IEnumerable <CompletionItem> GetClassItems(IPythonClassType cls, Expression e, CompletionContext context)
        {
            var eval = context.Analysis.ExpressionEvaluator;
            // See if we are completing on self. Note that we may be inside inner function
            // that does not necessarily have 'self' argument so we are looking beyond local
            // scope. We then check that variable type matches the class type, if any.
            var selfVariable     = eval.LookupNameInScopes("self");
            var completingOnSelf = cls.Equals(selfVariable?.GetPythonType()) && e is NameExpression nex && nex.Name == "self";

            var items = new List <CompletionItem>();
            var names = cls.GetMemberNames().ToArray();

            foreach (var t in names)
            {
                var m = cls.GetMember(t);
                if (m is IVariable v && v.Source != VariableSource.Declaration)
                {
                    continue;
                }

                // If this is class member completion, unmangle private member names.
                var unmangledName = cls.UnmangleMemberName(t);
                if (!string.IsNullOrEmpty(unmangledName))
                {
                    // Hide private variables outside of the class scope.
                    if (!completingOnSelf && cls.IsPrivateMember(t))
                    {
                        continue;
                    }
                    items.Add(context.ItemSource.CreateCompletionItem(unmangledName, m, cls));
                }
                else
                {
                    items.Add(context.ItemSource.CreateCompletionItem(t, m, cls));
                }
            }
            return(items);
        }
        public CompletionResult GetCompletions(IDocumentAnalysis analysis, SourceLocation location)
        {
            var context = new CompletionContext(analysis, location, _itemSource);

            ExpressionLocator.FindExpression(analysis.Ast, location,
                                             FindExpressionOptions.Complete, out var expression, out var statement, out var scope);

            switch (expression)
            {
            case MemberExpression me when me.Target != null && me.DotIndex > me.StartIndex && context.Position > me.DotIndex:
                return(new CompletionResult(ExpressionCompletion.GetCompletionsFromMembers(me.Target, scope, context)));

            case ConstantExpression ce1 when ce1.Value is double || ce1.Value is float:
                // no completions on integer ., the user is typing a float
                return(CompletionResult.Empty);

            case ConstantExpression ce2 when ce2.Value is string:
            case ConstantExpression ce3 when ce3.Value is AsciiString:
            // no completions in strings
            case null when context.Ast.IsInsideComment(context.Location):
            case null when context.Ast.IsInsideString(context.Location):
                return(CompletionResult.Empty);
            }

            if (statement is ImportStatement import)
            {
                var result = ImportCompletion.TryGetCompletions(import, context);
                if (result != null)
                {
                    return(result);
                }
            }
            if (statement is FromImportStatement fromImport)
            {
                var result = ImportCompletion.GetCompletionsInFromImport(fromImport, context);
                if (result != null)
                {
                    return(result);
                }
            }

            switch (statement)
            {
            case FunctionDefinition fd when FunctionDefinitionCompletion.TryGetCompletionsForOverride(fd, context, null, out var result):
                return(result);

            case FunctionDefinition fd when FunctionDefinitionCompletion.NoCompletions(fd, context.Position, context.Ast):
                return(CompletionResult.Empty);

            case ClassDefinition cd:
                if (!ClassDefinitionCompletion.NoCompletions(cd, context, out var addMetadataArg))
                {
                    var result = TopLevelCompletion.GetCompletions(statement, scope, context);
                    return(addMetadataArg
                            ? new CompletionResult(result.Completions.Append(CompletionItemSource.MetadataArg), result.ApplicableSpan)
                            : result);
                }
                return(CompletionResult.Empty);

            case ForStatement forStatement when ForCompletion.TryGetCompletions(forStatement, context, out var result):
                return(result);

            case WithStatement withStatement when WithCompletion.TryGetCompletions(withStatement, context, out var result):
                return(result);

            case RaiseStatement raiseStatement when RaiseCompletion.TryGetCompletions(raiseStatement, context, out var result):
                return(result);

            case TryStatementHandler tryStatement when ExceptCompletion.TryGetCompletions(tryStatement, context, out var result):
                return(result);

            default: {
                var result = ErrorExpressionCompletion.GetCompletions(scope, statement, expression, context);
                if (result == null)
                {
                    return(CompletionResult.Empty);
                }
                return(result == CompletionResult.Empty ? TopLevelCompletion.GetCompletions(statement, scope, context) : result);
            }
            }
        }
        private static IReadOnlyList <CompletionItem> GetChildModules(string[] names, CompletionContext context)
        {
            if (!names.Any())
            {
                return(Array.Empty <CompletionItem>());
            }

            var mres     = context.Analysis.Document.Interpreter.ModuleResolution;
            var fullName = string.Join(".", names.Take(names.Length - 1));

            var import = mres.CurrentPathResolver.GetModuleImportFromModuleName(fullName);

            if (string.IsNullOrEmpty(import?.ModulePath))
            {
                return(Array.Empty <CompletionItem>());
            }

            var packages = mres.GetPackagesFromDirectory(Path.GetDirectoryName(import.ModulePath));

            return(packages.Select(n => CompletionItemSource.CreateCompletionItem(n, CompletionItemKind.Module)).ToArray());
        }
        private static string MakeOverrideCompletionString(string indentation, IPythonFunctionOverload overload, string className, CompletionContext context)
        {
            var sb = new StringBuilder();

            var first = overload.Parameters.FirstOrDefault();
            var fn    = overload.ClassMember as IPythonFunctionType;
            var skipFirstParameters = fn?.IsStatic == true ? overload.Parameters : overload.Parameters.Skip(1);

            var addComma  = false;
            var addMarker = false;

            sb.Append(overload.Name);
            sb.Append('(');

            foreach (var p in overload.Parameters)
            {
                if (addComma)
                {
                    sb.Append(", ");
                }
                else
                {
                    addComma = true;
                }

                if (p.Kind == ParameterKind.PositionalOnly)
                {
                    addMarker = true;
                }
                else if (addMarker && p.Kind != ParameterKind.PositionalOnly)
                {
                    sb.Append("/, ");
                    addMarker = false;
                }

                sb.Append(MakeOverrideParameter(p, p.DefaultValueString));
            }

            if (addMarker)
            {
                sb.Append(", /");
            }

            sb.AppendLine("):");
            sb.Append(indentation);

            if (overload.Parameters.Count > 0)
            {
                // Return in __init__ not good practice, only add return statement if overload is not __init__
                if (!overload.Name.Equals("__init__"))
                {
                    sb.Append("return ");
                }

                var parameterString = string.Join(", ", skipFirstParameters.Select(p => MakeOverrideParameter(p, p.Name)));
                if (context.Ast.LanguageVersion.Is3x())
                {
                    sb.AppendFormat("super().{0}({1})",
                                    overload.Name,
                                    parameterString);
                }
                else if (!string.IsNullOrEmpty(className))
                {
                    sb.AppendFormat("super({0}, {1}).{2}({3})",
                                    className,
                                    first?.Name ?? string.Empty,
                                    overload.Name,
                                    parameterString);
                }
                else
                {
                    sb.Append("pass");
                }
            }
            else
            {
                sb.Append("pass");
            }

            return(sb.ToString());
        }
        private static IEnumerable <CompletionItem> GetItemsFromExpression(Expression e, CompletionContext context)
        {
            var eval  = context.Analysis.ExpressionEvaluator;
            var value = eval.GetValueFromExpression(e);

            if (!value.IsUnknown())
            {
                var type = value.GetPythonType();
                if (type is IPythonClassType cls)
                {
                    return(GetClassItems(cls, e, context));
                }

                return(type.GetMemberNames()
                       .Select(name => context.ItemSource.CreateCompletionItem(name, type.GetMember(name), type)));
            }
            return(Enumerable.Empty <CompletionItem>());
        }