Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix task completion #152

Merged
merged 4 commits into from
Feb 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,13 @@ static TaskParameterInfo ConvertParameter (IPropertySymbol prop, INamedTypeSymbo

string fullTypeName = propType.GetFullName ();

kind = ValueKindExtensions.FromFullTypeName (fullTypeName);
// strongly type Message.Importance - although public type is string, it errors if it can't cast to MessageImportance
if (prop.Name == "Importance" && type.GetFullName () == "Microsoft.Build.Tasks.Message") {
kind = MSBuildValueKind.Importance;
}
else {
kind = ValueKindExtensions.FromFullTypeName (fullTypeName);
}

if (kind == MSBuildValueKind.Unknown) {
//this usually happens because the type has public members with custom types for testing,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,46 @@ public async Task ProjectChildElementBracketCompletion ()
result.AssertContains ("<!--");
}

[Test]
public async Task TaskCompletion ()
{
var result = await this.GetCompletionContext (@"<Project><Target><$");

result.AssertContains ("<Message");
result.AssertContains ("<Exec");
result.AssertContains ("<Csc");
}

[Test]
public async Task TaskParameterCompletion ()
{
var result = await this.GetCompletionContext (@"<Project><Target><Message $");

result.AssertContains ("Importance");
result.AssertContains ("Text");
result.AssertContains ("HelpKeyword");
result.AssertContains ("Condition");
}

[Test]
public async Task MessageImportanceCompletion ()
{
var result = await this.GetCompletionContext (@"<Project><Target><Message Importance=""$");

result.AssertContains ("High");
result.AssertContains ("Normal");
result.AssertContains ("Low");
}

[Test]
public async Task TaskOutputCompletion ()
{
var result = await this.GetCompletionContext (@"<Project><Target><Csc><Output TaskParameter=""$");

result.AssertContains ("OutputAssembly");
result.AssertContains ("OutputRefAssembly");
}

[Test]
public async Task InferredItems ()
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ public class MSBuildFindReferencesTests
var logger = TestLoggerFactory.CreateLogger (testMethodName);
var doc = MSBuildTestHelpers.CreateEmptyDocument ();
var parseContext = new MSBuildParserContext (
new TestMSBuildEnvironment (), null, null, null, "test.csproj", new PropertyValueCollector (false), null, logger, null, default);
new NullMSBuildEnvironment (), null, null, null, "test.csproj", new PropertyValueCollector (false), null, logger, null, default);
doc.Build (xdoc, parseContext);

var functionTypeProvider = new RoslynFunctionTypeProvider (null, parseContext.Logger);
Expand Down
14 changes: 13 additions & 1 deletion MonoDevelop.MSBuild.Tests.Editor/Mocks/TestMSBuildEnvironment.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,22 @@

using System.ComponentModel.Composition;

using Microsoft.Extensions.Logging;

using MonoDevelop.MSBuild.Editor.Completion;
using MonoDevelop.MSBuild.SdkResolution;

namespace MonoDevelop.MSBuild.Tests.Editor.Mocks
{
// Subclass CurrentProcessMSBuildEnvironment so we get real value for ToolsPath, allowing .tasks and .overridetasks to be found by tests
[Export (typeof (IMSBuildEnvironment))]
class TestMSBuildEnvironment : NullMSBuildEnvironment
[method: ImportingConstructor]
class TestMSBuildEnvironment (MSBuildEnvironmentLogger environmentLogger) : CurrentProcessMSBuildEnvironment(environmentLogger.Logger)
{
// However, suppress resolution of Microsoft.NET.SDK so tests don't use the SDK fallback.
// The SDK fallback substantially slows down the tests and is not necessary for the tests,
// and different versions of the SDK may introduce unexpected values from inference.
public override SdkInfo ResolveSdk ((string name, string version, string minimumVersion) sdk, string projectFile, string solutionPath, ILogger logger = null)
=> null;
}
}
61 changes: 61 additions & 0 deletions MonoDevelop.MSBuild.Tests/DescriptionTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

using MonoDevelop.MSBuild.Language.Typesystem;
using MonoDevelop.MSBuild.Schema;

using NUnit.Framework;

namespace MonoDevelop.MSBuild.Tests;

[TestFixture]
internal class DescriptionTests
{
// soft break, no backticks
[TestCase (
"This is a sentence that is very very very very very very very very long",
"This is a sentence that is very very very very very very..."
)]
// soft break, backticks
[TestCase (
"This is a `sentence` that is `very` very very very very very very very long",
"This is a sentence that is very very very very very very..."
)]
// hard break, no backticks
[TestCase (
"This is a sentence. It is `very` very very very very very very very long",
"This is a sentence"
)]
// hard break, backticks
[TestCase (
"This is a `sentence`. It is `very` very very very very very very very long",
"This is a sentence"
)]
// no break, no backticks, no trailing period
[TestCase (
"This is a sentence",
"This is a sentence"
)]
// no break, backticks, no trailing period
[TestCase (
"This is a `sentence`",
"This is a sentence"
)]
// no break, no backticks, trailing period
[TestCase (
"This is a sentence.",
"This is a sentence"
)]
// no break, backticks, trailing period
[TestCase (
"This is a `sentence`.",
"This is a sentence"
)]
public void TestCompletionHint (string longDescription, string expectedCompletionHint)
{
var symbol = new CustomTypeValue ("foo", longDescription);
var actual = DescriptionFormatter.GetCompletionHint (symbol);

Assert.AreEqual (expectedCompletionHint, actual);
}
}
2 changes: 1 addition & 1 deletion MonoDevelop.MSBuild/CurrentProcessMSBuildEnvironment.cs
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ public CurrentProcessMSBuildEnvironment (ILogger logger)
public IReadOnlyDictionary<string, string[]> ProjectImportSearchPaths { get; }

//FIXME: caching should be specific to the (projectFile, string solutionPath) pair
public SdkInfo ResolveSdk (
public virtual SdkInfo ResolveSdk (
(string name, string version, string minimumVersion) sdk, string projectFile, string solutionPath, ILogger logger = null)
{
var sdkRef = new SdkReference (sdk.name, sdk.version, sdk.minimumVersion);
Expand Down
21 changes: 15 additions & 6 deletions MonoDevelop.MSBuild/Language/MSBuildInferredSchema.cs
Original file line number Diff line number Diff line change
Expand Up @@ -443,7 +443,10 @@ void ExtractReferences (MSBuildValueKind kind, ExpressionNode expression)
break;
case ExpressionText literal:
if (literal.IsPure) {
var value = literal.GetUnescapedValue (true, out _, out _);
var value = literal.GetUnescapedValue (true, out _, out _).Trim ();
if (value.Length == 0) {
continue;
}
switch (kind.WithoutModifiers ()) {
case MSBuildValueKind.ItemName:
CollectItem (value, ReferenceUsage.Unknown);
Expand Down Expand Up @@ -489,7 +492,8 @@ void CollectComparisonProperties (ExpressionNode expression)

// '$(Configuration)'=='Debug')
if (left is ExpressionProperty prop && prop.IsSimpleProperty) {
CollectComparisonProperty (prop, txt.Value);
var value = txt.GetUnescapedValue (true, out _, out _);
CollectComparisonProperty (prop, value);
return;
}

Expand All @@ -501,16 +505,21 @@ left is ConcatExpression concat
&& concat.Nodes[0] is ExpressionProperty p1 && p1.IsSimpleProperty
&& concat.Nodes[2] is ExpressionProperty p2 && p2.IsSimpleProperty
) {
var s = txt.Value.Split ('|');
if (s.Length == 2) {
CollectComparisonProperty (p1, s[0]);
CollectComparisonProperty (p2, s[1]);
var value = txt.GetUnescapedValue (true, out _, out _);
var split = value.Split ('|');
if (split.Length == 2) {
CollectComparisonProperty (p1, split[0]);
CollectComparisonProperty (p2, split[1]);
}
}
}

void CollectComparisonProperty (ExpressionProperty prop, string value)
{
value = value.Trim ();
if (value.Length == 0) {
return;
}
if (string.Equals (prop.Name, "Configuration", StringComparison.OrdinalIgnoreCase)) {
Configurations.Add (value);
} else if (string.Equals (prop.Name, "Platform", StringComparison.OrdinalIgnoreCase)) {
Expand Down
2 changes: 2 additions & 0 deletions MonoDevelop.MSBuild/Language/Syntax/MSBuildAttributeSyntax.cs
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;

using MonoDevelop.MSBuild.Language.Typesystem;

namespace MonoDevelop.MSBuild.Language.Syntax
{
[DebuggerDisplay("MSBuildAttributeSyntax ({SyntaxKind,nq})")]
public class MSBuildAttributeSyntax : MSBuildSyntax
{
public MSBuildAttributeSyntax (
Expand Down
11 changes: 6 additions & 5 deletions MonoDevelop.MSBuild/Language/Syntax/MSBuildElementSyntax.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,15 @@

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;

using MonoDevelop.Xml.Dom;

using MonoDevelop.MSBuild.Language.Typesystem;
using MonoDevelop.Xml.Dom;

namespace MonoDevelop.MSBuild.Language.Syntax
{
[DebuggerDisplay("MSBuildElementSyntax ({SyntaxKind,nq})")]
public class MSBuildElementSyntax : MSBuildSyntax
{
MSBuildElementSyntax[] children = Array.Empty<MSBuildElementSyntax> ();
Expand Down Expand Up @@ -189,19 +190,19 @@ static MSBuildElementSyntax ()
ItemDefinition = AddBuiltin ("ItemDefinition", ElementDescriptions.ItemDefinition, MSBuildSyntaxKind.ItemDefinition, isAbstract: true); // docs don't treat this as distinct from Item in ItemGroup
ItemDefinitionGroup = AddBuiltin ("ItemDefinitionGroup", ElementDescriptions.ItemDefinitionGroup, MSBuildSyntaxKind.ItemDefinitionGroup, helpUrl: HelpUrls.Element_ItemDefinitionGroup);
ItemGroup = AddBuiltin ("ItemGroup", ElementDescriptions.ItemGroup, MSBuildSyntaxKind.ItemGroup, helpUrl: HelpUrls.Element_ItemGroup);
Metadata = AddBuiltin ("Metadata", ElementDescriptions.Metadata, MSBuildSyntaxKind.Metadata, MSBuildValueKind.Unknown, true, helpUrl: HelpUrls.Element_Metadata);
Metadata = AddBuiltin ("Metadata", ElementDescriptions.Metadata, MSBuildSyntaxKind.Metadata, MSBuildValueKind.Unknown, isAbstract: true, helpUrl: HelpUrls.Element_Metadata);
OnError = AddBuiltin ("OnError", ElementDescriptions.OnError, MSBuildSyntaxKind.OnError, helpUrl: HelpUrls.Element_OnError);
Otherwise = AddBuiltin ("Otherwise", ElementDescriptions.Otherwise, MSBuildSyntaxKind.Otherwise, helpUrl: HelpUrls.Element_Otherwise);
Output = AddBuiltin ("Output", ElementDescriptions.Output, MSBuildSyntaxKind.Output, helpUrl: HelpUrls.Element_Output);
Parameter = AddBuiltin ("Parameter", ElementDescriptions.Parameter, MSBuildSyntaxKind.Parameter, isAbstract: true, helpUrl: HelpUrls.Element_Parameter);
ParameterGroup = AddBuiltin ("ParameterGroup", ElementDescriptions.ParameterGroup, MSBuildSyntaxKind.ParameterGroup, helpUrl: HelpUrls.Element_ParameterGroup);
Project = AddBuiltin ("Project", ElementDescriptions.Project, MSBuildSyntaxKind.Project, helpUrl: HelpUrls.Element_Project);
ProjectExtensions = AddBuiltin ("ProjectExtensions", ElementDescriptions.ProjectExtensions, MSBuildSyntaxKind.ProjectExtensions, MSBuildValueKind.Data, helpUrl: HelpUrls.Element_ProjectExtensions);
Property = AddBuiltin ("Property", ElementDescriptions.Property, MSBuildSyntaxKind.Property, MSBuildValueKind.Unknown, true, helpUrl: HelpUrls.Element_Property);
Property = AddBuiltin ("Property", ElementDescriptions.Property, MSBuildSyntaxKind.Property, MSBuildValueKind.Unknown, isAbstract: true, helpUrl: HelpUrls.Element_Property);
PropertyGroup = AddBuiltin ("PropertyGroup", ElementDescriptions.PropertyGroup, MSBuildSyntaxKind.PropertyGroup, helpUrl: HelpUrls.Element_PropertyGroup);
Sdk = AddBuiltin ("Sdk", ElementDescriptions.Sdk, MSBuildSyntaxKind.Sdk, helpUrl: HelpUrls.Element_Sdk);
Target = AddBuiltin ("Target", ElementDescriptions.Target, MSBuildSyntaxKind.Target, helpUrl: HelpUrls.Element_Target);
Task = AddBuiltin ("AbstractTask", ElementDescriptions.Task, MSBuildSyntaxKind.Task, helpUrl: HelpUrls.Element_Task);
Task = AddBuiltin ("AbstractTask", ElementDescriptions.Task, MSBuildSyntaxKind.Task, isAbstract:true, helpUrl: HelpUrls.Element_Task);
TaskBody = AddBuiltin ("Task", ElementDescriptions.TaskBody, MSBuildSyntaxKind.TaskBody, helpUrl: HelpUrls.Element_TaskBody);
UsingTask = AddBuiltin ("UsingTask", ElementDescriptions.UsingTask, MSBuildSyntaxKind.UsingTask, helpUrl: HelpUrls.Element_UsingTask);
When = AddBuiltin ("When", ElementDescriptions.When, MSBuildSyntaxKind.When, helpUrl: HelpUrls.Element_When);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,9 +85,9 @@ public static IReadOnlyList<ConstantSymbol> GetSimpleValues (this MSBuildValueKi
];
case MSBuildValueKind.Importance:
return [
new ("high", "High importance, only displayed for all log verbosity settings", MSBuildValueKind.Importance),
new ("normal", "Normal importance", MSBuildValueKind.Importance),
new ("low", "Low importance, only displayed for highly verbose log settings", MSBuildValueKind.Importance)
new ("High", "High importance, only displayed for all log verbosity settings", MSBuildValueKind.Importance),
new ("Normal", "Normal importance", MSBuildValueKind.Importance),
new ("Low", "Low importance, only displayed for highly verbose log settings", MSBuildValueKind.Importance)
];
case MSBuildValueKind.HostOS:
return [
Expand Down Expand Up @@ -181,9 +181,10 @@ public static MSBuildValueKind FromFullTypeName (string fullTypeName)
return MSBuildValueKind.Float;
case "Microsoft.Build.Framework.ITaskItem":
return MSBuildValueKind.UnknownItem;
case "Microsoft.Build.Framework.MessageImportance":
return MSBuildValueKind.Importance;
}


return MSBuildValueKind.Unknown;
}
}
Expand Down
Loading