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

Give a specific message when analyzer references a more-recent compiler version #61261

Merged

Conversation

RikkiGibson
Copy link
Contributor

@RikkiGibson RikkiGibson commented May 12, 2022

@RikkiGibson RikkiGibson changed the base branch from main to release/dev17.3 July 8, 2022 19:32
@RikkiGibson RikkiGibson marked this pull request as ready for review July 8, 2022 19:32
@RikkiGibson RikkiGibson requested review from a team as code owners July 8, 2022 19:32
@@ -2099,6 +2099,8 @@ internal enum ErrorCode
ERR_FixedFieldMustNotBeRef = 9049,
ERR_RefFieldCannotReferToRefStruct = 9050,

WRN_AnalyzerReferencesNewerCompiler = 9057,
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we're skipping error codes which we know are present in 17.4.

@@ -37,9 +38,11 @@ public enum FailureErrorCode
/// </summary>
public Exception? Exception { get; }

public Version? ReferencedCompilerVersion { get; init; }
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The idea here was to prevent breaking the signature of the constructor, since it is public API. I guess we could use 'internal init' here as well.

Instead of adding this property, we could consider "smuggling through" a string representation of the referenced version through the 'message' property. But that is very hacky.

Ideally the public API would be much more limited here, i.e. the constructor would be internal and perhaps the entire type as well. It's not clear to me why external users would need to dig through why analyzers are failing to load instead of just surfacing the diagnostics.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@mavasani do you know whether/how the IDE is directly using new AnalyzerLoadFailureEventArgs and related APIs such as AnalyzerLoadFailureEventArgs.FailureErrorCode?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The one point I would raise is whether the increase in complexity in the API is justified by how much clearer it makes the error. Basically is the error message without this good enough? Does knowing the exact version referenced by the analyzer help the customer enough to make this API worth it? Lacking this data the customer would still have the version of the compiler and the version of the analyzer (usually it's the full path to the NuPkg).

Leaned both ways thinking about this in last 5 minutes.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Lacking this data the customer would still have the version of the compiler and the version of the analyzer

The user would have the running version of the compiler, to be clear. They could be referencing an analyzer version which just happens to require a later SDK than the one they're running, and the process of figuring out manually which compiler version the analyzer is referencing may not be something we expect users to know how to do.

I'm happy to look at any way to pass along this information in a way that's found to be more palatable. But I do think the information is worth passing along.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@mavasani do you know whether/how the IDE is directly using new AnalyzerLoadFailureEventArgs and related APIs such as AnalyzerLoadFailureEventArgs.FailureErrorCode?

@RikkiGibson AnalyzerLoadFailureEventArgs is required to be exposed for all analyzer hosts that might require loading the analyzer assembly in contexts outside analyzer execution. For example, in the IDE, we need to load the analyzer assembly to populate the Analyzers node in the solution explorer, and any failure to load the analyzer assembly needs to be reported as a diagnostic in the error list. We do so by hooking up to the event handler AnalyzerFileReference.AnalyzerLoadFailed:

var analyzerFileReference = new AnalyzerFileReference(FullPath, s_analyzerAssemblyLoader);
analyzerFileReference.AnalyzerLoadFailed += OnAnalyzerLoadError;

In the hooked up event handler, we create the appropriate diagnostic using the failure code and report it in the error list:

private void OnAnalyzerLoadError(object sender, AnalyzerLoadFailureEventArgs e)
{
var data = DocumentAnalysisExecutor.CreateAnalyzerLoadFailureDiagnostic(e, FullPath, _projectId, _language);
lock (_gate)
{
_analyzerLoadErrors = _analyzerLoadErrors.Add(data);
_hostDiagnosticUpdateSource.UpdateDiagnosticsForProject(_projectId, this, _analyzerLoadErrors);
}
}

}

[ConditionalFact(typeof(IsEnglishLocal))]
public void AssemblyLoading_ReferencesLaterFakeCompiler_EndToEnd_CSharp()
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I also wanted to do an end-to-end test for VB, but I wasn't able to figure out how to provide a ref to Microsoft.VisualBasic.dll and System.dll in this context. Tried a few ways of making a mock compiler.

@RikkiGibson RikkiGibson requested a review from a team as a code owner July 8, 2022 21:44
using System;
using System.Reflection;

[assembly: AssemblyVersionAttribute(""42.42.42.42"")]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why use 42.42.42.42 here? This will sometimes match the version in the MS.CA running in this process and sometimes not match it. Feels like that could lead to flakiness down the road (running unit tests on official binaries for example). My instinct says a different number should be here. Am I missing something about what this helps with?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can use a small number here. The only point of this is to be a baseline, so in the next scenario we can pinpoint the high version number as the reason it won't load. I did find that helpful when initially setting all this up though it perhaps doesn't look as helpful now that things are working :)

@RikkiGibson
Copy link
Contributor Author

Looking at the failing netframework tests now.

@RikkiGibson
Copy link
Contributor Author

@jaredpar @chsienki This is ready for another review pass.

@RikkiGibson RikkiGibson merged commit be8eed3 into dotnet:release/dev17.3 Jul 12, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Compiler needs to declaratively fail when loading newer analyzers
5 participants