-
Notifications
You must be signed in to change notification settings - Fork 4.1k
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
Move Roslyn.sln to latest analyzer packages, also including the newly… #25179
Changes from all commits
c6e43f3
ad14927
e0f2523
2e58602
9d942b1
184ea69
f728c6e
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -276,59 +276,61 @@ private DirectiveTriviaSyntax ParseErrorOrWarningDirective(SyntaxToken hash, Syn | |
bool isError = keyword.Kind == SyntaxKind.ErrorKeyword; | ||
if (isActive) | ||
{ | ||
var triviaBuilder = new System.IO.StringWriter(System.Globalization.CultureInfo.InvariantCulture); | ||
int triviaWidth = 0; | ||
|
||
// whitespace and single line comments are trailing trivia on the keyword, the rest | ||
// of the error message is leading trivia on the eod. | ||
// | ||
bool skipping = true; | ||
foreach (var t in keyword.TrailingTrivia) | ||
using (var triviaBuilder = new System.IO.StringWriter(System.Globalization.CultureInfo.InvariantCulture)) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ❔ What's our reason for not treating There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Special casing disposable types as "okay to not dispose" due to an implementation detail about the current Dispose implementation on a type is not good design. There is nothing that prevents the future versions of the library implementing such types to change their implementation to hold onto to more disposable objects and/or change the implementation of Dispose method, hence I believe that all disposable objects should be disposed, even if we think it is a no-op. |
||
{ | ||
if (skipping) | ||
int triviaWidth = 0; | ||
|
||
// whitespace and single line comments are trailing trivia on the keyword, the rest | ||
// of the error message is leading trivia on the eod. | ||
// | ||
bool skipping = true; | ||
foreach (var t in keyword.TrailingTrivia) | ||
{ | ||
if (t.Kind == SyntaxKind.WhitespaceTrivia) | ||
if (skipping) | ||
{ | ||
continue; | ||
if (t.Kind == SyntaxKind.WhitespaceTrivia) | ||
{ | ||
continue; | ||
} | ||
|
||
skipping = false; | ||
} | ||
|
||
skipping = false; | ||
t.WriteTo(triviaBuilder, leading: true, trailing: true); | ||
triviaWidth += t.FullWidth; | ||
} | ||
|
||
t.WriteTo(triviaBuilder, leading: true, trailing: true); | ||
triviaWidth += t.FullWidth; | ||
} | ||
|
||
foreach (var node in eod.LeadingTrivia) | ||
{ | ||
node.WriteTo(triviaBuilder, leading: true, trailing: true); | ||
triviaWidth += node.FullWidth; | ||
} | ||
foreach (var node in eod.LeadingTrivia) | ||
{ | ||
node.WriteTo(triviaBuilder, leading: true, trailing: true); | ||
triviaWidth += node.FullWidth; | ||
} | ||
|
||
//relative to leading trivia of eod | ||
//could be negative if part of the error text comes from the trailing trivia of the keyword token | ||
int triviaOffset = eod.GetLeadingTriviaWidth() - triviaWidth; | ||
//relative to leading trivia of eod | ||
//could be negative if part of the error text comes from the trailing trivia of the keyword token | ||
int triviaOffset = eod.GetLeadingTriviaWidth() - triviaWidth; | ||
|
||
string errorText = triviaBuilder.ToString(); | ||
eod = this.AddError(eod, triviaOffset, triviaWidth, isError ? ErrorCode.ERR_ErrorDirective : ErrorCode.WRN_WarningDirective, errorText); | ||
string errorText = triviaBuilder.ToString(); | ||
eod = this.AddError(eod, triviaOffset, triviaWidth, isError ? ErrorCode.ERR_ErrorDirective : ErrorCode.WRN_WarningDirective, errorText); | ||
|
||
if (isError) | ||
{ | ||
if (errorText.Equals("version", StringComparison.Ordinal)) | ||
if (isError) | ||
{ | ||
Assembly assembly = typeof(CSharpCompiler).GetTypeInfo().Assembly; | ||
string version = CommonCompiler.GetAssemblyFileVersion(assembly); | ||
eod = this.AddError(eod, triviaOffset, triviaWidth, ErrorCode.ERR_CompilerAndLanguageVersion, version, | ||
this.Options.SpecifiedLanguageVersion.ToDisplayString()); | ||
} | ||
else | ||
{ | ||
const string versionMarker = "version:"; | ||
if (errorText.StartsWith(versionMarker, StringComparison.Ordinal) && | ||
LanguageVersionFacts.TryParse(errorText.Substring(versionMarker.Length), out var languageVersion)) | ||
if (errorText.Equals("version", StringComparison.Ordinal)) | ||
{ | ||
ErrorCode error = this.Options.LanguageVersion.GetErrorCode(); | ||
eod = this.AddError(eod, triviaOffset, triviaWidth, error, "version", new CSharpRequiredLanguageVersion(languageVersion)); | ||
Assembly assembly = typeof(CSharpCompiler).GetTypeInfo().Assembly; | ||
string version = CommonCompiler.GetAssemblyFileVersion(assembly); | ||
eod = this.AddError(eod, triviaOffset, triviaWidth, ErrorCode.ERR_CompilerAndLanguageVersion, version, | ||
this.Options.SpecifiedLanguageVersion.ToDisplayString()); | ||
} | ||
else | ||
{ | ||
const string versionMarker = "version:"; | ||
if (errorText.StartsWith(versionMarker, StringComparison.Ordinal) && | ||
LanguageVersionFacts.TryParse(errorText.Substring(versionMarker.Length), out var languageVersion)) | ||
{ | ||
ErrorCode error = this.Options.LanguageVersion.GetErrorCode(); | ||
eod = this.AddError(eod, triviaOffset, triviaWidth, error, "version", new CSharpRequiredLanguageVersion(languageVersion)); | ||
} | ||
} | ||
} | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -10,7 +10,7 @@ | |
|
||
namespace Microsoft.CodeAnalysis.CSharp | ||
{ | ||
#pragma warning disable RS0010 | ||
#pragma warning disable CA1200 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ❕ Please add the comment with the title of the suppressed rule (same for other cases) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sure, will do. |
||
/// <summary> | ||
/// Displays a value in the C# style. | ||
/// </summary> | ||
|
@@ -19,7 +19,7 @@ namespace Microsoft.CodeAnalysis.CSharp | |
/// the Formatter project and we don't want it to be public there. | ||
/// </remarks> | ||
/// <seealso cref="T:Microsoft.CodeAnalysis.VisualBasic.Symbols.ObjectDisplay"/> | ||
#pragma warning restore RS0010 | ||
#pragma warning restore CA1200 | ||
internal static class ObjectDisplay | ||
{ | ||
/// <summary> | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
| ||
// This file is used by Code Analysis to maintain SuppressMessage | ||
// attributes that are applied to this project. | ||
// Project-level suppressions either have no target or are given | ||
// a specific target and scoped to a namespace, type, member, etc. | ||
|
||
[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Performance", "CA1819:Properties should not return arrays", Justification = "MSBuild has lot of properties returning arrays")] | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ❓ Why is this suppressed here instead of with 📝 I would be interested in seeing the cases where the warning was reported. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
I guess just a preference and ease of application - a suppression code fix offered in IDE only covers adding global suppress message attribute, not a project level no-warn.
See https://github.com/dotnet/roslyn/blob/master/src/Compilers/Core/MSBuildTask/ManagedCompiler.cs for an example. There are lots of violations in this project. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. One advantage of There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
AnalyzerDriver only executes an analyzer if There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't necessarily have a preference in how we suppress warnings but I do prefer it be done consintently. I see a lot of NoWarn, manually suppression, assembly attributes and rulesets. Feel like we need to pick a way and go with it. Otherwise it's nearly impossible to determine what rules are in effect because you have to check so many different places to see if they are turned off. |
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,6 +3,7 @@ | |
using System; | ||
using System.Diagnostics; | ||
using System.IO; | ||
using System.Text; | ||
|
||
namespace Microsoft.CodeAnalysis.BuildTasks | ||
{ | ||
|
@@ -12,7 +13,10 @@ public static class MvidReader | |
|
||
public static Guid ReadAssemblyMvidOrEmpty(Stream stream) | ||
{ | ||
return ReadAssemblyMvidOrEmpty(new BinaryReader(stream)); | ||
using (var reader = new BinaryReader(stream, new UTF8Encoding(encoderShouldEmitUTF8Identifier: false, throwOnInvalidBytes: true), leaveOpen: true)) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 💭 I'm not confident this is an improvement. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes it is - see my previous comment on why I believe all disposable objects should be disposed. Nothing prevents future version of There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In that sense, it is an improvement, but it is certainly not more readable, hence my 💭 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
I believe honoring an IDisposable contract that can lead to future leaks is more important then readability. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sure, thanks will change to |
||
{ | ||
return ReadAssemblyMvidOrEmpty(reader); | ||
} | ||
} | ||
|
||
private static Guid ReadAssemblyMvidOrEmpty(BinaryReader reader) | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
📝 The construction of a disposable object occurs in
AssemblyMetadata.Create
.💭 I'm not sure this can or should be treated as an ownership transfer. The
CreatePEAssemblyForAssemblyMetadata
method returnsPEAssemblySymbol
, which is not a disposable type. I would only expect factory methods to be candidates for ownership transfer if the constructed object is disposable.📝 In addition, I believe this is a legitimate resource leak.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, I assumed
CreatePEAssemblyForAssemblyMetadata
returns an IDisposable. This is indeed a resource leak. I will file a bug and add it to the suppression.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
FxCop does not treat factory methods OR constructor invocations as leading to an implicit dispose ownership transfer - it special cased very few cases, which we match. This means that we will have lot more false positives when these are actually dispose ownership transfers, but we will not miss out on flagging true violations where such a transfer does not happen (for example, we never assigned passed in disposable argument to a field or pass it further down). I think this is a general principle for dispose rules and it has been confirmed multiple times by customers - false positives is fine, but identifying as many true violations as possible is super valuable. This is the reason that dispose rules are by design most noisy and most valuable at the same time, which is somewhat ironical.
dotnet/roslyn-analyzers#1617 tracks how we can design this better, but I would not like to mask true leaks by assuming anything as a possible dispose ownership transfer.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can avoid masking by pairing the transfer heuristics - each case where signatures treat the code as a transfer of ownership, both the caller and callee agree this is the case. This will allow us to detect the majority cases without losing true positives.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This will not work. I have added the reasoning here so we capture all the arguments in that design issue.