diff --git a/src/Microsoft.SqlTools.ServiceLayer/LanguageServices/AutoCompleteHelper.cs b/src/Microsoft.SqlTools.ServiceLayer/LanguageServices/AutoCompleteHelper.cs index df5ea3c9..f23a57b0 100644 --- a/src/Microsoft.SqlTools.ServiceLayer/LanguageServices/AutoCompleteHelper.cs +++ b/src/Microsoft.SqlTools.ServiceLayer/LanguageServices/AutoCompleteHelper.cs @@ -332,7 +332,7 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices /// /// Gets a static instance of an empty completion list to avoid - // unneeded memory allocations + /// unneeded memory allocations /// internal static CompletionItem[] EmptyCompletionList { @@ -342,6 +342,16 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices } } + /// + /// Checks whether a given word is in the reserved + /// word list or not + /// + internal static bool IsReservedWord(string text) + { + int pos = Array.IndexOf(DefaultCompletionText, text.ToLower()); + return pos > -1; + } + /// /// Gets or sets the current workspace service instance /// Setter for internal testing purposes only diff --git a/src/Microsoft.SqlTools.ServiceLayer/LanguageServices/Completion/SqlCompletionItem.cs b/src/Microsoft.SqlTools.ServiceLayer/LanguageServices/Completion/SqlCompletionItem.cs index 39247f34..49e3fd44 100644 --- a/src/Microsoft.SqlTools.ServiceLayer/LanguageServices/Completion/SqlCompletionItem.cs +++ b/src/Microsoft.SqlTools.ServiceLayer/LanguageServices/Completion/SqlCompletionItem.cs @@ -3,6 +3,7 @@ // Licensed under the MIT license. See LICENSE file in the project root for full license information. // +using System; using System.Globalization; using System.Text.RegularExpressions; using Microsoft.SqlServer.Management.SqlParser.Intellisense; @@ -45,7 +46,7 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices.Completion { InsertText = GetCompletionItemInsertName(); Label = DeclarationTitle; - if (StartsWithBracket(TokenText)) + if (StartsWithBracket(TokenText) || AutoCompleteHelper.IsReservedWord(InsertText)) { Label = WithBracket(Label); InsertText = WithBracket(InsertText); @@ -142,7 +143,7 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices.Completion int row, int startColumn, int endColumn) - { + { CompletionItem item = new CompletionItem() { Label = label, diff --git a/test/Microsoft.SqlTools.ServiceLayer.Test/LanguageServer/SqlCompletionItemTests.cs b/test/Microsoft.SqlTools.ServiceLayer.Test/LanguageServer/SqlCompletionItemTests.cs index 727e379d..a1030578 100644 --- a/test/Microsoft.SqlTools.ServiceLayer.Test/LanguageServer/SqlCompletionItemTests.cs +++ b/test/Microsoft.SqlTools.ServiceLayer.Test/LanguageServer/SqlCompletionItemTests.cs @@ -13,6 +13,304 @@ namespace Microsoft.SqlTools.ServiceLayer.Test.LanguageServer { public class SqlCompletionItemTests { + private static readonly string[] ReservedWords = new string[] + { + "all", + "alter", + "and", + "apply", + "as", + "asc", + "at", + "backup", + "begin", + "binary", + "bit", + "break", + "bulk", + "by", + "call", + "cascade", + "case", + "catch", + "char", + "character", + "check", + "checkpoint", + "close", + "clustered", + "column", + "columnstore", + "commit", + "connect", + "constraint", + "continue", + "create", + "cross", + "current_date", + "cursor", + "cursor_close_on_commit", + "cursor_default", + "data", + "data_compression", + "database", + "date", + "datetime", + "datetime2", + "days", + "dbcc", + "dec", + "decimal", + "declare", + "default", + "delete", + "deny", + "desc", + "description", + "disabled", + "disk", + "distinct", + "double", + "drop", + "drop_existing", + "dump", + "dynamic", + "else", + "enable", + "encrypted", + "end", + "end-exec", + "exec", + "execute", + "exists", + "exit", + "external", + "fast_forward", + "fetch", + "file", + "filegroup", + "filename", + "filestream", + "filter", + "first", + "float", + "for", + "foreign", + "from", + "full", + "function", + "geography", + "get", + "global", + "go", + "goto", + "grant", + "group", + "hash", + "hashed", + "having", + "hidden", + "hierarchyid", + "holdlock", + "hours", + "identity", + "identitycol", + "if", + "image", + "immediate", + "include", + "index", + "inner", + "insert", + "instead", + "int", + "integer", + "intersect", + "into", + "isolation", + "join", + "json", + "key", + "language", + "last", + "left", + "level", + "lineno", + "load", + "local", + "locate", + "location", + "login", + "masked", + "maxdop", + "merge", + "message", + "modify", + "move", + "namespace", + "native_compilation", + "nchar", + "next", + "no", + "nocheck", + "nocount", + "nonclustered", + "none", + "norecompute", + "not", + "now", + "null", + "numeric", + "object", + "of", + "off", + "offsets", + "on", + "online", + "open", + "openrowset", + "openxml", + "option", + "or", + "order", + "out", + "outer", + "output", + "over", + "owner", + "partial", + "partition", + "password", + "path", + "percent", + "percentage", + "period", + "persisted", + "plan", + "policy", + "precision", + "predicate", + "primary", + "print", + "prior", + "proc", + "procedure", + "public", + "query_store", + "quoted_identifier", + "raiserror", + "range", + "raw", + "read", + "read_committed_snapshot", + "read_only", + "read_write", + "readonly", + "readtext", + "real", + "rebuild", + "receive", + "reconfigure", + "recovery", + "recursive", + "recursive_triggers", + "references", + "relative", + "remove", + "reorganize", + "required", + "restart", + "restore", + "restrict", + "resume", + "return", + "returns", + "revert", + "revoke", + "rollback", + "rollup", + "row", + "rowcount", + "rowguidcol", + "rows", + "rule", + "sample", + "save", + "schema", + "schemabinding", + "scoped", + "scroll", + "secondary", + "security", + "select", + "send", + "sent", + "sequence", + "server", + "session", + "set", + "sets", + "setuser", + "simple", + "smallint", + "smallmoney", + "snapshot", + "sql", + "standard", + "start", + "started", + "state", + "statement", + "static", + "statistics", + "statistics_norecompute", + "status", + "stopped", + "sysname", + "system", + "system_time", + "table", + "take", + "target", + "then", + "throw", + "time", + "timestamp", + "tinyint", + "to", + "top", + "tran", + "transaction", + "trigger", + "truncate", + "try", + "tsql", + "type", + "uncommitted", + "union", + "unique", + "uniqueidentifier", + "updatetext", + "use", + "user", + "using", + "value", + "values", + "varchar", + "version", + "view", + "waitfor", + "when", + "where", + "while", + "with", + "within", + "without", + "writetext", + "xact_abort", + "xml", + }; + [Fact] public void InsertTextShouldIncludeBracketGivenNameWithSpace() { @@ -132,6 +430,24 @@ namespace Microsoft.SqlTools.ServiceLayer.Test.LanguageServer Assert.Equal(completionItem.Detail, expected); } + [Fact] + public void LabelShouldIncBracketGivenReservedName() + { + foreach (string word in ReservedWords) + { + string declarationTitle = word; + string expected = "[" + declarationTitle + "]"; + DeclarationType declarationType = DeclarationType.Table; + string tokenText = "[]"; + SqlCompletionItem item = new SqlCompletionItem(declarationTitle, declarationType, tokenText); + CompletionItem completionItem = item.CreateCompletionItem(0, 1, 2); + + Assert.Equal(completionItem.Label, expected); + Assert.Equal(completionItem.InsertText, expected); + Assert.Equal(completionItem.Detail, expected); + } + } + [Fact] public void KindShouldBeModuleGivenSchemaDeclarationType() {