From d273c6cd4cad4d51306abd8d44bb9575d063d69d Mon Sep 17 00:00:00 2001 From: "N. Taylor Mullen" Date: Fri, 14 Apr 2017 11:38:59 -0700 Subject: [PATCH] Ensure output hint descriptors don't schema check. - Prior to this if you had a `TagHelper` whos output hint was not in the final form of the completions we'd fall through into a schema check which resulted in a completion being added when it shouldn't. Example: `TagHelper` for `my-tr` that has an output hint of `tr` would end up getting added to the completion list under `body` because `my-tr` was not in the schema and would then be treated like the `environment` `TagHelper` (a new element). - Added a test to validate that `TagHelper`s with output hints are cross referenced vs. existing completions and do not fall through to a schema check. #1225 --- .../DefaultTagHelperCompletionService.cs | 10 +++--- .../DefaultTagHelperCompletionServiceTest.cs | 36 +++++++++++++++++++ 2 files changed, 42 insertions(+), 4 deletions(-) diff --git a/src/Microsoft.VisualStudio.LanguageServices.Razor/DefaultTagHelperCompletionService.cs b/src/Microsoft.VisualStudio.LanguageServices.Razor/DefaultTagHelperCompletionService.cs index a2d7941879..bf81b9161f 100644 --- a/src/Microsoft.VisualStudio.LanguageServices.Razor/DefaultTagHelperCompletionService.cs +++ b/src/Microsoft.VisualStudio.LanguageServices.Razor/DefaultTagHelperCompletionService.cs @@ -62,11 +62,13 @@ namespace Microsoft.VisualStudio.LanguageServices.Razor { addRuleCompletions = true; } - else if (outputHint != null && elementCompletions.ContainsKey(outputHint)) + else if (outputHint != null) { - // If the possible descriptors final output tag already exists in our list of completions, we should add every representation - // of that descriptor to the possible element completions. - addRuleCompletions = true; + // If the current descriptor has an output hint we need to make sure it shows up only when its output hint would normally show up. + // Example: We have a MyTableTagHelper that has an output hint of "table" and a MyTrTagHelper that has an output hint of "tr". + // If we try typing in a situation like this: | + // We'd expect to only get "my-table" as a completion because the "body" tag doesn't allow "tr" tags. + addRuleCompletions = elementCompletions.ContainsKey(outputHint); } else if (!completionContext.InHTMLSchema(rule.TagName)) { diff --git a/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/DefaultTagHelperCompletionServiceTest.cs b/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/DefaultTagHelperCompletionServiceTest.cs index 0dbc538240..c16b9eca9f 100644 --- a/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/DefaultTagHelperCompletionServiceTest.cs +++ b/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/DefaultTagHelperCompletionServiceTest.cs @@ -10,6 +10,42 @@ namespace Microsoft.VisualStudio.LanguageServices.Razor { public class DefaultTagHelperCompletionServiceTest { + [Fact] + public void GetElementCompletions_TagOutputHintDoesNotFallThroughToSchemaCheck() + { + // Arrange + var documentDescriptors = new[] + { + TagHelperDescriptorBuilder.Create("MyTableTagHelper", "TestAssembly") + .TagMatchingRule(rule => rule.RequireTagName("my-table")) + .TagOutputHint("table") + .Build(), + TagHelperDescriptorBuilder.Create("MyTrTagHelper", "TestAssembly") + .TagMatchingRule(rule => rule.RequireTagName("my-tr")) + .TagOutputHint("tr") + .Build(), + }; + var expectedCompletions = ElementCompletionResult.Create(new Dictionary>() + { + ["my-table"] = new HashSet { documentDescriptors[0] }, + ["table"] = new HashSet(), + }); + + var existingCompletions = new[] { "table" }; + var completionContext = BuildCompletionContext( + documentDescriptors, + existingCompletions, + containingTagName: "body", + containingParentTagName: null); + var service = CreateTagHelperCompletionFactsService(); + + // Act + var completions = service.GetElementCompletions(completionContext); + + // Assert + AssertCompletionsAreEquivalent(expectedCompletions, completions); + } + [Fact] public void GetElementCompletions_CatchAllsOnlyApplyToCompletionsStartingWithPrefix() {