Skip to content

Commit

Permalink
Merge pull request #221 from mhutch/deprecated-and-introduced-in-version
Browse files Browse the repository at this point in the history
Rework IDeprecatable into IVersionableSymbol
  • Loading branch information
mhutch authored Apr 30, 2024
2 parents 91c4127 + 7f8b9e1 commit 3104707
Show file tree
Hide file tree
Showing 34 changed files with 312 additions and 109 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,10 @@ internal static class ComAggregate
/// will be forwarded to the managed implementation.
/// </summary>
internal static object CreateAggregatedObject (object managedObject)
=> WrapperPolicy.CreateAggregatedObject (managedObject);
{
Shell.ThreadHelper.ThrowIfNotOnUIThread ();
return WrapperPolicy.CreateAggregatedObject (managedObject);
}

/// <summary>
/// Return the RCW for the native IComWrapperFixed instance aggregating "managedObject"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ internal sealed class ComEventSink
{
public static ComEventSink Advise<T>(object obj, T sink) where T : class
{
Shell.ThreadHelper.ThrowIfNotOnUIThread ();

if (!typeof(T).IsInterface)
{
throw new InvalidOperationException();
Expand Down Expand Up @@ -46,6 +48,8 @@ public ComEventSink(IConnectionPoint connectionPoint, uint cookie)

public void Unadvise()
{
Shell.ThreadHelper.ThrowIfNotOnUIThread ();

if (_unadvised)
{
throw new InvalidOperationException("Already unadvised.");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,15 @@ internal static class WrapperPolicy
{
/// <summary>
/// Factory object for creating IComWrapperFixed instances.
/// Internal and not readonly so that unit tests can provide an alternative implementation.
/// </summary>
internal static IComWrapperFactory s_ComWrapperFactory =
(IComWrapperFactory)PackageUtilities.CreateInstance(typeof(IComWrapperFactory).GUID);
static IComWrapperFactory? s_ComWrapperFactory;

internal static object CreateAggregatedObject(object managedObject) => s_ComWrapperFactory.CreateAggregatedObject(managedObject);
internal static object CreateAggregatedObject(object managedObject)
{
ThreadHelper.ThrowIfNotOnUIThread();
s_ComWrapperFactory ??= (IComWrapperFactory)PackageUtilities.CreateInstance (typeof (IComWrapperFactory).GUID);
return s_ComWrapperFactory.CreateAggregatedObject(managedObject);
}

/// <summary>
/// Return the RCW for the native IComWrapperFixed instance aggregating "managedObject"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,8 @@ public int OnNewView (IVsTextView view)

public int RemoveAdornments ()
{
Shell.ThreadHelper.ThrowIfNotOnUIThread ();

_sink.Unadvise ();

return VSConstants.S_OK;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,8 @@ public override IServiceProvider SystemServiceProvider
/// </summary>
internal void Setup()
{
Shell.ThreadHelper.ThrowIfNotOnUIThread ();

this.ComAggregate = CreateComAggregate();

// First, acquire any services we need throughout our lifetime.
Expand All @@ -84,7 +86,10 @@ internal void Setup()
}

private object CreateComAggregate()
=> Interop.ComAggregate.CreateAggregatedObject(this);
{
Shell.ThreadHelper.ThrowIfNotOnUIThread ();
return Interop.ComAggregate.CreateAggregatedObject(this);
}

internal void TearDown()
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,9 +60,11 @@ QuickInfoItem GetQuickInfoItemInternal (IAsyncQuickInfoSession session, Cancella
elements.Add (displayElementFactory.GetDiagnosticTooltip (diagnostic));

var tagSpan = mappingSpan.Span.GetSpans (snapshot).First ();
applicableToSpan = applicableToSpan.HasValue ? applicableToSpan.Value.Overlap (tagSpan) : tagSpan;
applicableToSpan = applicableToSpan.HasValue ? (applicableToSpan.Value.Overlap (tagSpan)?? triggerSpan) : tagSpan;
}

applicableToSpan ??= triggerSpan;

return new QuickInfoItem (
snapshot.CreateTrackingSpan (applicableToSpan.Value, SpanTrackingMode.EdgeExclusive),
new ContainerElement (ContainerElementStyle.Stacked | ContainerElementStyle.VerticalPadding, elements)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
using Microsoft.Extensions.Logging;

using MonoDevelop.MSBuild.Evaluation;
using MonoDevelop.MSBuild.Language;
using MonoDevelop.MSBuild.Language.Expressions;
using MonoDevelop.MSBuild.Language.Typesystem;
using MonoDevelop.MSBuild.Schema;
Expand Down Expand Up @@ -98,13 +99,15 @@ INamedTypeSymbol FindType (INamespaceSymbol ns, string name)
var parameters = new Dictionary<string, TaskParameterInfo> (StringComparer.OrdinalIgnoreCase);
GetTaskInfoFromTask (type, logger, parameters, out string? deprecationMessage);

var versionInfo = deprecationMessage is not null ? SymbolVersionInfo.Deprecated (deprecationMessage) : null;

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

Expand Down Expand Up @@ -205,7 +208,9 @@ static TaskParameterInfo ConvertParameter (IPropertySymbol prop, INamedTypeSymbo
kind = kind.AsList ();
}

return new TaskParameterInfo (prop.Name, RoslynHelpers.GetDescription (prop), isRequired, isOutput, kind, deprecationMessage);
var versionInfo = deprecationMessage is not null ? SymbolVersionInfo.Deprecated (deprecationMessage) : null;

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

Dictionary<(string fileExpr, string asmName, string declaredInFile), (string, IAssemblySymbol)?> resolvedAssemblies
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ Task TestTypeCommands (string filename, string before, string typeChars, string
filename: filename,
initialize: (tv) => {
tv.Options.SetOptionValue ("BraceCompletion/Enabled", true);
return Task.CompletedTask;
}
);
}
Expand Down
8 changes: 0 additions & 8 deletions MonoDevelop.MSBuild/Language/ISymbol.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,6 @@ public interface ISymbol
DisplayText Description { get; }
}

/// <summary>
/// Common interface for symbols that may be deprecated
/// </summary>
public interface IDeprecatable : ISymbol
{
string? DeprecationMessage { get; }
}

/// <summary>
/// Common interface for symbols that are typed
/// </summary>
Expand Down
51 changes: 51 additions & 0 deletions MonoDevelop.MSBuild/Language/IVersionableSymbol.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
// Copyright (c) 2016 Xamarin Inc.
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

using System;

namespace MonoDevelop.MSBuild.Language;

/// <summary>
/// Common interface for symbols that may be deprecated or contain information about when they were introduced
/// </summary>
public interface IVersionableSymbol : ISymbol
{
SymbolVersionInfo? VersionInfo { get; }
}

/// <summary>
/// Contains information about whether a symbol is deprecated and/or when it was introduced.
/// </summary>
/// <param name="DeprecationMessage">If the symbol is deprecated, the deprecation message, otherwise <c>null</c>. Zero-length deprecation messages are not permitted and will be ignored.</param>
/// <param name="DeprecatedInVersion">Optionally indicate the MSBuild version in which it was deprecated. Ignored if <see cref="DeprecationMessage"/> is <c>null</c>.</param>
/// <param name="IntroducedInVersion">Optionally indicate the MSBuild version in which the symbol was introduced.</param>
/// <param name="VersionKind">Indicates what kind of version was provided in <see cref="DeprecatedInVersion"/> and/or <see cref="IntroducedInVersion"/></param>
public record SymbolVersionInfo (string? DeprecationMessage = null, Version? DeprecatedInVersion = null, Version? IntroducedInVersion = null, SymbolVersionKind VersionKind = SymbolVersionKind.MSBuild)
{
public bool IsDeprecated => !string.IsNullOrEmpty (DeprecationMessage); // TODO: ctor should throw on zero length deprecation messages

public static SymbolVersionInfo Deprecated(string deprecationMessage) => new (DeprecationMessage: deprecationMessage);
public static SymbolVersionInfo Deprecated(int majorVersion, int minorVersion, string deprecationMessage) => new (DeprecationMessage: deprecationMessage, DeprecatedInVersion: new Version (majorVersion, minorVersion));

public static SymbolVersionInfo Introduced (int majorVersion, int minorVersion) => new (IntroducedInVersion: new Version(majorVersion, minorVersion));
}

/// <summary>
/// Indicates what kind of version was provided in the <see cref="SymbolVersionInfo"/>
/// </summary>
public enum SymbolVersionKind
{
/// <summary>
/// The symbol was deprecated or introduced in a specific version of MSBuild.
/// </summary>
MSBuild = 0,
/// <summary>
/// NOT SUPPORTED YET. The symbol was deprecated or introduced in a specific version of the .NET SDK.
/// </summary>
DotNetSdk,
/// <summary>
/// NOT SUPPORTED YET. The symbol was deprecated or introduced in a specific version of a NuGet package.
/// </summary>
NuGetPackage
}
24 changes: 12 additions & 12 deletions MonoDevelop.MSBuild/Language/MSBuildDocumentValidator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -63,8 +63,8 @@ void ValidateResolvedElement (XElement element, MSBuildElementSyntax elementSynt
{
CheckDeprecated (elementSyntax, element);

if (elementSymbol != elementSyntax && elementSymbol is IDeprecatable deprecatable) {
CheckDeprecated (deprecatable, element);
if (elementSymbol != elementSyntax && elementSymbol is IVersionableSymbol versionableSymbol) {
CheckDeprecated (versionableSymbol, element);
}

foreach (var rat in elementSyntax.Attributes) {
Expand Down Expand Up @@ -165,18 +165,18 @@ TextSpan[] GetNameSpans (XElement el) => (el.ClosingTag is XClosingTag ct)
}
}

bool CheckDeprecated (IDeprecatable info, INamedXObject namedObj) => CheckDeprecated (info, namedObj.NameSpan);
bool CheckDeprecated (IVersionableSymbol versionableSymbol, INamedXObject namedObj) => CheckDeprecated (versionableSymbol, namedObj.NameSpan);

bool CheckDeprecated (IDeprecatable info, ExpressionNode expressionNode) => CheckDeprecated (info, expressionNode.Span);
bool CheckDeprecated (IVersionableSymbol versionableSymbol, ExpressionNode expressionNode) => CheckDeprecated (versionableSymbol, expressionNode.Span);

bool CheckDeprecated (IDeprecatable info, TextSpan squiggleSpan)
bool CheckDeprecated (IVersionableSymbol versionableSymbol, TextSpan squiggleSpan)
{
if (info.IsDeprecated (out string? deprecationMessage)) {
if (versionableSymbol.IsDeprecated (out string? deprecationMessage)) {
Document.Diagnostics.Add (
CoreDiagnostics.DeprecatedWithMessage,
squiggleSpan,
DescriptionFormatter.GetKindNoun (info),
info.Name,
DescriptionFormatter.GetKindNoun (versionableSymbol),
versionableSymbol.Name,
deprecationMessage
);
return true;
Expand Down Expand Up @@ -479,8 +479,8 @@ void ValidateAttribute (XElement element, XAttribute attribute, MSBuildAttribute
{
CheckDeprecated (attributeSyntax, attribute);

if (attributeSymbol != attributeSyntax && attributeSymbol is IDeprecatable deprecatable) {
CheckDeprecated (deprecatable, attribute);
if (attributeSymbol != attributeSyntax && attributeSymbol is IVersionableSymbol versionableSymbol) {
CheckDeprecated (versionableSymbol, attribute);
}

if (string.IsNullOrWhiteSpace (attribute.Value)) {
Expand Down Expand Up @@ -640,8 +640,8 @@ void VisitPureLiteral (MSBuildElementSyntax elementSymbol, MSBuildAttributeSynta
AddFixableError (CoreDiagnostics.UnknownValue, DescriptionFormatter.GetTitleCaseKindNoun (valueSymbol), valueSymbol.Name, value);
return;
}
if (isKnownValue && knownValue is IDeprecatable deprecatable) {
CheckDeprecated (deprecatable, expressionText);
if (isKnownValue && knownValue is IVersionableSymbol versionableSymbol) {
CheckDeprecated (versionableSymbol, expressionText);
}
}

Expand Down
15 changes: 7 additions & 8 deletions MonoDevelop.MSBuild/Language/MSBuildSymbolExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,25 +14,24 @@ public static class MSBuildSymbolExtensions

public static bool HasDescription (this ISymbol symbol) => !symbol.Description.IsEmpty;

public static bool IsDeprecated (this IDeprecatable symbol) => !string.IsNullOrEmpty (symbol.DeprecationMessage);
public static bool IsDeprecated (this IVersionableSymbol symbol) => symbol.VersionInfo?.IsDeprecated ?? false;

public static bool IsDeprecated (this IDeprecatable symbol, [NotNullWhen (true)] out string? deprecationMessage)
public static bool IsDeprecated (this IVersionableSymbol symbol, [NotNullWhen (true)] out string? deprecationMessage)
{
if (IsDeprecated (symbol)) {
deprecationMessage = symbol.DeprecationMessage;
if (symbol.VersionInfo is SymbolVersionInfo versionInfo && versionInfo.IsDeprecated) {
deprecationMessage = versionInfo.DeprecationMessage;
return true;
}
deprecationMessage = null;
return false;
}

public static bool IsDeprecated (this ISymbol symbol) => symbol is IDeprecatable deprecatable && deprecatable.IsDeprecated ();
public static bool IsDeprecated (this ISymbol symbol) => symbol is IVersionableSymbol versionableSymbol && versionableSymbol.IsDeprecated ();

public static bool IsDeprecated (this ISymbol symbol, [NotNullWhen (true)] out string? deprecationMessage)
{
if (symbol is IDeprecatable deprecatable && deprecatable.IsDeprecated ()) {
deprecationMessage = deprecatable.DeprecationMessage;
return true;
if (symbol is IVersionableSymbol versionableSymbol) {
return versionableSymbol.IsDeprecated (out deprecationMessage);
}
deprecationMessage = null;
return false;
Expand Down
4 changes: 2 additions & 2 deletions MonoDevelop.MSBuild/Language/Syntax/MSBuildAttributeSyntax.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,9 @@ public MSBuildAttributeSyntax (
string name, DisplayText description, MSBuildSyntaxKind syntaxKind, MSBuildValueKind valueKind,
CustomTypeInfo? customType = null,
bool required = false, MSBuildSyntaxKind? abstractKind = null,
string? deprecationMessage = null,
SymbolVersionInfo? versionInfo = null,
string? helpUrl = null)
: base (name, description, valueKind, customType, deprecationMessage, helpUrl)
: base (name, description, valueKind, customType, versionInfo, helpUrl)
{
SyntaxKind = syntaxKind;
Element = element;
Expand Down
7 changes: 4 additions & 3 deletions MonoDevelop.MSBuild/Language/Syntax/MSBuildElementSyntax.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
using System.Linq;

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

namespace MonoDevelop.MSBuild.Language.Syntax
Expand All @@ -34,8 +35,8 @@ public class MSBuildElementSyntax : MSBuildSyntax
string name, DisplayText description, MSBuildSyntaxKind syntaxKind,
MSBuildValueKind valueKind = MSBuildValueKind.Nothing,
CustomTypeInfo? customType = null,
bool isAbstract = false, string deprecationMessage = null, string helpUrl = null, string attributesHelpUrl = null)
: base (name, description, valueKind, customType, deprecationMessage, helpUrl)
bool isAbstract = false, SymbolVersionInfo? versionInfo = null, string helpUrl = null, string? attributesHelpUrl = null)
: base (name, description, valueKind, customType, versionInfo, helpUrl)
{
SyntaxKind = syntaxKind;
IsAbstract = isAbstract;
Expand Down Expand Up @@ -275,7 +276,7 @@ static MSBuildElementSyntax ()
new (Project, "InitialTargets", ElementDescriptions.Project_InitialTargets, MSBuildSyntaxKind.Project_InitialTargets, MSBuildValueKind.TargetName.AsList ().AsLiteral (),
helpUrl: "https://learn.microsoft.com/en-us/visualstudio/msbuild/target-build-order#initial-targets"
),
new (Project, "ToolsVersion", ElementDescriptions.Project_ToolsVersion, MSBuildSyntaxKind.Project_ToolsVersion, MSBuildValueKind.ToolsVersion.AsLiteral (), deprecationMessage: "Ignored in modern MSBuild projects"),
new (Project, "ToolsVersion", ElementDescriptions.Project_ToolsVersion, MSBuildSyntaxKind.Project_ToolsVersion, MSBuildValueKind.ToolsVersion.AsLiteral (), versionInfo: MSBuildIntrinsics.ToolsVersionDeprecatedInfo, helpUrl: HelpUrls.Element_Project_ToolsVersion),
new (Project, "TreatAsLocalProperty", ElementDescriptions.Project_TreatAsLocalProperty, MSBuildSyntaxKind.Project_TreatAsLocalProperty, MSBuildValueKind.PropertyName.AsList ().AsLiteral ()),
new (Project, "xmlns", ElementDescriptions.Project_xmlns, MSBuildSyntaxKind.Project_xmlns, MSBuildValueKind.Xmlns.AsLiteral ()),
new (Project, "Sdk", ElementDescriptions.Project_Sdk, MSBuildSyntaxKind.Project_Sdk, MSBuildValueKind.SdkWithVersion.AsList().AsLiteral ()),
Expand Down
10 changes: 6 additions & 4 deletions MonoDevelop.MSBuild/Language/Syntax/MSBuildSyntax.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,23 @@

#nullable enable

using System;

using MonoDevelop.MSBuild.Language.Typesystem;

namespace MonoDevelop.MSBuild.Language.Syntax;

public abstract class MSBuildSyntax : ISymbol, ITypedSymbol, IDeprecatable, IHasHelpUrl
public abstract class MSBuildSyntax : ISymbol, ITypedSymbol, IVersionableSymbol, IHasHelpUrl
{
protected MSBuildSyntax (
string name, DisplayText description, MSBuildValueKind valueKind = MSBuildValueKind.Unknown,
CustomTypeInfo? customType = null,
string? deprecationMessage = null,
SymbolVersionInfo? versionInfo = null,
string? helpUrl = null)
{
Name = name;
Description = description;
DeprecationMessage = deprecationMessage;
VersionInfo = versionInfo;
HelpUrl = helpUrl;

ValueKind = valueKind;
Expand All @@ -30,6 +32,6 @@ protected MSBuildSyntax (

public virtual MSBuildValueKind ValueKind { get; }
public CustomTypeInfo? CustomType { get; }
public string? DeprecationMessage { get; }
public SymbolVersionInfo? VersionInfo { get; }
public virtual string? HelpUrl { get; }
}
3 changes: 3 additions & 0 deletions MonoDevelop.MSBuild/Language/Typesystem/ConstantSymbol.cs
Original file line number Diff line number Diff line change
@@ -1,11 +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;

namespace MonoDevelop.MSBuild.Language.Typesystem
{
/// <summary>
/// Describes a constant's name and type (but not its value)
/// </summary>
[DebuggerDisplay("ConstantSymbol({Name},nq)")]
public class ConstantSymbol : BaseSymbol, ITypedSymbol
{
public ConstantSymbol (string name, DisplayText description, MSBuildValueKind kind) : base (name, description)
Expand Down
2 changes: 2 additions & 0 deletions MonoDevelop.MSBuild/Language/Typesystem/CustomTypeInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,11 @@
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Diagnostics;

namespace MonoDevelop.MSBuild.Language.Typesystem
{
[DebuggerDisplay("CustomTypeInfo({Name},nq)")]
public sealed class CustomTypeInfo
{
public CustomTypeInfo (
Expand Down
Loading

0 comments on commit 3104707

Please sign in to comment.