-
Notifications
You must be signed in to change notification settings - Fork 424
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
Apply outstanding FxCop rules #3007
Conversation
They even don't have agreement on arguments order.
throw new ArgumentOutOfRangeException( | ||
$"Can not weld bindable longs with non-overlapping min/max-ranges. The ranges were [{MinValue} - {MaxValue}] and [{other.MinValue} - {other.MaxValue}].", nameof(them)); | ||
nameof(them), $"Can not weld bindable longs with non-overlapping min/max-ranges. The ranges were [{MinValue} - {MaxValue}] and [{other.MinValue} - {other.MaxValue}]."); |
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.
ArgumentOutOfRangeException
puts param name at first, but ArgumentException
puts it at last. I'm not realizing this.
private static readonly Action<TexturedVertex2D> default_quad_action; | ||
|
||
static TextureGLSingle() | ||
{ | ||
QuadBatch<TexturedVertex2D> quadBatch = new QuadBatch<TexturedVertex2D>(100, 1000); | ||
default_quad_action = quadBatch.AddAction; | ||
} | ||
private static readonly Action<TexturedVertex2D> default_quad_action = new QuadBatch<TexturedVertex2D>(100, 1000).AddAction; |
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.
Static constructor has performance impact on every instance method call of the type, according to FxCop doc.
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.
Got a link for this?
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.
Here's one. It has to do with introducing a flag checking whether the static ctor was ever called before to all static methods and instance ctors.
Here's a sharplab snippet showing the difference between an explicit and an implicit static ctor (note the beforefieldinit
flag). As stated in the fxcop documentation the implicit static ctor is not guaranteed to finish before any static method call or instance ctor, but is guaranteed to run before all static field accesses.
But then again, it's just a flag check. I really doubt it'll have real and noticeable performance repercussions.
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.
Seems to be a bit over-the-top in terms of optimisation. That said, no harm if the changes don't affect readability, which seems to be the case for the two in this PR.
There are places we use static ctor
for more than just initialisation though, so as long as the fxcop rule accounts (and allows) for that, there shouldn't be an issue.
public bool Equals(FontUsage other) => string.Equals(Family, other.Family) && string.Equals(Weight, other.Weight) && Italics == other.Italics && Size.Equals(other.Size) && FixedWidth == other.FixedWidth; | ||
public bool Equals(FontUsage other) => Family == other.Family && Weight == other.Weight && Italics == other.Italics && Size.Equals(other.Size) && FixedWidth == other.FixedWidth; |
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.
==
on string uses SequenceEquals. It should be always used unless absolute reason.
private static readonly Logger logger; | ||
|
||
private static readonly HttpClient client; | ||
|
||
static WebRequest() | ||
private static readonly HttpClient client = new HttpClient(new HttpClientHandler { AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate }) | ||
{ | ||
client = new HttpClient(new HttpClientHandler { AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate }); | ||
client.DefaultRequestHeaders.UserAgent.ParseAdd("osu!"); | ||
|
||
DefaultRequestHeaders = | ||
{ | ||
UserAgent = { ProductInfoHeaderValue.Parse("osu!") } | ||
}, | ||
// Timeout is controlled manually through cancellation tokens because | ||
// HttpClient does not properly timeout while reading chunked data | ||
client.Timeout = System.Threading.Timeout.InfiniteTimeSpan; | ||
Timeout = System.Threading.Timeout.InfiniteTimeSpan | ||
}; |
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.
Quite tricky here - object initializer syntax allows you to set nested properties without assigning new objects in the first-level property. I learned this just recently.
private static readonly MethodInfo method_cocoa_to_ns_string = type_cocoa.GetMethod("ToNSString"); | ||
private static readonly MethodInfo method_cocoa_get_string_constant = type_cocoa.GetMethod("GetStringConstant"); | ||
|
||
public static IntPtr AppKitLibrary; | ||
public static IntPtr FoundationLibrary; | ||
public static IntPtr AppKitLibrary = (IntPtr)type_cocoa.GetField("AppKitLibrary").GetValue(null); | ||
public static IntPtr FoundationLibrary = (IntPtr)type_cocoa.GetField("FoundationLibrary").GetValue(null); |
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.
Static inline initializations are executed in the file order. The code is actually already depending on this in the previous lines.
CodeFactor should be aware about the member complexity before this PR 😟 |
I sort of disagree with enabling the ones that have to then be explicitly suppressed due to a lack of better alternative.
Personally I'd be fine with enabling these if those two were plain warnings. But it seems we currently have a very binary approach of error/no error. Oh, and I think codefactor just re-complains whenever a file with previously-dismissed warnings is touched. |
I'm neutual on this. Just tried it and find it's only complained in very few places.
I just think plain supression is less work than creating a splited rule set for tests. It supports inheriting, so not much work neither.
The analyzer seems not aware on what's the element type.
Big project should have all won't-fixes suppressed, or it will be hard to distinguish meaningful ones from them. |
@@ -59,7 +59,7 @@ internal bool Active | |||
} | |||
else | |||
{ | |||
timeEndPeriod(period); | |||
_ = timeEndPeriod(period); |
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.
Disagree with this style.
@@ -405,7 +405,9 @@ internal static class Interpolation<TValue> | |||
{ | |||
public static readonly InterpolationFunc<TValue> FUNCTION; | |||
|
|||
#pragma warning disable CA1810 // Initialize reference type static fields inline |
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.
You can make these into fields. I'd previously done it in the past, though it didn't lead to significant performance differences (generally the case with static ctor pre-checks that the JIT/EE does) so I didn't commit it.
@@ -38,7 +38,9 @@ public void TestEmptyRectangularToJagged() | |||
public void TestEmptyJaggedToRectangular() | |||
{ | |||
int[,] result = null; | |||
Assert.DoesNotThrow(() => result = new int[0][].ToRectangular()); | |||
#pragma warning disable CA1825 // Avoid zero-length array allocations. |
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.
Does Array.Empty<int[]>
not work?
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.
It just feels not natural in this test case. The test is dealing with [][]
and [,]
, using < []>
doesn't look good.
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.
Empty<int[]>
makes more sense to me than the original case. It's an empty array containing int[]
s, whereas the original code doesn't have the same impact.
@@ -26,9 +26,11 @@ public class TestWebRequest | |||
private static readonly string host; | |||
private static readonly IEnumerable<string> protocols; | |||
|
|||
#pragma warning disable CA1810 // Initialize reference type static fields inline |
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.
I personally disagree with disallowing static ctors. The only reason is performance differences which are extremely hard to benchmark in the first place. I'm ok with converting them over on a per-case basis where appropriate, but even benchmarkdotnet gives BenchmarkClass.StaticCtor: Default -> The method duration is indistinguishable from the empty method duration
.
I would generally benchmarks when making such changes.
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.
I'll change the warning to be disabled. The ones able to be written inline should be fine.
|
||
static Interpolation() | ||
// Should match the definition of InterpolationFunc and ValueAt | ||
private static readonly Type[] parameters = |
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.
Why this and not using reflection?
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.
Reflection will make the code into a complex expression that's too complicated.
The arguments and its reflection target (InterpolationFunc) live in the same file. There shouldn't be risk of out of sync.
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.
What do you mean by "complex expression"? From which perspective? Because it'd be just:
private static Type[] parameters = typeof(InterpolationFunc<TValue>)
.GetMethod(nameof(InterpolationFunc<TValue>.Invoke))
?.GetParameters().Select(p => p.ParameterType).ToArray();
I also don't understand what you mean "shouldn't be risk of out of sync", if we change the arguments of ValueAt
then we'll have to knowingly update this array without the compiler warning us. So yes there is a risk of being out of sync, even if it's in the same file.
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.
If inline initialization is used, the whole initialization of FUNCTION
will be a huge expression. The expression getting the parameters will be inlined.
Reverted the changes that makes it inline, with some small adjust.
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 is still risk of out of sync between ValueAt
declarations and InterpolationFunc
. Creating unused delegates (using direct creation instead of reflection) for them can make compiler error then, but may looks too verbose.
@@ -160,4 +160,15 @@ internal static CacheDependencyDelegate CreateActivator(Type type) | |||
} | |||
} | |||
} | |||
|
|||
/// <summary> | |||
/// The exception that is thrown when intending to cache <see langword="null"/> using <see cref="CachedAttribute"/>. |
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 exception that is thrown when intending to cache <see langword="null"/> using <see cref="CachedAttribute"/>. | |
/// The exception that is thrown when attempting to cache <see langword="null"/> using <see cref="CachedAttribute"/>. |
private static readonly Action<TexturedVertex2D> default_quad_action; | ||
|
||
static TextureGLSingle() | ||
{ | ||
QuadBatch<TexturedVertex2D> quadBatch = new QuadBatch<TexturedVertex2D>(100, 1000); | ||
default_quad_action = quadBatch.AddAction; | ||
} | ||
private static readonly Action<TexturedVertex2D> default_quad_action = new QuadBatch<TexturedVertex2D>(100, 1000).AddAction; |
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.
Got a link for this?
Oh...there're some rules I've already cleaned 3 years ago.
FxCop was old and containing some unsuitable rules. But it's now maintained by the official compiler team, and adding many new morden rules, and more official rules are going into them, so I pick it.
I've turned on the outstanding ones, and turned off ones conflicting with our current design.
I intended to add comments in the rule set, but VS designer will always remove them.
Supressing some hard-to-apply instances to very valuable diagnostics.