microsoft / vssdk-analyzers Goto Github PK
View Code? Open in Web Editor NEWRoslyn analyzers for Visual Studio extensions
License: MIT License
Roslyn analyzers for Visual Studio extensions
License: MIT License
On my machine I moved nuget globalPackagesFolder to a non SSD drive and unit tests were failing since they were looking for packages in user profile. As of yet I couldn't find a reliable way to get the globalPackagesFolder though since it can be set from multiple locations.
VS IDE - Microsoft Visual Studio Enterprise 2019 Preview
Version 16.6.0 Preview 4.0
System.TypeInitializationException : The type initializer for 'Microsoft.VisualStudio.SDK.Analyzers.VSSDK001DeriveFromAsyncPackageCodeFix' threw an exception. ---> System.FieldAccessException : Attempt by method 'Microsoft.VisualStudio.SDK.Analyzers.VSSDK001DeriveFromAsyncPackageCodeFix..cctor()' to access field 'Microsoft.VisualStudio.SDK.Analyzers.VSSDK001DeriveFromAsyncPackageAnalyzer.Descriptor' failed.
at Microsoft.VisualStudio.SDK.Analyzers.VSSDK001DeriveFromAsyncPackageCodeFix..cctor()
--- End of inner exception stack trace ---
at Microsoft.VisualStudio.SDK.Analyzers.VSSDK001DeriveFromAsyncPackageCodeFix.get_FixableDiagnosticIds()
at Microsoft.CodeAnalysis.CodeFixes.CodeFixService.GetAndTestFixableDiagnosticIds(CodeFixProvider codeFixProvider)
at Microsoft.CodeAnalysis.CodeFixes.CodeFixService.<>c.b__29_2(CodeFixProvider f)
at System.Collections.Immutable.ImmutableInterlocked.GetOrAdd[TKey,TValue](ImmutableDictionary2& location,TKey key,Func
2 valueFactory)
at Microsoft.CodeAnalysis.CodeFixes.CodeFixService.<>c__DisplayClass29_0.b__0()
at Microsoft.CodeAnalysis.Extensions.IExtensionManagerExtensions.PerformFunction[T](IExtensionManager extensionManager,Object extension,Func`1 function,T defaultValue)
Should we call out specific calls to the DTE when there are better and safer alternative APIs elsewhere?
VS IDE - Microsoft Visual Studio Enterprise 2019 Preview
Version 16.6.0 Preview 4.0
Stack Trace -
System.TypeInitializationException : The type initializer for 'Microsoft.VisualStudio.SDK.Analyzers.VSSDK006CheckServicesExistCodeFix' threw an exception. ---> System.FieldAccessException : Attempt by method 'Microsoft.VisualStudio.SDK.Analyzers.VSSDK006CheckServicesExistCodeFix..cctor()' to access field 'Microsoft.VisualStudio.SDK.Analyzers.VSSDK006CheckServicesExistAnalyzer.Descriptor' failed.
at Microsoft.VisualStudio.SDK.Analyzers.VSSDK006CheckServicesExistCodeFix..cctor()
--- End of inner exception stack trace ---
at Microsoft.VisualStudio.SDK.Analyzers.VSSDK006CheckServicesExistCodeFix.get_FixableDiagnosticIds()
at Microsoft.CodeAnalysis.CodeFixes.CodeFixService.GetAndTestFixableDiagnosticIds(CodeFixProvider codeFixProvider)
at Microsoft.CodeAnalysis.CodeFixes.CodeFixService.<>c.b__29_2(CodeFixProvider f)
at System.Collections.Immutable.ImmutableInterlocked.GetOrAdd[TKey,TValue](ImmutableDictionary2& location,TKey key,Func
2 valueFactory)
at Microsoft.CodeAnalysis.CodeFixes.CodeFixService.<>c__DisplayClass29_0.b__0()
at Microsoft.CodeAnalysis.Extensions.IExtensionManagerExtensions.PerformFunction[T](IExtensionManager extensionManager,Object extension,Func`1 function,T defaultValue)
On a Windows 10 PC with VS 2019 16.9.4 and .NET SDK 5.0.202 installed, I checked out the latest commit (ad578df as of 10-May-21), ran the init.ps1
script, then dotnet build
(0 warnings, 0 errors), and then dotnet test
. This produced many errors like this:
error CS0012: The type 'Object' is defined in an assembly that is not referenced.
You must add a reference to assembly 'mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'.
(And variations of the above for System.Void
, System.Int32
, System.Type
, etc)
and:
error CS0234: The type or namespace name 'Task' does not exist in the namespace 'System.Threading.Tasks' (are you missing an assembly reference?)
DiagnosticResult.CompilerError("CS0234").WithSpan(6, 37, 6, 41).WithArguments("Task", "System.Threading.Tasks"),
Total:
Failed: 81, Passed: 1, Skipped: 0, Total: 82, Duration: 54 s
(The one test that passes is AssemblyHasNoReferenceToMpf.)
See screenshot below for more details.
init.ps1
scriptdotnet build
dotnet test
(or dotnet test -f net472
)Or after step 2, open the solution in Visual Studio 2019 16.9.4 and then build, then run the tests in the Test Explorer.
The tests should all pass (according to the Azure builds).
I can get most of the tests to pass by explicitly adding metadata references in the Test
ctor (CSharpCodeFixVerifier`2.cs line 77), like this:
this.SolutionTransforms.Add((solution, projectId) =>
{
Project? project = solution.GetProject(projectId);
project = project?.AddMetadataReference(MetadataReference.CreateFromFile(typeof(object).Assembly.Location));
project = project?.AddMetadataReference(MetadataReference.CreateFromFile(typeof(System.ComponentModel.Design.IServiceContainer).Assembly.Location));
project = project?.AddMetadataReference(PresentationFrameworkReference);
if (project == null)
{
throw new System.NullReferenceException(nameof(project));
}
return project.Solution;
});
But some of the VSSDK006 tests still fail with this error:
error CS0012: The type 'Object' is defined in an assembly that is not referenced. You must add a reference to assembly 'netstandard, Version=2.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51'.
DiagnosticResult.CompilerError("CS0012").WithSpan(11, 17, 11, 24).WithArguments("System.Object", "netstandard, Version=2.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51"),
It's unclear why some VSSDK006 tests pass and others don't. E.g. LocalAssigned_GetService_ThenUsedAsync
fails with that error, but LocalAssigned_GetService_ThenUsed_WithNullConditionalAsync
passes.
New total with above workaround:
Failed: 17, Passed: 65, Skipped: 0, Total: 82, Duration: 1 m 4 s
This could deadlock VS according to @AlexEyler
A clear and concise description of what the bug is.
Warning VSSDK006 Check whether the result of GetService calls is null.
Sample code:
var item = provider.GetService(typeof(EnvDTE.ProjectItem)) as EnvDTE.ProjectItem; // <<< warning here
return (item != null) ? item.ContainingProject : null;
No error since checking item for null is present.
This code works fine:
var item = provider.GetService(typeof(EnvDTE.ProjectItem)) as EnvDTE.ProjectItem; // <<< no warning here
if (item != null)
return null;
return item.ContainingProject;
VS IDE - Microsoft Visual Studio Enterprise 2019 Preview
Version 16.6.0 Preview 4.0
Stack Trace -
System.TypeInitializationException : The type initializer for 'Microsoft.VisualStudio.SDK.Analyzers.VSSDK002PackageRegistrationMatchesBaseTypeCodeFix' threw an exception. ---> System.FieldAccessException : Attempt by method 'Microsoft.VisualStudio.SDK.Analyzers.VSSDK002PackageRegistrationMatchesBaseTypeCodeFix..cctor()' to access field 'Microsoft.VisualStudio.SDK.Analyzers.VSSDK002PackageRegistrationMatchesBaseTypeAnalyzer.Descriptor' failed.
at Microsoft.VisualStudio.SDK.Analyzers.VSSDK002PackageRegistrationMatchesBaseTypeCodeFix..cctor()
--- End of inner exception stack trace ---
at Microsoft.VisualStudio.SDK.Analyzers.VSSDK002PackageRegistrationMatchesBaseTypeCodeFix.get_FixableDiagnosticIds()
at Microsoft.CodeAnalysis.CodeFixes.CodeFixService.GetAndTestFixableDiagnosticIds(CodeFixProvider codeFixProvider)
at Microsoft.CodeAnalysis.CodeFixes.CodeFixService.<>c.b__29_2(CodeFixProvider f)
at System.Collections.Immutable.ImmutableInterlocked.GetOrAdd[TKey,TValue](ImmutableDictionary2& location,TKey key,Func
2 valueFactory)
at Microsoft.CodeAnalysis.CodeFixes.CodeFixService.<>c__DisplayClass29_0.b__0()
at Microsoft.CodeAnalysis.Extensions.IExtensionManagerExtensions.PerformFunction[T](IExtensionManager extensionManager,Object extension,Func`1 function,T defaultValue)
As @madskristensen reports, installing the nuget package built by this repo into a packages.config-based project does not get the analyzers defined in this project.
Are the install.ps1/uninstall.ps1 scripts missing or broken?
the analyzer doesn't stop complaining even though the GetAsyncToolWindowFactory() method is there.
see Screenshots here:
https://github.com/AdmiralSnyder/ErrorRepros#20220216---the-analyzer-that-wants-me-to-asynchronously-create-tool-windows-doesnt-stop-whining
see repro here:
https://github.com/AdmiralSnyder/ErrorRepros/tree/master/20220216_AsyncPackage_AsyncToolWindow/VsixProjectWithToolWindowCommunity
Version of the vssdk-analyzers:
Since i just updated VS to 17.2 preview 1, and it crashes in NormalizePath, i cannot really tell you which SDK analyzer version i'm running ( guess the latest, though) - maybe the screenshot will help
Analyzer rule:
Support async tool windows
Error (exception message, type, and callstack where applicable):
Steps or code to reproduce the behavior:
the analyzer should not complain anymore
There are potentially problems when extensions share Microsoft.VisualStudio.Shell.* types. This can lead to problems in the future.
Async packages that proffer services through their (synchronous) service providers result in the package not loading asynchronously even when that service is queried for using QueryServiceAsync
.
All services from an AsyncPackage
should be proffered with the IsAsyncQueryable
flag and registered with a Task-returning service factory (even if the factory itself is implemented synchronously) to ensure the package is loaded asynchronously.
ported from dotnet/roslyn#54264
Stack Trace:
System.TypeInitializationException : The type initializer for 'Microsoft.VisualStudio.SDK.Analyzers.VSSDK001DeriveFromAsyncPackageCodeFix' threw an exception. ---> System.FieldAccessException : Attempt by method 'Microsoft.VisualStudio.SDK.Analyzers.VSSDK001DeriveFromAsyncPackageCodeFix..cctor()' to access field 'Microsoft.VisualStudio.SDK.Analyzers.VSSDK001DeriveFromAsyncPackageAnalyzer.Descriptor' failed.
at Microsoft.VisualStudio.SDK.Analyzers.VSSDK001DeriveFromAsyncPackageCodeFix..cctor()
--- End of inner exception stack trace ---
at Microsoft.VisualStudio.SDK.Analyzers.VSSDK001DeriveFromAsyncPackageCodeFix.get_FixableDiagnosticIds()
at Microsoft.CodeAnalysis.CodeFixes.CodeFixService.GetAndTestFixableDiagnosticIds(CodeFixProvider codeFixProvider)
at Microsoft.CodeAnalysis.CodeFixes.CodeFixService.<>c.b__37_2(CodeFixProvider f)
at System.Collections.Immutable.ImmutableInterlocked.GetOrAdd[TKey,TValue](ImmutableDictionary2& location,TKey key,Func
2 valueFactory)
at Microsoft.CodeAnalysis.CodeFixes.CodeFixService.<>c__DisplayClass37_0.b__0()
at Microsoft.CodeAnalysis.Extensions.IExtensionManagerExtensions.PerformFunction[T](IExtensionManager extensionManager,Object extension,Func`1 function,T defaultValue)
VSSDK001, 002, and 006 all failed simultaneously with roughly the same error.
It happened in an already opened solution.
vssdk-analyzers version: 16.3.2
System.TypeInitializationException : The type initializer for 'Microsoft.VisualStudio.SDK.Analyzers.VSSDK001DeriveFromAsyncPackageCodeFix' threw an exception. ---> System.FieldAccessException : Attempt by method 'Microsoft.VisualStudio.SDK.Analyzers.VSSDK001DeriveFromAsyncPackageCodeFix..cctor()' to access field 'Microsoft.VisualStudio.SDK.Analyzers.VSSDK001DeriveFromAsyncPackageAnalyzer.Descriptor' failed.
at Microsoft.VisualStudio.SDK.Analyzers.VSSDK001DeriveFromAsyncPackageCodeFix..cctor()
--- End of inner exception stack trace ---
at Microsoft.VisualStudio.SDK.Analyzers.VSSDK001DeriveFromAsyncPackageCodeFix.get_FixableDiagnosticIds()
at Microsoft.CodeAnalysis.CodeFixes.CodeFixService.GetAndTestFixableDiagnosticIds(CodeFixProvider codeFixProvider)
at Microsoft.CodeAnalysis.CodeFixes.CodeFixService.<>c.<GetFixableDiagnosticIds>b__27_2(CodeFixProvider f)
at System.Collections.Immutable.ImmutableInterlocked.GetOrAdd[TKey,TValue](ImmutableDictionary`2& location,TKey key,Func`2 valueFactory)
at Microsoft.CodeAnalysis.CodeFixes.CodeFixService.<>c__DisplayClass27_0.<GetFixableDiagnosticIds>b__0()
at Microsoft.CodeAnalysis.Extensions.IExtensionManagerExtensions.PerformFunction[T](IExtensionManager extensionManager,Object extension,Func`1 function,T defaultValue)
We should have an analyzer (preferably with a code fix provider) to find tool windows that initialize synchronously and encourage support for async tool windows when targeting a VS version that supports them.
The spec for async tool windows is here. The diff for the update from sync to async tool windows is roughly this:
diff --git a/VSIXProject9/ToolWindow1.cs b/VSIXProject9/ToolWindow1.cs
index 9d0a240..eb43f28 100644
--- a/VSIXProject9/ToolWindow1.cs
+++ b/VSIXProject9/ToolWindow1.cs
@@ -30,5 +30,10 @@
// the object returned by the Content property.
this.Content = new ToolWindow1Control();
}
+
+ public ToolWindow1(string message)
+ : this()
+ {
+ }
}
}
diff --git a/VSIXProject9/ToolWindow1Command.cs b/VSIXProject9/ToolWindow1Command.cs
index 16dfe90..082dcec 100644
--- a/VSIXProject9/ToolWindow1Command.cs
+++ b/VSIXProject9/ToolWindow1Command.cs
@@ -24,14 +24,14 @@ namespace VSIXProject9
/// <summary>
/// VS Package that provides this command, not null.
/// </summary>
- private readonly Package package;
+ private readonly AsyncPackage package;
/// <summary>
/// Initializes a new instance of the <see cref="ToolWindow1Command"/> class.
/// Adds our command handlers for menu (commands must exist in the command table file)
/// </summary>
/// <param name="package">Owner package, not null.</param>
- private ToolWindow1Command(Package package)
+ private ToolWindow1Command(AsyncPackage package)
{
this.package = package ?? throw new ArgumentNullException("package");
@@ -67,7 +67,7 @@ namespace VSIXProject9
/// Initializes the singleton instance of the command.
/// </summary>
/// <param name="package">Owner package, not null.</param>
- public static void Initialize(Package package)
+ public static void Initialize(AsyncPackage package)
{
Instance = new ToolWindow1Command(package);
}
@@ -82,14 +82,17 @@ namespace VSIXProject9
// Get the instance number 0 of this tool window. This window is single instance so this instance
// is actually the only one.
// The last flag is set to true so that if the tool window does not exists it will be created.
- ToolWindowPane window = this.package.FindToolWindow(typeof(ToolWindow1), 0, true);
- if ((null == window) || (null == window.Frame))
+ this.package.JoinableTaskFactory.RunAsync(async delegate
{
- throw new NotSupportedException("Cannot create tool window");
- }
+ ToolWindowPane window = await this.package.ShowToolWindowAsync(typeof(ToolWindow1), 0, true, this.package.DisposalToken);
+ if ((null == window) || (null == window.Frame))
+ {
+ throw new NotSupportedException("Cannot create tool window");
+ }
- IVsWindowFrame windowFrame = (IVsWindowFrame)window.Frame;
- Microsoft.VisualStudio.ErrorHandler.ThrowOnFailure(windowFrame.Show());
+ IVsWindowFrame windowFrame = (IVsWindowFrame)window.Frame;
+ Microsoft.VisualStudio.ErrorHandler.ThrowOnFailure(windowFrame.Show());
+ });
}
}
}
diff --git a/VSIXProject9/ToolWindow1Package.cs b/VSIXProject9/ToolWindow1Package.cs
index de311f3..6875ef0 100644
--- a/VSIXProject9/ToolWindow1Package.cs
+++ b/VSIXProject9/ToolWindow1Package.cs
@@ -4,11 +4,14 @@ using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.Runtime.InteropServices;
+using System.Threading;
+using System.Threading.Tasks;
using Microsoft.VisualStudio;
using Microsoft.VisualStudio.OLE.Interop;
using Microsoft.VisualStudio.Shell;
using Microsoft.VisualStudio.Shell.Interop;
using Microsoft.Win32;
+using Task = System.Threading.Tasks.Task;
namespace VSIXProject9
{
@@ -71,5 +74,32 @@ namespace VSIXProject9
}
#endregion
+
+ public override IVsAsyncToolWindowFactory GetAsyncToolWindowFactory(Guid toolWindowType)
+ {
+ if (toolWindowType == typeof(ToolWindow1).GUID)
+ {
+ return this;
+ }
+
+ return base.GetAsyncToolWindowFactory(toolWindowType);
+ }
+
+ protected override string GetToolWindowTitle(Type toolWindowType, int id)
+ {
+ if (toolWindowType == typeof(ToolWindow1))
+ {
+ return "ToolWindow1 loading";
+ }
+
+ return base.GetToolWindowTitle(toolWindowType, id);
+ }
+
+ protected override async Task<object> InitializeToolWindowAsync(Type toolWindowType, int id, CancellationToken cancellationToken)
+ {
+ await Task.Delay(5000);
+
+ return "foo";
+ }
}
}
If the Package.Initialize
override in the user code does not call base.Initialize
, the VSSDK001 code fix does not insert the await this.jtf.SwitchToMainThreadAsync()
in the method. But this switch is important for the rest of the code that does appear in the (renamed) InitializeAsync
method.
This is for when the only purpose of the package is to register a service, code expansions or other things that don't require autoload
The VSTHRD010 analyzer defined in vs-threading is the only analyzer in that project that is really VS-specific. We should consider moving that analyzer to this repo. The alternative would be to make that analyzer more generalized (data-driven), which may be a good idea anyway.
The package has a lib folder with the analyzers in it instead of an analyzers\cs
folder with the library under that.
Types from Microsoft.VisualStudio.Shell.XX.0.dll are not subject to the normal versioning strategies in Visual Studio. Exposing them in signatures can result in compile or runtime failures in side-by-side load scenarios.
An analyzer can report a diagnostic for all cases where an exposed signature depends on a type defined in one of these assemblies.
No one in the VS primary AppDomain should create a JoinableTaskContext
instance except UIInternal
's singleton. Any VS extension doing it should produce an error to protect the singleton.
We'll need to find a way to make it permissible for a unit test project by default, however.
As we're seeing more packages migrate to be async packages, the AsyncPackage.InitializeAsync
method is more likely to see null results from GetService
or GetServiceAsync
calls, if VS starts to shutdown while the package isn't finished initializing. These null's should not be interpreted to mean something failed (and crash VS) but rather should be treated like any other unexpected null result: simply either degrade gracefully or throw a meaningful exception about not getting the required service.
We should offer an analyzer that notices when GetService
or GetServiceAsync
calls aren't followed by a check for a non-null result and report a diagnostic for those cases.
The PackageRegistrationAttribute.AllowsBackgroundLoading
parameter on your VS package class
should indicate whether your class derives from AsyncPackage
.
[PackageRegistration(UseManagedResourcesOnly = true)]
class MyCoolPackage : AsyncPackage {
}
or
[PackageRegistration(UseManagedResourcesOnly = true, AllowsBackgroundLoading = true)]
class MyCoolPackage : Package {
}
Update the PackageRegistration attribute to match the base type of your package class.
Specifically, the AllowsBackgroundLoading
parameter should be set to true
if and only if your package derives from AsyncPackage
.
[PackageRegistration(UseManagedResourcesOnly = true)]
class MyCoolPackage : Package {
}
or
[PackageRegistration(UseManagedResourcesOnly = true, AllowsBackgroundLoading = true)]
class MyCoolPackage : AsyncPackage {
}
A code fix is offered for this diagnostic to automatically apply this change.
VSSDK003 (use async tool windows) still fires if you're using ToolWindowCreationContext.Unspecified, and doesn't hint at what you should do to make it go away then.
We had an existing class that defined a tool window, and we moved to the newer analyzers which (correctly) suggested to move to an async tool window. I did my first pass overriding the methods of AsyncPackage, but I couldn't get the diagnostic to go away. I was using ToolWindowCreationContext.Unspecified in InitializeToolWindowAsync to specify that my tool window constructor didn't need to get anything -- at least initially while I was trying to get everything else to work -- but the analyzer was still complaining.
I was able to figure out what was going on by finding the analyzer code and reading it, which quickly revealed the problem. But hey, I work on Roslyn, so that's "easy" for me. ๐
Once I had overridden the methods in AsyncPackage, the diagnostic would go away. I kept assuming that because I was still getting the diagnostic, I had missed some overload.
The analyzer is actually looking entirely at the constructor of the ToolWindow to see if there's a non-default constructor. Although the presence of one does indicate it's an async tool window, the absence doesn't necessarily. In any case, I ran around in circles trying to figure out what I was doing wrong.
In a perfect world the analyzer could see what was happening and realized it was fine, but that's hard. A good heuristic might be that default constructors are OK if InitializeToolWindowAsync somewhere has a reference to ToolWindowCreationContext.Unspecified. Or, if the analyzer sees a reference to Unspecified, consider reporting a different message that tells you it might be OK, and you should just use a constructor to ensure it's safe.
Or, absent of code changes, just update the docs that if you use Unspecified, the analyzer will still be "wrong". That at least wouldn't have sent me down a path of assuming I'm doing something wrong.
In an async method that calls the static method: `ServiceProvider.GetGlobalServiceAsync<SVsSolution, IVsSolution>(), VSTHRD010 will claim that the async method needs to switch to the main thread first. It should not do this.
This method is prepared to be called from any thread. So we might fix this by whitelisting this method in the additionalfiles supplied by this vssdk-analyzers repo.
Another option is to suppress VSTHRD010 altogether for any call to an async method, since per the threading rules all async methods should be callable from any thread.
A clear and concise description of what the bug is.
Analyzer 'Microsoft.VisualStudio.SDK.Analyzers.VSSDK006CheckServicesExistAnalyzer' threw an exception of type 'System.ArgumentException' with message 'Syntax node is not within syntax tree'.
'Microsoft.VisualStudio.SDK.Analyzers.VSSDK006CheckServicesExistAnalyzer' threw the following exception:
SyntaxTree: D:\repos\Scalability Measurment\src\VSUtilitiesVSIX\CMDPackage.cs
SyntaxNode: this.GetService(typeof(SDTE)) [InvocationExpressionSyntax]@[4656..4685) (87,31)-(87,60)
System.ArgumentException: Syntax node is not within syntax tree
at Microsoft.CodeAnalysis.CSharp.CSharpSemanticModel.CheckSyntaxNode(CSharpSyntaxNode syntax)
at Microsoft.CodeAnalysis.CSharp.CSharpSemanticModel.GetSymbolInfo(ExpressionSyntax expression, CancellationToken cancellationToken)
at Microsoft.CodeAnalysis.CSharp.CSharpExtensions.GetSymbolInfo(SemanticModel semanticModel, ExpressionSyntax expression, CancellationToken cancellationToken)
at Microsoft.VisualStudio.SDK.Analyzers.VSSDK006CheckServicesExistAnalyzer.CompilationState.IsThrowingNullCheck(SyntaxNode node, ISymbol symbol, SyntaxNodeAnalysisContext context)
at Microsoft.VisualStudio.SDK.Analyzers.VSSDK006CheckServicesExistAnalyzer.CompilationState.IsNonNullCheck(SyntaxNode node, ISymbol symbol, SyntaxNodeAnalysisContext context)
at Microsoft.VisualStudio.SDK.Analyzers.VSSDK006CheckServicesExistAnalyzer.CompilationState.<>c__DisplayClass6_0.<ScanBlockForDereferencesWithoutNullCheck>b__3(SyntaxNode n)
at System.Linq.Enumerable.Any[TSource](IEnumerable`1 source, Func`2 predicate)
at Microsoft.VisualStudio.SDK.Analyzers.VSSDK006CheckServicesExistAnalyzer.CompilationState.ScanBlockForDereferencesWithoutNullCheck(SyntaxNodeAnalysisContext context, ISymbol symbol, SyntaxNode containingBlockOrExpression)
at Microsoft.VisualStudio.SDK.Analyzers.VSSDK006CheckServicesExistAnalyzer.CompilationState.<>c__DisplayClass5_1.<AnalyzeInvocationExpression>b__15(<>f__AnonymousType2`2 <>h__TransparentIdentifier2)
at System.Linq.Enumerable.<SelectManyIterator>d__23`3.MoveNext()
at System.Linq.Enumerable.Any[TSource](IEnumerable`1 source)
at Microsoft.VisualStudio.SDK.Analyzers.VSSDK006CheckServicesExistAnalyzer.CompilationState.AnalyzeInvocationExpression(SyntaxNodeAnalysisContext context)
at Microsoft.CodeAnalysis.Diagnostics.AnalyzerExecutor.<>c__50`1.<ExecuteSyntaxNodeAction>b__50_0(ValueTuple`2 data)
at Microsoft.CodeAnalysis.Diagnostics.AnalyzerExecutor.ExecuteAndCatchIfThrows_NoLock[TArg](DiagnosticAnalyzer analyzer, Action`1 analyze, TArg argument, Nullable`1 info)
Steps or code to reproduce the behavior:
Scalability Measurment
(works around an unrelated bug with percent-encoded sequence in folders)No warning.
When a VS package derives from Package
directly, the only way to get services from it is via the Microsoft.VisualStudio.Shell.PackageUtilities.QueryService(OLE.Interop.IServiceprovider)
methods (generic and non-generic). But these methods aren't considered part of the GetService-family of methods that VSSDK006 checks, so null checks aren't required.
If ThreadHelper.JoinableTaskFactory.RunAsync
is called and the JoinableTask
returned isn't tracked anywhere, that represents unmonitored async work that can crash if still running when VS shuts down the CLR. Folks should follow a pattern of tracking their async work.
This is actually more general to all async methods invoked but not awaited or assigned to something.
Note that some JTF instances are associated with a JoinableTaskCollection
that tracks the async work implicitly and that shouldn't produce a warning.
Maybe this should go into the vs-threading library, except perhaps not all apps are as sensitive to untracked async work as VS is. Also, we may want to special case well-known JTF instances such as the one on ThreadHelper
to know that that is not a tracking one and should therefore be flagged.
I'm running into this a bit, I don't know exact repro but likely due to a mix of assemblies versions in-proc?
I don't have a repro, nor can I reproduce it on demand. I've hit it across multiple code bases over the past year.
System.TypeInitializationException : The type initializer for 'Microsoft.VisualStudio.SDK.Analyzers.VSSDK001DeriveFromAsyncPackageCodeFix' threw an exception. ---> System.FieldAccessException : Attempt by method 'Microsoft.VisualStudio.SDK.Analyzers.VSSDK001DeriveFromAsyncPackageCodeFix..cctor()' to access field 'Microsoft.VisualStudio.SDK.Analyzers.VSSDK001DeriveFromAsyncPackageAnalyzer.Descriptor' failed.
at Microsoft.VisualStudio.SDK.Analyzers.VSSDK001DeriveFromAsyncPackageCodeFix..cctor()
--- End of inner exception stack trace ---
at Microsoft.VisualStudio.SDK.Analyzers.VSSDK001DeriveFromAsyncPackageCodeFix.get_FixableDiagnosticIds()
at Microsoft.CodeAnalysis.CodeFixes.CodeFixService.GetAndTestFixableDiagnosticIds(CodeFixProvider codeFixProvider)
at Microsoft.CodeAnalysis.CodeFixes.CodeFixService.<>c.<GetFixableDiagnosticIds>b__34_2(CodeFixProvider f)
at System.Collections.Immutable.ImmutableInterlocked.GetOrAdd[TKey,TValue](ImmutableDictionary`2& location,TKey key,Func`2 valueFactory)
at Microsoft.CodeAnalysis.CodeFixes.CodeFixService.<>c__DisplayClass34_0.<GetFixableDiagnosticIds>b__0()
at Microsoft.CodeAnalysis.Extensions.IExtensionManagerExtensions.PerformFunction[T](IExtensionManager extensionManager,Object extension,Func`1 function,T defaultValue)
Since this is passing the entire document and not a span, this means any fully-or-partially-qualified types anywhere in the file (even far away from the Assumes.Present being added) will get imports added for them and they'll be minimally qualified. This is problematic since people might have wanted the qualification to avoid ambiguities or other problems. ImportAdder isn't smart enough to handle complicated cases where it shouldn't add them.
The fix is to call one of the overloads of AddImportsAsync either by passing the span of the Assumes.Present, or annotating the Assumes.Present with an annotation and calling the overload that takes the annotation.
Since some Package classes don't include System.Threading.Tasks
, the code written isn't very reader friendly. We should use the ImportAdder and Simplifier annotation to simplify the code.
Also consider explicitly adding using Task = System.Threading.Tasks.Task;
to the document.
I would like to report telemetry when a service is null, so I'm validating my services with another method rather than calling Assumes.Present, or duplicating bunch of if-null blocks. However, VSSDK006 doesn't detect that.
FXCop's CA1602 addresses this by looking at the [ValidatedNotnull]
attribute on the validation method (see dotnet/roslyn-analyzers#2863 (comment)). Any chance something similar can be done here?
The VSSDK006 warning conflicts with CA2007: Do not directly await a Task without calling ConfigureAwait
var componentModel = (IComponentModel)await GetServiceAsync(typeof(SComponentModel));
Assumes.Present(componentModel);
var componentModel = (IComponentModel)await GetServiceAsync(typeof(SComponentModel)).ConfigureAwait(false);
Assumes.Present(componentModel);
I guess VSSDK006 should handle calling ConfigureAwait
on GetServiceAsync
?
We can quite easily miss introducing a regression in the analyzers by inadvertently introducing a dependency on the Roslyn Workspaces assembly which the code fixes require but analyzers aren't allowed to use. Using unit tests to monitor this seems nearly impossible.
Instead, the best fix for this is probably to split the code fixes out into their own assembly. StyleCop.Analyzers did this a while back with DotNetAnalyzers/StyleCopAnalyzers#1674
The [ProvideAutoload]
attribute should only be used on AsyncPackage
and be marked to load in the background
When the user has this:
using Microsoft.VisualStudio.Shell;
using System.Threading.Tasks; // with or without this
Then implementing async methods becomes very tricky because unhelpful compiler errors show up when using Task
. The fix is to add this to the top of the file:
using Task = System.Threading.Tasks.Task;
But many users don't realize this. An analyzer could suggest this and offer a code fix.
Folks who target 16.9 but use VisualStudioServices.VS2019_7
are missing out on functionality or perf improvements that may be reserved to users of VisualStudioServices.VS2019_9
.
As existing code from when code targeted an older version is inevitable, we should add an analyzer that notices when any version older than the most recent available one is used given the reference assemblies.
I suggest making the diagnostic severity default to Info, since light-up scenarios or behavioral difference between service moniker versions can make upgrading significant.
A code fix could offer to bulk update all uses too.
Hello there,
Sorry to bother you guys :-)
I am writing an visual studio extension using C# recently, somehow, i need to retrieve an 'IVsBuildPropertyStorage2' instance to set project build property without escaping characters, but i don't know how to get the instance. Cast from project hierarchy won't work.
so, could you help me to solve this problem?
Thanks.
Please reword this message:
"Error | VSSDK002 | The PackageRegistrationAttribute.AllowsBackgroundLoading should be set to true if and only if the package derives from AsyncPackage.
-- | -- | -- "
In fact, from that message, it wasn't clear to me that my package, which derives from AsyncPackage had the AllowsBackgroundLoading set to false.
There are important files that Microsoft projects should all have that are not present in this repository. A pull request has been opened to add the missing file(s). When the pr is merged this issue will be closed automatically.
Microsoft teams can learn more about this effort and share feedback within the open source guidance available internally.
This repo has a working .appveyor.yml file. Can someone with admin access on this repo attach an appveyor build definition?
@madskristensen if you make me an admin, I can do it.
Calling GetService in Package constructors is a common place for failures - there's no guarantee that the service provider will be properly set up by the time the Package is created.
Instead, the GetService call should be done in Initialize (or InitializeAsync, after switching to the main thread).
AsyncToolWindow in 15.6 should be used if possible.
This issue is actually about Microsoft.VSSDK.BuildTools and Microsoft.VSSDK.CompatibilityAnalyzer 17.2.x packages, but I was not able to find appropriate place for reporting issues with those packages.
MSBuild target "VsixCompatibilityAnalyzer" from Microsoft.VisualStudio.Sdk.CompatibilityAnalyzerTasks.dll (Microsoft.VSSDK.CompatibilityAnalyzer package) is keeping file lock on the vsix file till the end of the whole build.
After updating Microsoft.VSSDK.BuildTools package from 17.1.4057 to 17.2.2186, our "AfterBuild" step, which performs custom signing of the vsix file, started to fail as it was not able to overwrite the vsix file.
In our product, we call PowerShell script in "AfterBuild" target (cleaned up version):
<Target Name="AfterBuild">
<CallTarget Targets="PublishArtifacts" />
</Target>
<Target Name="PublishArtifacts">
<Exec Command="pwsh.exe -NonInteractive -NoProfile -ExecutionPolicy RemoteSigned -File "$(MSBuildProjectDirectory)\Publish-Artifact.ps1" -SourceArtifactPath "$(MSBuildProjectDirectory)\$(TargetVsixContainer)"" />
</Target>
In "Publish-Artifact.ps1", Copy-Item
with -Destination
being the vsix container will fail due to:
Copy-Item: D:\xyz\foobar.ps1:123
Copy-Item -Path $SomeCacheFile -Destination $VsixContainerPath -Force
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The process cannot access the file
'D:\xyz\bin\Release\net472\foobar.vsix' because it is being used by another process.
Example "Publish-Artifact.ps1", which should show the issue:
param([string] $SourceArtifactPath)
function AwaitWriteable {
[CmdletBinding()]
param(
[Parameter(Mandatory = $true)]
[ValidateNotNullOrEmpty()]
[string] $Path
)
$canWrite = $false
$retryCount = 0
while (!$canWrite -and $retryCount -lt 5) {
$retryCount++
try {
[IO.File]::OpenWrite($Path).Close()
$canWrite = $true
}
catch {
if ($retryCount -lt 5) {
Write-Host "Path '$Path' is not writeable. Retrying in 5 seconds ($retryCount/5)..."
}
Start-Sleep -Seconds 5
}
}
if (!$canWrite) {
throw "Unable to gain write access to '$Path'"
}
Write-Host "Got write access to '$Path'"
}
$global:ErrorActionPreference = 'Stop'
AwaitWriteable -Path "$SourceArtifactPath"
I added above code just to see if the file gets unlocked after few seconds, but it does not.
"VsixCompatibilityAnalyzer" target/task should not leave file lock on the vsix file after it's done.
Not sure if it's relevant, but the task reported some compatibilty issues:
6>Target VsixCompatibilityAnalyzer:
6> Task "Message"
6> Executing CompatibilityAnalyzer..
6> Done executing task "Message".
6> Using "VsixCompatibilityAnalyzer" task from assembly "D:\xyz\packages\microsoft.vssdk.compatibilityanalyzer\17.2.2186\build\Microsoft.VisualStudio.Sdk.CompatibilityAnalyzerTasks.dll".
6> Task "VsixCompatibilityAnalyzer"
6> D:\xyz\packages\microsoft.vssdk.compatibilityanalyzer\17.2.2186\build\Microsoft.VSSDK.CompatibilityAnalyzer.targets(40,5): warning VSIXCompatibility1001: The extension is incompatible with the targeted version of Visual Studio. More info at https://aka.ms/ExtensionSdkErrors.
6> D:\xyz\packages\microsoft.vssdk.compatibilityanalyzer\17.2.2186\build\Microsoft.VSSDK.CompatibilityAnalyzer.targets(40,5): warning VSIXCompatibility1001: Following references are incompatible.
6> D:\xyz\packages\microsoft.vssdk.compatibilityanalyzer\17.2.2186\build\Microsoft.VSSDK.CompatibilityAnalyzer.targets(40,5): warning VSIXCompatibility1001: Microsoft.VisualStudio.Data.Schema.Package.dll -> Microsoft.VisualStudio.OLE.Interop; Microsoft.VisualStudio.Shell.Interop; Microsoft.VisualStudio.TextManager.Interop; Microsoft.VisualStudio.TextManager.Interop.8.0; Microsoft.VisualStudio.Shell.Interop.8.0; envdte80; envdte; VSLangProj; envdte; Microsoft.VisualStudio.Shell.Interop.10.0; Microsoft.VisualStudio.Shell.Interop.9.0; Microsoft.VisualStudio.Designer.Interfaces
6> Done executing task "VsixCompatibilityAnalyzer".
6>Done building target "VsixCompatibilityAnalyzer" in project "VsPackage.2022.csproj".
A clear and concise description of what the bug is.
Warning VSSDK006 Check whether the result of GetService calls is null.
Steps or code to reproduce the behavior:
Sample code:
var imageService = ServiceProvider.GlobalProvider.GetService(typeof(SVsImageService)) as IVsImageService2;
if (imageService is null)
{
return default;
}
no error since I'm checking result for null
This code works fine:
var imageService = ServiceProvider.GlobalProvider.GetService(typeof(SVsImageService)) as IVsImageService2;
if (imageService == null)
{
return default;
}
There should be a diagnostic checking if Export
declarations are correct. For example:
[Export(typeof(IBar))]
public class Foo { }
This should be flagged as incorrect since Foo
does not implement IBar
The threading analyzer warns that IVsInvalidateCachedCommandState.InvalidateSpecificCommandUIState(VSCommand)
must be called on the main thread; however, this interface is free-threaded.
Version used: Microsoft.VisualStudio.Threading.Analyzers 16.9.39-alpha
Too much code in Visual Studio runs expensive, async work that slows down IDE shutdown.
A new analyzer that ensures all JoinableTaskFactory.SwitchToMainThreadAsync
calls pass in a CancellationToken
(or None
or default
), with a fix offered to pass in VsShellUtilities.ShutdownToken
. The analyzer should only activate when the VsShellUtilities.ShutdownToken
symbol is available to the compilation.
Severity Code Description Project File Line Suppression State Detail Description
Error AD0001 Analyzer 'Microsoft.VisualStudio.Threading.Analyzers.VSTHRD010MainThreadUsageAnalyzer' threw an exception of type 'System.Exception' with message 'Analyzer failure while processing syntax at C:\git\WinAnyCode\Package\CommandHandler.cs(829,26): System.ArgumentNullException Value cannot be null.
Parameter name: values. Syntax: ServiceProvider.GlobalProvider.GetService(typeof(IVsMonitorSelection))'. WinAnyCode.Package 1 Active Analyzer 'Microsoft.VisualStudio.Threading.Analyzers.VSTHRD010MainThreadUsageAnalyzer' threw the following exception:
'Exception occurred with following context:
Compilation: WinAnyCode.Package
SyntaxTree: C:\git\WinAnyCode\Package\CommandHandler.cs
SyntaxNode: ServiceProvider.GlobalProvider. ... [InvocationExpressionSyntax]@[35032..35102) (828,25)-(828,95)
System.Exception: Analyzer failure while processing syntax at C:\git\WinAnyCode\Package\CommandHandler.cs(829,26): System.ArgumentNullException Value cannot be null.
Parameter name: values. Syntax: ServiceProvider.GlobalProvider.GetService(typeof(IVsMonitorSelection)) ---> System.ArgumentNullException: Value cannot be null.
Parameter name: values
at System.String.Join(String separator, IEnumerable`1 values)
at Microsoft.VisualStudio.Threading.Analyzers.CommonInterest.QualifiedType.ToString()
at Microsoft.VisualStudio.Threading.Analyzers.CommonInterest.QualifiedMember.ToString()
at Microsoft.VisualStudio.Threading.Analyzers.VSTHRD010MainThreadUsageAnalyzer.MethodAnalyzer.AnalyzeTypeWithinContext(ITypeSymbol type, ISymbol symbol, SyntaxNodeAnalysisContext context, Location focusDiagnosticOn)
at Microsoft.VisualStudio.Threading.Analyzers.VSTHRD010MainThreadUsageAnalyzer.MethodAnalyzer.AnalyzeInvocation(SyntaxNodeAnalysisContext context)
at Microsoft.VisualStudio.Threading.Analyzers.Utils.<>c__DisplayClass0_0.<DebuggableWrapper>b__0(SyntaxNodeAnalysisContext ctxt)
--- End of inner exception stack trace ---
at Microsoft.VisualStudio.Threading.Analyzers.Utils.<>c__DisplayClass0_0.<DebuggableWrapper>b__0(SyntaxNodeAnalysisContext ctxt)
at Microsoft.CodeAnalysis.Diagnostics.AnalyzerExecutor.<>c__43`1.<ExecuteSyntaxNodeAction>b__43_0(ValueTuple`2 data)
at Microsoft.CodeAnalysis.Diagnostics.AnalyzerExecutor.ExecuteAndCatchIfThrows_NoLock[TArg](DiagnosticAnalyzer analyzer, Action`1 analyze, TArg argument, Nullable`1 info)
-----
System.ArgumentNullException: Value cannot be null.
Parameter name: values
at System.String.Join(String separator, IEnumerable`1 values)
at Microsoft.VisualStudio.Threading.Analyzers.CommonInterest.QualifiedType.ToString()
at Microsoft.VisualStudio.Threading.Analyzers.CommonInterest.QualifiedMember.ToString()
at Microsoft.VisualStudio.Threading.Analyzers.VSTHRD010MainThreadUsageAnalyzer.MethodAnalyzer.AnalyzeTypeWithinContext(ITypeSymbol type, ISymbol symbol, SyntaxNodeAnalysisContext context, Location focusDiagnosticOn)
at Microsoft.VisualStudio.Threading.Analyzers.VSTHRD010MainThreadUsageAnalyzer.MethodAnalyzer.AnalyzeInvocation(SyntaxNodeAnalysisContext context)
at Microsoft.VisualStudio.Threading.Analyzers.Utils.<>c__DisplayClass0_0.<DebuggableWrapper>b__0(SyntaxNodeAnalysisContext ctxt)
This is the block I have starting at line 828:
public bool OptionRazzleWindowEnabled
{
get
{
return _settings.OptionRazzleWindowEnabled;
}
set
{
_settings.OptionRazzleWindowEnabled = value;
}
}
About the "_settings", it's defined like:
[Import]
private IUserSettings _settings;
Meanwhile its property is defined in this way:
/// <summary>
/// Property representing the state (enabled/disabled) of the 'Razzle Window' feature.
/// </summary>
bool OptionRazzleWindowEnabled
{
get;
set;
}
I get the following error when opening my package class:
Warning AD0001 Analyzer 'Microsoft.VisualStudio.SDK.Analyzers.VSSDK003SupportAsyncToolWindowAnalyzer' threw an exception of type 'System.Exception' with message 'Analyzer failure while processing syntax at C:\Users\<username>\Documents\GitHub\ProtocolHandlerSample\src\ProtocolPackage.cs(11,5): System.InvalidOperationException Nullable object must have a value.. Syntax: [PackageRegistration(UseManagedResourcesOnly = true)]
[InstalledProductRegistration("#110", "#112", "1.0", IconResourceID = 400)]
[Guid("4b19d544-cbe1-404c-b751-21698348b48d")]
[ProvideAppCommandLine(_cliSwitch, typeof(ProtocolPackage), Arguments = "1", DemandLoad = 1)] // More info https://docs.microsoft.com/en-us/visualstudio/extensibility/adding-command-line-switches
public sealed class ProtocolPackage : AsyncPackage
{
private const string _cliSwitch = "MySwitch";
protected override async Task InitializeAsync(CancellationToken cancellationToken, IProgress<ServiceProgressData> progress)
{
await JoinableTaskFactory.SwitchToMainThreadAsync();
var cmdline = await GetServiceAsync(typeof(SVsAppCommandLine)) as IVsAppCommandLine;
ErrorHandler.ThrowOnFailure(cmdline.GetOption(_cliSwitch, out int isPresent, out string optionValue));
if (isPresent == 1)
{
// If opened from a URL, then "optionValue" is the URL string itself
System.Windows.Forms.MessageBox.Show(optionValue);
}
}
}'. ProtocolHandlerSample 1 Active
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.