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
KnownReference: Add support for testing for referenced libraries #6726
Changes from 21 commits
695358b
7547b03
6b5d8f4
5f39f96
c739408
d3842bd
92deb06
8422676
ec96228
ab95c9b
4caa689
af2cdc8
c4ae3a4
657c32e
9bef92a
9450d62
886b451
98364c7
abed89f
d619346
6d341b1
078a782
f9bbb8a
0cd2ee6
88e2f90
d2794d2
98ddc1b
0c21bd5
54ed0dd
5117f76
cb7633f
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 |
---|---|---|
|
@@ -24,4 +24,17 @@ internal static class CompilationExtensions | |
{ | ||
public static INamedTypeSymbol GetTypeByMetadataName(this Compilation compilation, KnownType knownType) => | ||
compilation.GetTypeByMetadataName(knownType.FullName); | ||
|
||
public static IMethodSymbol GetTypeMethod(this Compilation compilation, SpecialType type, string methodName) => | ||
(IMethodSymbol)compilation.GetSpecialType(type) | ||
.GetMembers(methodName) | ||
.SingleOrDefault(); | ||
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. This could be a single line |
||
|
||
public static bool IsNetFrameworkTarget(this Compilation compilation) => | ||
// There's no direct way of checking compilation target framework yet (09/2020). | ||
// See https://github.com/dotnet/roslyn/issues/3798 | ||
compilation.ObjectType.ContainingAssembly.Name == "mscorlib"; | ||
Comment on lines
+31
to
+34
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. This is somewhat overlapping with While this extension can live here, the implementation should be in that class to have this kind of ugly detection should live on one place. 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. The implementations can not easily be merged. I created #6751 |
||
|
||
public static bool References(this Compilation compilation, KnownReference reference) | ||
=> reference.IsReferencedBy(compilation); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,77 @@ | ||
/* | ||
* SonarAnalyzer for .NET | ||
* Copyright (C) 2015-2023 SonarSource SA | ||
* mailto: contact AT sonarsource DOT com | ||
* | ||
* This program is free software; you can redistribute it and/or | ||
* modify it under the terms of the GNU Lesser General Public | ||
* License as published by the Free Software Foundation; either | ||
* version 3 of the License, or (at your option) any later version. | ||
* | ||
* This program is distributed in the hope that it will be useful, | ||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
* Lesser General Public License for more details. | ||
* | ||
* You should have received a copy of the GNU Lesser General Public License | ||
* along with this program; if not, write to the Free Software Foundation, | ||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | ||
*/ | ||
|
||
using System.ComponentModel; | ||
|
||
namespace SonarAnalyzer.Helpers; | ||
|
||
public sealed partial class KnownReference | ||
{ | ||
private const StringComparison AssemblyNameComparission = StringComparison.OrdinalIgnoreCase; | ||
|
||
[EditorBrowsable(EditorBrowsableState.Never)] | ||
internal static class Predicates | ||
{ | ||
internal static Func<AssemblyIdentity, bool> NameIs(string name) => | ||
x => x.Name.Equals(name, AssemblyNameComparission); | ||
|
||
internal static Func<AssemblyIdentity, bool> StartsWith(string name) => | ||
x => x.Name.StartsWith(name, AssemblyNameComparission); | ||
|
||
internal static Func<AssemblyIdentity, bool> EndsWith(string name) => | ||
x => x.Name.EndsWith(name, AssemblyNameComparission); | ||
|
||
internal static Func<AssemblyIdentity, bool> Contains(string name) => | ||
x => x.Name.IndexOf(name, 0, AssemblyNameComparission) >= 0; | ||
|
||
internal static Func<AssemblyIdentity, bool> VersionLowerThen(string version) => | ||
VersionLowerThen(Version.Parse(version)); | ||
|
||
internal static Func<AssemblyIdentity, bool> VersionLowerThen(Version version) => | ||
x => x.Version < version; | ||
|
||
internal static Func<AssemblyIdentity, bool> VersionGreaterOrEqual(string version) => | ||
VersionGreaterOrEqual(Version.Parse(version)); | ||
|
||
internal static Func<AssemblyIdentity, bool> VersionGreaterOrEqual(Version version) => | ||
x => x.Version >= version; | ||
|
||
internal static Func<AssemblyIdentity, bool> VersionBetween(string from, string to) => | ||
VersionBetween(Version.Parse(from), Version.Parse(to)); | ||
|
||
internal static Func<AssemblyIdentity, bool> VersionBetween(Version from, Version to) => | ||
x => x.Version >= from && x.Version <= to; | ||
|
||
internal static Func<AssemblyIdentity, bool> OptionalPublicKeyTokenIs(string key) => | ||
x => !x.HasPublicKey || PublicKeyEqualHex(x, key); | ||
|
||
internal static Func<AssemblyIdentity, bool> PublicKeyTokenIs(string key) => | ||
x => x.HasPublicKey && PublicKeyEqualHex(x, key); | ||
|
||
private static bool PublicKeyEqualHex(AssemblyIdentity identity, string hexString) | ||
{ | ||
var normalizedHexString = hexString.Replace("-", string.Empty); | ||
return ArraysEqual(identity.PublicKeyToken.ToArray(), normalizedHexString) || ArraysEqual(identity.PublicKey.ToArray(), normalizedHexString); | ||
|
||
static bool ArraysEqual(byte[] key, string hexString) => | ||
BitConverter.ToString(key).Replace("-", string.Empty).Equals(hexString, StringComparison.OrdinalIgnoreCase); | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
@@ -0,0 +1,46 @@ | ||||||
/* | ||||||
* SonarAnalyzer for .NET | ||||||
* Copyright (C) 2015-2023 SonarSource SA | ||||||
* mailto: contact AT sonarsource DOT com | ||||||
* | ||||||
* This program is free software; you can redistribute it and/or | ||||||
* modify it under the terms of the GNU Lesser General Public | ||||||
* License as published by the Free Software Foundation; either | ||||||
* version 3 of the License, or (at your option) any later version. | ||||||
* | ||||||
* This program is distributed in the hope that it will be useful, | ||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||||||
* Lesser General Public License for more details. | ||||||
* | ||||||
* You should have received a copy of the GNU Lesser General Public License | ||||||
* along with this program; if not, write to the Free Software Foundation, | ||||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | ||||||
*/ | ||||||
|
||||||
using static SonarAnalyzer.Helpers.KnownReference.Predicates; | ||||||
|
||||||
namespace SonarAnalyzer.Helpers | ||||||
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. Could be file scoped namespace |
||||||
{ | ||||||
public sealed partial class KnownReference | ||||||
{ | ||||||
private readonly Func<IEnumerable<AssemblyIdentity>, bool> predicate; | ||||||
|
||||||
public static KnownReference XUnit_Assert { get; } = new( | ||||||
NameIs("xunit.assert"), | ||||||
NameIs("xunit").And(VersionLowerThen("2.0"))); | ||||||
|
||||||
internal KnownReference(Func<AssemblyIdentity, bool> predicate, params Func<AssemblyIdentity, bool>[] or) | ||||||
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. This will simplify it quite a lot. As this is supposed to be instantiated only from within this class (and therefore it would be beneficial to have it
Suggested change
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. This would be a bad API design. We can enforce proper usage at compile time and should do so. |
||||||
: this(predicate is null || or.Any(x => x is null) | ||||||
? throw new ArgumentNullException(nameof(predicate), "All predicates must be non-null.") | ||||||
: identities => identities.Any(identitiy => predicate(identitiy) || or.Any(orPredicate => orPredicate(identitiy)))) | ||||||
{ | ||||||
} | ||||||
|
||||||
internal KnownReference(Func<IEnumerable<AssemblyIdentity>, bool> predicate) => | ||||||
this.predicate = predicate ?? throw new ArgumentNullException(nameof(predicate)); | ||||||
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. We don't need two constructors, this class is meant to be created only with the previous one. Assign the predicate there. Those few UTs will survive without it ,they can use the other one anyway
Suggested change
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. This ctor is needed for cases where more than one assembly reference needs to be present (e.g. WPF: WindowsBase, PresentationCore, and PresentationFramework). |
||||||
|
||||||
public bool IsReferencedBy(Compilation compilation) => | ||||||
predicate(compilation.ReferencedAssemblyNames); | ||||||
} | ||||||
} |
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.