Skip to content

Commit 5e08fa1

Browse files
authored
Initial code analyzer for Microsoft.ML, use limited StyleCop (#557)
* Initial code analyzer for Microsoft.ML Adds code analysis initially for correct usage of common Contracts.Except/Check patterns, naming conventions, variable usage and initializations, and other idioms used throughout the Microsoft.ML codebase. Enables analysis on Microsoft.ML projects. Also added StyleCop, with most rules currently disabled, but rules on whitespace, declaration modifier ordering, explicit access modifiers, and inteface naming check. * Analyzer is .NET Standard 1.3 to avoid problems with IDE1003. dotnet/roslyn#22368 * Projects in `src` can not use analyzer by setting `UseMLCodeAnalyzer` project property to false.
1 parent 8cfa2ed commit 5e08fa1

File tree

299 files changed

+4063
-1109
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

299 files changed

+4063
-1109
lines changed

Microsoft.ML.sln

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,9 @@ MinimumVisualStudioVersion = 10.0.40219.1
55
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.ML.Core", "src\Microsoft.ML.Core\Microsoft.ML.Core.csproj", "{A6CA6CC6-5D7C-4D7F-A0F5-35E14B383B0A}"
66
EndProject
77
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{09EADF06-BE25-4228-AB53-95AE3E15B530}"
8+
ProjectSection(SolutionItems) = preProject
9+
src\Source.ruleset = src\Source.ruleset
10+
EndProjectSection
811
EndProject
912
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{AED9C836-31E3-4F3F-8ABC-929555D3F3C4}"
1013
EndProject
@@ -88,6 +91,12 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Microsoft.ML.CpuMath", "Mic
8891
pkg\Microsoft.ML.CpuMath\Microsoft.ML.CpuMath.symbols.nupkgproj = pkg\Microsoft.ML.CpuMath\Microsoft.ML.CpuMath.symbols.nupkgproj
8992
EndProjectSection
9093
EndProject
94+
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tools-local", "tools-local", "{7F13E156-3EBA-4021-84A5-CD56BA72F99E}"
95+
EndProject
96+
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.ML.CodeAnalyzer", "tools-local\Microsoft.ML.CodeAnalyzer\Microsoft.ML.CodeAnalyzer.csproj", "{B4E55B2D-2A92-46E7-B72F-E76D6FD83440}"
97+
EndProject
98+
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.ML.CodeAnalyzer.Tests", "test\Microsoft.ML.CodeAnalyzer.Tests\Microsoft.ML.CodeAnalyzer.Tests.csproj", "{3E4ABF07-7970-4BE6-B45B-A13D3C397545}"
99+
EndProject
91100
Global
92101
GlobalSection(SolutionConfigurationPlatforms) = preSolution
93102
Debug|Any CPU = Debug|Any CPU
@@ -304,6 +313,22 @@ Global
304313
{DCF46B79-1FDB-4DBA-A263-D3D64E3AAA27}.Release|Any CPU.Build.0 = Release|Any CPU
305314
{DCF46B79-1FDB-4DBA-A263-D3D64E3AAA27}.Release-Intrinsics|Any CPU.ActiveCfg = Release|Any CPU
306315
{DCF46B79-1FDB-4DBA-A263-D3D64E3AAA27}.Release-Intrinsics|Any CPU.Build.0 = Release|Any CPU
316+
{B4E55B2D-2A92-46E7-B72F-E76D6FD83440}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
317+
{B4E55B2D-2A92-46E7-B72F-E76D6FD83440}.Debug|Any CPU.Build.0 = Debug|Any CPU
318+
{B4E55B2D-2A92-46E7-B72F-E76D6FD83440}.Debug-Intrinsics|Any CPU.ActiveCfg = Debug|Any CPU
319+
{B4E55B2D-2A92-46E7-B72F-E76D6FD83440}.Debug-Intrinsics|Any CPU.Build.0 = Debug|Any CPU
320+
{B4E55B2D-2A92-46E7-B72F-E76D6FD83440}.Release|Any CPU.ActiveCfg = Release|Any CPU
321+
{B4E55B2D-2A92-46E7-B72F-E76D6FD83440}.Release|Any CPU.Build.0 = Release|Any CPU
322+
{B4E55B2D-2A92-46E7-B72F-E76D6FD83440}.Release-Intrinsics|Any CPU.ActiveCfg = Release|Any CPU
323+
{B4E55B2D-2A92-46E7-B72F-E76D6FD83440}.Release-Intrinsics|Any CPU.Build.0 = Release|Any CPU
324+
{3E4ABF07-7970-4BE6-B45B-A13D3C397545}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
325+
{3E4ABF07-7970-4BE6-B45B-A13D3C397545}.Debug|Any CPU.Build.0 = Debug|Any CPU
326+
{3E4ABF07-7970-4BE6-B45B-A13D3C397545}.Debug-Intrinsics|Any CPU.ActiveCfg = Debug|Any CPU
327+
{3E4ABF07-7970-4BE6-B45B-A13D3C397545}.Debug-Intrinsics|Any CPU.Build.0 = Debug|Any CPU
328+
{3E4ABF07-7970-4BE6-B45B-A13D3C397545}.Release|Any CPU.ActiveCfg = Release|Any CPU
329+
{3E4ABF07-7970-4BE6-B45B-A13D3C397545}.Release|Any CPU.Build.0 = Release|Any CPU
330+
{3E4ABF07-7970-4BE6-B45B-A13D3C397545}.Release-Intrinsics|Any CPU.ActiveCfg = Release|Any CPU
331+
{3E4ABF07-7970-4BE6-B45B-A13D3C397545}.Release-Intrinsics|Any CPU.Build.0 = Release|Any CPU
307332
EndGlobalSection
308333
GlobalSection(SolutionProperties) = preSolution
309334
HideSolutionNode = FALSE
@@ -340,6 +365,8 @@ Global
340365
{001F3B4E-FBE4-4001-AFD2-A6A989CD1C25} = {09EADF06-BE25-4228-AB53-95AE3E15B530}
341366
{DCF46B79-1FDB-4DBA-A263-D3D64E3AAA27} = {09EADF06-BE25-4228-AB53-95AE3E15B530}
342367
{BF66A305-DF10-47E4-8D81-42049B149D2B} = {D3D38B03-B557-484D-8348-8BADEE4DF592}
368+
{B4E55B2D-2A92-46E7-B72F-E76D6FD83440} = {7F13E156-3EBA-4021-84A5-CD56BA72F99E}
369+
{3E4ABF07-7970-4BE6-B45B-A13D3C397545} = {AED9C836-31E3-4F3F-8ABC-929555D3F3C4}
343370
EndGlobalSection
344371
GlobalSection(ExtensibilityGlobals) = postSolution
345372
SolutionGuid = {41165AF1-35BB-4832-A189-73060F82B01D}

build/Dependencies.props

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,6 @@
77
<SystemCodeDomPackageVersion>4.4.0</SystemCodeDomPackageVersion>
88
<SystemReflectionEmitLightweightPackageVersion>4.3.0</SystemReflectionEmitLightweightPackageVersion>
99
<PublishSymbolsPackageVersion>1.0.0-beta-62824-02</PublishSymbolsPackageVersion>
10-
<LightGBMPackageVersion>2.1.2.2</LightGBMPackageVersion>
10+
<LightGBMPackageVersion>2.1.2.2</LightGBMPackageVersion>
1111
</PropertyGroup>
1212
</Project>

src/Directory.Build.props

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,18 @@
1111
<NoWarn>$(NoWarn);1591</NoWarn>
1212
<WarningsNotAsErrors>$(WarningsNotAsErrors);1591</WarningsNotAsErrors>
1313

14-
14+
<CodeAnalysisRuleSet>$(MSBuildThisFileDirectory)\Source.ruleset</CodeAnalysisRuleSet>
1515
</PropertyGroup>
1616

17+
<ItemGroup>
18+
<ProjectReference
19+
Condition="'$(UseMLCodeAnalyzer)' != 'false' and '$(MSBuildProjectExtension)' == '.csproj'"
20+
Include="$(MSBuildThisFileDirectory)\..\tools-local\Microsoft.ML.CodeAnalyzer\Microsoft.ML.CodeAnalyzer.csproj">
21+
<ReferenceOutputAssembly>false</ReferenceOutputAssembly>
22+
<OutputItemType>Analyzer</OutputItemType>
23+
</ProjectReference>
24+
<PackageReference Condition="'$(UseStyleCopAnalyzer)' != 'false' and '$(MSBuildProjectExtension)' == '.csproj'"
25+
Include="StyleCop.Analyzers" Version="1.1.0-beta008" PrivateAssets="All" />
26+
</ItemGroup>
27+
1728
</Project>

src/Microsoft.ML.Api/ApiUtils.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ private static OpCode GetAssignmentOpCode(Type t)
4646

4747
/// <summary>
4848
/// Each of the specialized 'peek' methods copies the appropriate field value of an instance of T
49-
/// into the provided buffer. So, the call is 'peek(userObject, ref destination)' and the logic is
49+
/// into the provided buffer. So, the call is 'peek(userObject, ref destination)' and the logic is
5050
/// indentical to 'destination = userObject.##FIELD##', where ##FIELD## is defined per peek method.
5151
/// </summary>
5252
internal static Delegate GeneratePeek<TOwn, TRow>(InternalSchemaDefinition.Column column)
@@ -83,7 +83,7 @@ private static Delegate GeneratePeek<TOwn, TRow, TValue>(FieldInfo fieldInfo, Op
8383

8484
/// <summary>
8585
/// Each of the specialized 'poke' methods sets the appropriate field value of an instance of T
86-
/// to the provided value. So, the call is 'peek(userObject, providedValue)' and the logic is
86+
/// to the provided value. So, the call is 'peek(userObject, providedValue)' and the logic is
8787
/// indentical to 'userObject.##FIELD## = providedValue', where ##FIELD## is defined per poke method.
8888
/// </summary>
8989
internal static Delegate GeneratePoke<TOwn, TRow>(InternalSchemaDefinition.Column column)

src/Microsoft.ML.Api/CodeGenerationUtils.cs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -97,12 +97,12 @@ public static string GetCSharpString(CSharpCodeProvider codeProvider, string val
9797
}
9898

9999
/// <summary>
100-
/// Gets the C# strings representing the type name for a variable corresponding to
101-
/// the <see cref="IDataView"/> column type.
102-
///
103-
/// If the type is a vector, then <paramref name="useVBuffer"/> controls whether the array field is
100+
/// Gets the C# strings representing the type name for a variable corresponding to
101+
/// the <see cref="IDataView"/> column type.
102+
///
103+
/// If the type is a vector, then <paramref name="useVBuffer"/> controls whether the array field is
104104
/// generated or <see cref="VBuffer{T}"/>.
105-
///
105+
///
106106
/// If additional attributes are required, they are appended to the <paramref name="attributes"/> list.
107107
/// </summary>
108108
private static string GetBackingTypeName(ColumnType colType, bool useVBuffer, List<string> attributes)

src/Microsoft.ML.Api/ComponentCreation.cs

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,14 @@
1111
namespace Microsoft.ML.Runtime.Api
1212
{
1313
/// <summary>
14-
/// This class defines extension methods for an <see cref="IHostEnvironment"/> to facilitate creating
14+
/// This class defines extension methods for an <see cref="IHostEnvironment"/> to facilitate creating
1515
/// components (loaders, transforms, trainers, scorers, evaluators, savers).
1616
/// </summary>
1717
public static class ComponentCreation
1818
{
1919
/// <summary>
2020
/// Create a new data view which is obtained by appending all columns of all the source data views.
21-
/// If the data views are of different length, the resulting data view will have the length equal to the
21+
/// If the data views are of different length, the resulting data view will have the length equal to the
2222
/// length of the shortest source.
2323
/// </summary>
2424
/// <param name="env">The host environment to use.</param>
@@ -59,11 +59,11 @@ public static RoleMappedData CreateExamples(this IHostEnvironment env, IDataView
5959
/// Create a new <see cref="IDataView"/> over an in-memory collection of the items of user-defined type.
6060
/// The user maintains ownership of the <paramref name="data"/> and the resulting data view will
6161
/// never alter the contents of the <paramref name="data"/>.
62-
/// Since <see cref="IDataView"/> is assumed to be immutable, the user is expected to not
62+
/// Since <see cref="IDataView"/> is assumed to be immutable, the user is expected to not
6363
/// modify the contents of <paramref name="data"/> while the data view is being actively cursored.
64-
///
64+
///
6565
/// One typical usage for in-memory data view could be: create the data view, train a predictor.
66-
/// Once the predictor is fully trained, modify the contents of the underlying collection and
66+
/// Once the predictor is fully trained, modify the contents of the underlying collection and
6767
/// train another predictor.
6868
/// </summary>
6969
/// <typeparam name="TRow">The user-defined item type.</typeparam>
@@ -88,9 +88,9 @@ public static IDataView CreateDataView<TRow>(this IHostEnvironment env, IList<TR
8888
/// Since <see cref="IDataView"/> is assumed to be immutable, the user is expected to support
8989
/// multiple enumeration of the <paramref name="data"/> that would return the same results, unless
9090
/// the user knows that the data will only be cursored once.
91-
///
91+
///
9292
/// One typical usage for streaming data view could be: create the data view that lazily loads data
93-
/// as needed, then apply pre-trained transformations to it and cursor through it for transformation
93+
/// as needed, then apply pre-trained transformations to it and cursor through it for transformation
9494
/// results. This is how <see cref="BatchPredictionEngine{TSrc,TDst}"/> is implemented.
9595
/// </summary>
9696
/// <typeparam name="TRow">The user-defined item type.</typeparam>
@@ -191,7 +191,7 @@ public static PredictionEngine<TSrc, TDst> CreatePredictionEngine<TSrc, TDst>(th
191191
/// <summary>
192192
/// Create a prediction engine.
193193
/// This encapsulates the 'classic' prediction problem, where the input is denoted by the float array of features,
194-
/// and the output is a float score. For binary classification predictors that can output probability, there are output
194+
/// and the output is a float score. For binary classification predictors that can output probability, there are output
195195
/// fields that report the predicted label and probability.
196196
/// </summary>
197197
/// <param name="env">The host environment to use.</param>
@@ -207,7 +207,7 @@ public static SimplePredictionEngine CreateSimplePredictionEngine(this IHostEnvi
207207

208208
/// <summary>
209209
/// Load the transforms (but not loader) from the model steram and apply them to the specified data.
210-
/// It is acceptable to have no transforms in the model stream: in this case the original
210+
/// It is acceptable to have no transforms in the model stream: in this case the original
211211
/// <paramref name="data"/> will be returned.
212212
/// </summary>
213213
/// <param name="env">The host environment to use.</param>

src/Microsoft.ML.Api/DataViewConstructionUtils.cs

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -285,7 +285,7 @@ private Delegate CreateGetter(int index)
285285
}
286286

287287
// REVIEW: The converting getter invokes a type conversion delegate on every call, so it's inherently slower
288-
// than the 'direct' getter. We don't have good indication of this to the user, and the selection
288+
// than the 'direct' getter. We don't have good indication of this to the user, and the selection
289289
// of affected types is pretty arbitrary (signed integers and bools, but not uints and floats).
290290
private Delegate CreateConvertingArrayGetterDelegate<TSrc, TDst>(int index, Func<TSrc, TDst> convert)
291291
{
@@ -396,7 +396,7 @@ private void CheckColumnInRange(int columnIndex)
396396
}
397397

398398
/// <summary>
399-
/// An in-memory data view based on the IList of data.
399+
/// An in-memory data view based on the IList of data.
400400
/// Supports shuffling.
401401
/// </summary>
402402
private sealed class ListDataView<TRow> : DataViewBase<TRow>
@@ -492,11 +492,11 @@ protected override bool MoveManyCore(long count)
492492
}
493493

494494
/// <summary>
495-
/// An in-memory data view based on the IEnumerable of data.
495+
/// An in-memory data view based on the IEnumerable of data.
496496
/// Doesn't support shuffling.
497-
///
497+
///
498498
/// This class is public because prediction engine wants to call its <see cref="SetData"/>
499-
/// for performance reasons.
499+
/// for performance reasons.
500500
/// </summary>
501501
public sealed class StreamingDataView<TRow> : DataViewBase<TRow>
502502
where TRow : class
@@ -578,7 +578,7 @@ protected override bool MoveNextCore()
578578

579579
/// <summary>
580580
/// This represents the 'infinite data view' over one (mutable) user-defined object.
581-
/// The 'current row' object can be updated at any time, this will affect all the
581+
/// The 'current row' object can be updated at any time, this will affect all the
582582
/// newly created cursors, but not the ones already existing.
583583
/// </summary>
584584
public sealed class SingleRowLoopDataView<TRow> : DataViewBase<TRow>
@@ -731,7 +731,7 @@ public abstract partial class MetadataInfo
731731
/// </summary>
732732
public ColumnType MetadataType;
733733
/// <summary>
734-
/// The string identifier of the metadata. Some identifiers have special meaning,
734+
/// The string identifier of the metadata. Some identifiers have special meaning,
735735
/// like "SlotNames", but any other identifiers can be used.
736736
/// </summary>
737737
public readonly string Kind;
@@ -757,7 +757,7 @@ public sealed class MetadataInfo<T> : MetadataInfo
757757
/// <summary>
758758
/// Constructor for metadata of value type T.
759759
/// </summary>
760-
/// <param name="kind">The string identifier of the metadata. Some identifiers have special meaning,
760+
/// <param name="kind">The string identifier of the metadata. Some identifiers have special meaning,
761761
/// like "SlotNames", but any other identifiers can be used.</param>
762762
/// <param name="value">Metadata value.</param>
763763
/// <param name="metadataType">Type of the metadata.</param>

src/Microsoft.ML.Api/GenerateCodeCommand.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ namespace Microsoft.ML.Runtime.Api
2121
{
2222
/// <summary>
2323
/// Generates the sample prediction code for a given model file, with correct input and output classes.
24-
///
24+
///
2525
/// REVIEW: Consider adding support for generating VBuffers instead of arrays, maybe for high dimensionality vectors.
2626
/// </summary>
2727
public sealed class GenerateCodeCommand : ICommand
@@ -45,7 +45,7 @@ public sealed class Arguments
4545
ShortName = "sparse", SortOrder = 102)]
4646
public bool SparseVectorDeclaration;
4747

48-
// REVIEW: currently, it's only used in unit testing to not generate the paths into the test output folder.
48+
// REVIEW: currently, it's only used in unit testing to not generate the paths into the test output folder.
4949
// However, it might be handy for automation scenarios, so I've added this as a hidden option.
5050
[Argument(ArgumentType.AtMostOnce, HelpText = "A location of the model file to put into generated file", Hide = true)]
5151
public string ModelNameOverride;

src/Microsoft.ML.Api/InternalSchemaDefinition.cs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -76,12 +76,12 @@ private Column(string columnName, ColumnType columnType, FieldInfo fieldInfo = n
7676
}
7777

7878
/// <summary>
79-
/// Function that checks whether the InternalSchemaDefinition.Column is a valid one.
79+
/// Function that checks whether the InternalSchemaDefinition.Column is a valid one.
8080
/// To be valid, the Column must:
8181
/// 1. Have non-empty values for ColumnName and ColumnType
8282
/// 2. Have a non-empty value for FieldInfo iff it is a field column, else
8383
/// ReturnParameterInfo and Generator iff it is a computed column
84-
/// 3. Generator must have the method inputs (TRow rowObject,
84+
/// 3. Generator must have the method inputs (TRow rowObject,
8585
/// long position, ref TValue outputValue) in that order.
8686
/// </summary>
8787
[Conditional("DEBUG")]
@@ -133,7 +133,7 @@ private InternalSchemaDefinition(Column[] columns)
133133
/// <summary>
134134
/// Given a field info on a type, returns whether this appears to be a vector type,
135135
/// and also the associated data kind for this type. If a data kind could not
136-
/// be determined, this will throw.
136+
/// be determined, this will throw.
137137
/// </summary>
138138
/// <param name="fieldInfo">The field info to inspect.</param>
139139
/// <param name="isVector">Whether this appears to be a vector type.</param>
@@ -149,7 +149,7 @@ public static void GetVectorAndKind(FieldInfo fieldInfo, out bool isVector, out
149149
/// <summary>
150150
/// Given a parameter info on a type, returns whether this appears to be a vector type,
151151
/// and also the associated data kind for this type. If a data kind could not
152-
/// be determined, this will throw.
152+
/// be determined, this will throw.
153153
/// </summary>
154154
/// <param name="parameterInfo">The parameter info to inspect.</param>
155155
/// <param name="isVector">Whether this appears to be a vector type.</param>
@@ -165,7 +165,7 @@ public static void GetVectorAndKind(ParameterInfo parameterInfo, out bool isVect
165165
/// <summary>
166166
/// Given a type and name for a variable, returns whether this appears to be a vector type,
167167
/// and also the associated data kind for this type. If a data kind could not
168-
/// be determined, this will throw.
168+
/// be determined, this will throw.
169169
/// </summary>
170170
/// <param name="rawType">The type of the variable to inspect.</param>
171171
/// <param name="name">The name of the variable to inspect.</param>
@@ -222,7 +222,7 @@ public static InternalSchemaDefinition Create(Type userType, SchemaDefinition us
222222
col.MemberName,
223223
userType.FullName);
224224

225-
//Clause to handle the field that may be used to expose the cursor channel.
225+
//Clause to handle the field that may be used to expose the cursor channel.
226226
//This field does not need a column.
227227
if (fieldInfo.FieldType == typeof(IChannel))
228228
continue;
@@ -251,7 +251,7 @@ public static InternalSchemaDefinition Create(Type userType, SchemaDefinition us
251251
}
252252
else
253253
{
254-
// Make sure that the types are compatible with the declared type, including
254+
// Make sure that the types are compatible with the declared type, including
255255
// whether it is a vector type.
256256
if (isVector != col.ColumnType.IsVector)
257257
{

0 commit comments

Comments
 (0)