Skip to content

Commit

Permalink
Merge pull request #132 from mhutch/update-schemas
Browse files Browse the repository at this point in the history
Docs URLs in tooltips, update schemas, fix warnings
  • Loading branch information
mhutch authored Jan 30, 2024
2 parents 29c2ab3 + 3563b81 commit 486e344
Show file tree
Hide file tree
Showing 88 changed files with 3,546 additions and 1,110 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ public void LoadOrCreate (out bool wasCreated)
}
}
} catch (Exception ex) {
logger.LogError (ex, "Error loading {typeof(T)} settings file");
logger.LogError (ex, $"Error loading {typeof(T)} settings file");
}

value = createDefault ();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,14 @@
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.Linq;
using System.Threading.Tasks;

using Microsoft.Extensions.Logging;
using Microsoft.VisualStudio.Threading;
using Microsoft.VisualStudio.Utilities;

using MonoDevelop.MSBuild.Editor.Completion;
using MonoDevelop.Xml.Logging;

using NuGet.VisualStudio;

Expand All @@ -18,38 +21,61 @@ namespace MonoDevelop.MSBuild.Editor.VisualStudio
[Name ("Visual Studio Package Feed Registry Provider")]
partial class PackageFeedRegistryProvider : IPackageFeedRegistryProvider
{
readonly object gate = new ();
readonly JoinableTaskContext joinableTaskContext;
readonly IVsPackageSourceProvider provider;
readonly ILogger logger;
Task<IReadOnlyList<string>> packageSourcesTask;

[ImportingConstructor]
public PackageFeedRegistryProvider (IVsPackageSourceProvider provider, MSBuildEnvironmentLogger logger)
public PackageFeedRegistryProvider (JoinableTaskContext joinableTaskContext, IVsPackageSourceProvider provider, MSBuildEnvironmentLogger logger)
{
this.joinableTaskContext = joinableTaskContext;
this.provider = provider;
this.logger = logger.Logger;

provider.SourcesChanged += OnSourcesChanged;
OnSourcesChanged (this, EventArgs.Empty);
}

void OnSourcesChanged (object sender, EventArgs e)
{
lock(gate) {
packageSourcesTask = Task.Run (() => GetPackageSourcesAsync ()).WithTaskExceptionLogger (logger);
}
}

async Task<IReadOnlyList<string>> GetPackageSourcesAsync ()
{
// docs for IVsPackageSourceProvider are wrong, in VS 17.3 and later it's no longer thread safe
await joinableTaskContext.Factory.SwitchToMainThreadAsync ();

List<string> sources;
try {
sources = provider.GetSources (true, false).Select (s => s.Value).ToList ();
} catch (Exception ex) {
LogFailedToGetConfiguredSources (logger, ex);
sources = [ "https://api.nuget.org/v3/index.json" ];
}

// make sure we always have the installed package cache as a source
if (!sources.Any (x => x.IndexOf ("\\.nuget", StringComparison.OrdinalIgnoreCase) > -1)) {
sources.Add (Environment.ExpandEnvironmentVariables ("%USERPROFILE%\\.nuget\\packages"));
}

return sources;
}

// TODO: on base interface, make this a "try" method and add the "changed" event
public IReadOnlyList<string> ConfiguredFeeds {
get {
var sources = new List<string> ();

// IVsPackageSourceProvider seems to be broken in 17.3 previews so add a fallback
try {
IEnumerable<KeyValuePair<string, string>> enabledSources = provider.GetSources (true, false);

foreach (KeyValuePair<string, string> curEnabledSource in enabledSources) {
string source = curEnabledSource.Value;
sources.Add (source);
}
} catch (Exception ex) {
LogFailedToGetConfiguredSources (logger, ex);
sources.Add ("https://api.nuget.org/v3/index.json");
}

if (!sources.Any (x => x.IndexOf ("\\.nuget", StringComparison.OrdinalIgnoreCase) > -1)) {
sources.Add (Environment.ExpandEnvironmentVariables ("%USERPROFILE%\\.nuget\\packages"));
if (packageSourcesTask is not null && packageSourcesTask.Status == TaskStatus.RanToCompletion) {
// https://github.com/microsoft/vs-threading/issues/301
#pragma warning disable VSTHRD002 // Avoid problematic synchronous waits
return packageSourcesTask.Result;
#pragma warning restore VSTHRD002 // Avoid problematic synchronous waits
}

return sources;
return Array.Empty<string> ();
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

#nullable enable annotations

using System.Runtime.CompilerServices;
using System.Text;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

#nullable enable annotations

using System;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

#nullable enable annotations

using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

#nullable enable annotations

using System.Runtime.InteropServices;
using Microsoft.VisualStudio.Shell;
using Microsoft.VisualStudio.Shell.Interop;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

#nullable enable annotations

using System;
using System.Runtime.InteropServices;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

#nullable enable annotations

using System;
using System.Threading;
using Microsoft.VisualStudio.ComponentModelHost;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ CompletionItem CreateCompletionItem (MSBuildCompletionDocumentationProvider docu
{
ImageElement image;

if (info is IDeprecatable deprecatable && deprecatable.IsDeprecated) {
if (info.IsDeprecated ()) {
image = provider.DisplayElementFactory.GetImageElement (KnownImages.Deprecated);
} else {
image = provider.DisplayElementFactory.GetImageElement (info);
Expand Down
27 changes: 22 additions & 5 deletions MonoDevelop.MSBuild.Editor/DisplayElementFactory.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

#nullable enable annotations

using System;
using System.Collections.Generic;
using System.ComponentModel.Composition;
Expand Down Expand Up @@ -112,20 +114,35 @@ public async Task<object> GetInfoTooltipElement (ITextBuffer buffer, MSBuildRoot
elements.Add (deprecationElement);
}

if (GetHelpElement (info) is ContainerElement helpElement) {
elements.Add (helpElement);
}

return elements.Count == 1
? elements[0]
: new ContainerElement (ContainerElementStyle.Stacked | ContainerElementStyle.VerticalPadding, elements);
}

ContainerElement GetDeprecationElement (ISymbol info)
{
if (info is IDeprecatable deprecatable && deprecatable.IsDeprecated) {
var msg = string.IsNullOrEmpty (deprecatable.DeprecationMessage) ? "Deprecated" : $"Deprecated: {deprecatable.DeprecationMessage}";
if (info.IsDeprecated (out string? deprecationMessage)) {
var msg = deprecationMessage == "Deprecated"? deprecationMessage : $"Deprecated: {deprecationMessage}";
return GetDiagnosticElement (MSBuildDiagnosticSeverity.Warning, msg);
}
return null;
}

static ContainerElement GetHelpElement (ISymbol info)
{
if (info.HasHelpUrl (out string? helpUrl)) {
return new ContainerElement (
ContainerElementStyle.Wrapped,
new ClassifiedTextElement (CreateWebLink (helpUrl, "Go to documentation"))
);
}
return null;
}

public ClassifiedTextElement GetNameElement (ISymbol info)
{
var label = DescriptionFormatter.GetTitle (info);
Expand Down Expand Up @@ -530,9 +547,7 @@ public object GetPackageInfoTooltip (string packageId, IPackageInfo package, Fee
}

void AddUrlElement (string url, string linkText) => stackedElements.Add (
new ClassifiedTextElement (
new ClassifiedTextRun ("navigableSymbol", linkText, () => Process.Start (url), url)
)
new ClassifiedTextElement (CreateWebLink (url, linkText))
);
}

Expand All @@ -541,6 +556,8 @@ void AddUrlElement (string url, string linkText) => stackedElements.Add (
stackedElements);
}

static ClassifiedTextRun CreateWebLink (string url, string linkText) => new ClassifiedTextRun ("navigableSymbol", linkText, () => Process.Start (url), url);

public object GetDiagnosticTooltip (MSBuildDiagnostic diagnostic) => GetDiagnosticElement (diagnostic.Descriptor.Severity, diagnostic.GetFormattedMessage () ?? diagnostic.GetFormattedTitle ());

ContainerElement GetDiagnosticElement (MSBuildDiagnosticSeverity severity, string message)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -214,7 +214,7 @@ public bool FindReferences (ITextBuffer buffer, MSBuildResolveResult resolveResu

async Task FindReferencesAsync (ITextBuffer buffer, MSBuildResolveResult reference, ILogger logger)
{
var referenceName = reference.GetReferenceName ();
var referenceName = reference.GetReferenceDisplayName ();
var searchCtx = Presenter.StartSearch ($"'{referenceName}' references", referenceName, true);

try {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ QuickInfoItem CreateQuickInfo (ITextSnapshot snapshot, IEnumerable<NavigationAnn
async Task<QuickInfoItem> CreateNuGetQuickInfo (ITextSnapshot snapshot, MSBuildRootDocument doc, MSBuildResolveResult rr, CancellationToken token)
{
IPackageInfo info = null;
var packageId = (string)rr.Reference;
var packageId = rr.GetNuGetIDReference ();

try {
var frameworkId = doc.GetTargetFrameworkNuGetSearchParameter ();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,10 @@ public override Task RegisterRefactoringsAsync (MSBuildRefactoringContext contex

// walk up the scopes in which propertygroups can exist
while (beforeElement?.ParentElement is XElement scope) {
var syntax = MSBuildElementSyntax.Get (scope.Name.FullName);
if (scope.Name.FullName is not string fullName) {
yield break;
}
var syntax = MSBuildElementSyntax.Get (fullName);
if (syntax.IsValidPropertyGroupScope ()) {
var elementsBeforeOffset = scope.ElementsBefore (beforeElement.Span.Start);
if (elementsBeforeOffset.OfSyntax (MSBuildElementSyntax.PropertyGroup).LastOrDefault (n => !n.HasCondition () && !n.IsSelfClosing && n.IsClosed) is XElement existingPg) {
Expand Down
21 changes: 10 additions & 11 deletions MonoDevelop.MSBuild.Editor/Roslyn/RoslynTaskMetadataBuilder.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

#nullable enable annotations

using System;
using System.Collections.Generic;
using System.ComponentModel.Composition;
Expand Down Expand Up @@ -94,21 +96,20 @@ INamedTypeSymbol FindType (INamespaceSymbol ns, string name)
}

var parameters = new Dictionary<string, TaskParameterInfo> (StringComparer.OrdinalIgnoreCase);
GetTaskInfoFromTask (type, logger, parameters, out bool isDeprecated, out string deprecationMessage);
GetTaskInfoFromTask (type, logger, parameters, out string? deprecationMessage);

return new TaskInfo (
type.Name, RoslynHelpers.GetDescription (type),
TaskDeclarationKind.Assembly,
type.GetFullName (),
assemblyName, assemblyFileStr,
declaredInFile, declaredAtOffset,
isDeprecated, deprecationMessage,
deprecationMessage,
parameters);
}

static void GetTaskInfoFromTask (INamedTypeSymbol type, ILogger logger, Dictionary<string, TaskParameterInfo> parameters, out bool isDeprecated, out string deprecationMessage)
static void GetTaskInfoFromTask (INamedTypeSymbol type, ILogger logger, Dictionary<string, TaskParameterInfo> parameters, out string? deprecationMessage)
{
isDeprecated = false;
deprecationMessage = null;

while (type != null) {
Expand All @@ -125,13 +126,12 @@ static void GetTaskInfoFromTask (INamedTypeSymbol type, ILogger logger, Dictiona
}
}

if (!isDeprecated) {
if (deprecationMessage is null) {
foreach (var att in type.GetAttributes ()) {
switch (att.AttributeClass.Name) {
case "ObsoleteAttribute":
if (att.AttributeClass.GetFullName () == "System.ObsoleteAttribute") {
isDeprecated = true;
deprecationMessage = att.ConstructorArguments.FirstOrDefault ().Value as string;
deprecationMessage = (att.ConstructorArguments.FirstOrDefault ().Value as string) ?? "Deprecated";
}
break;
}
Expand All @@ -151,7 +151,7 @@ static void GetTaskInfoFromTask (INamedTypeSymbol type, ILogger logger, Dictiona

static TaskParameterInfo ConvertParameter (IPropertySymbol prop, INamedTypeSymbol type)
{
bool isOutput = false, isRequired = false, isDeprecated = false;
bool isOutput = false, isRequired = false;
string deprecationMessage = null;

foreach (var att in prop.GetAttributes ()) {
Expand All @@ -168,8 +168,7 @@ static TaskParameterInfo ConvertParameter (IPropertySymbol prop, INamedTypeSymbo
break;
case "ObsoleteAttribute":
if (att.AttributeClass.GetFullName () == "System.ObsoleteAttribute") {
isDeprecated = true;
deprecationMessage = att.ConstructorArguments.FirstOrDefault ().Value as string;
deprecationMessage = (att.ConstructorArguments.FirstOrDefault ().Value as string) ?? "Deprecated";
}
break;
}
Expand Down Expand Up @@ -200,7 +199,7 @@ static TaskParameterInfo ConvertParameter (IPropertySymbol prop, INamedTypeSymbo
kind = kind.AsList ();
}

return new TaskParameterInfo (prop.Name, RoslynHelpers.GetDescription (prop), isRequired, isOutput, kind, isDeprecated, deprecationMessage);
return new TaskParameterInfo (prop.Name, RoslynHelpers.GetDescription (prop), isRequired, isOutput, kind, deprecationMessage);
}

Dictionary<(string fileExpr, string asmName, string declaredInFile), (string, IAssemblySymbol)?> resolvedAssemblies
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ public async Task ProjectChildElementBracketCompletion ()
{
var result = await this.GetCompletionContext (@"<Project><$");

result.AssertItemCount (11);
result.AssertItemCount (12);

result.AssertContains ("<PropertyGroup");
result.AssertContains ("<Choose");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,10 +37,11 @@ public class MSBuildFindReferencesTests
var results = new List<(int Offset, int Length, ReferenceUsage Usage)> ();
var collector = MSBuildReferenceCollector.Create (
doc, textDoc,logger,
new MSBuildResolveResult {
new MSBuildResolver.MSBuildMutableResolveResult {
ReferenceKind = kind,
Reference = reference,
}, functionTypeProvider, results.Add);
}.AsImmutable (),
functionTypeProvider, results.Add);
collector.Run (xdoc.RootElement);
return results;
}
Expand Down
4 changes: 2 additions & 2 deletions MonoDevelop.MSBuild.Tests.Editor/MSBuildResolverTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ void AssertReferences (string doc, params (MSBuildReferenceKind kind, object ref
for (int i = 0; i < results.Count; i++) {
var a = results [i];
var e = expected [i];
if (a.result.ReferenceKind != e.kind || !IgnoreCaseEquals (e.kind, a.result.Reference, e.reference)) {
if (a.result.ReferenceKind != e.kind || !IgnoreCaseEquals (e.kind, a.result.GetReferenceForTest (), e.reference)) {
Dump ();
Assert.Fail ($"Index {i}: Expected '{e.kind}'='{FormatName (e.reference)}', got '{a.result.ReferenceKind}'='{FormatNameRR (a.result)}'");
}
Expand All @@ -86,7 +86,7 @@ string FormatName (object reference) {
return reference?.ToString () ?? "[null]";
}

string FormatNameRR (MSBuildResolveResult rr) => FormatName (rr.Reference);
string FormatNameRR (MSBuildResolveResult rr) => FormatName (rr.GetReferenceForTest ());
bool IgnoreCaseEquals (MSBuildReferenceKind kind, object a, object e)
{
if (e is ValueTuple<string,string> et) {
Expand Down
Loading

0 comments on commit 486e344

Please sign in to comment.