Skip to content

Commit

Permalink
Update Diagnostic rules (#685)
Browse files Browse the repository at this point in the history
* update diagnostic messages

* change wme to cswinrt

* Add notes to rules in AnalyzerReleases

* fix bug in unittests

* fix bug in ref diagnostic being thrown
  • Loading branch information
j0shuams authored Jan 26, 2021
2 parents 28eae2e + 02894d7 commit 5351b4b
Show file tree
Hide file tree
Showing 8 changed files with 174 additions and 130 deletions.
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,4 @@ global.json
nuget/Microsoft.Windows.CsWinRT.Prerelease.targets
*.binlog
vs_buildtools.exe
.buildtools
.buildtools
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
; Shipped analyzer releases
; https://github.com/dotnet/roslyn-analyzers/blob/master/src/Microsoft.CodeAnalysis.Analyzers/ReleaseTrackingAnalyzers.Help.md

33 changes: 33 additions & 0 deletions src/Authoring/WinRT.SourceGenerator/AnalyzerReleases.Unshipped.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
; Unshipped analyzer release
; https://github.com/dotnet/roslyn-analyzers/blob/master/src/Microsoft.CodeAnalysis.Analyzers/ReleaseTrackingAnalyzers.Help.md

### New Rules
Rule ID | Category | Severity | Notes
--------|----------|----------|-------
CsWinRT1000 | Usage | Error | Property should have public `get` method
CsWinRT1001 | Usage | Error | Namespaces should match the assembly namespace or be child namespaces of the assembly namespace
CsWinRT1002 | Usage | Error | Namespaces cannot differ only by case
CsWinRT1003 | Usage | Error | Component must have at least on public type
CsWinRT1004 | Usage | Error | Public types cannot be generic
CsWinRT1005 | Usage | Error | Classes exposed to CsWinRT should be sealed
CsWinRT1006 | Usage | Error | Do not expose unsupported type
CsWinRT1007 | Usage | Error | Structs should contain at least one public field
CsWinRT1008 | Usage | Error | Interfaces should not inherit interfaces that are not valid in Windows Runtime
CsWinRT1009 | Usage | Error | Class should not have multiple constructors that take the same amount of parameters
CsWinRT1010 | Usage | Error | Methods should not use parameter names that conflict with generated parameter names
CsWinRT1011 | Usage | Error | Structs should not have private fields
CsWinRT1012 | Usage | Error | Structs should not have a constant field
CsWinRT1013 | Usage | Error | Structs should only contain basic types or other structs
CsWinRT1014 | Usage | Error | Types should not overload an operator
CsWinRT1015 | Usage | Error | Do not use `DefaultOverloadAttribute` more than once for a set of overloads
CsWinRT1016 | Usage | Error | Exactly one overload should be marked as DefaultOverload
CsWinRT1017 | Usage | Error | Array types should be one dimensional, not jagged
CsWinRT1018 | Usage | Error | Array types should be one dimensional
CsWinRT1019 | Usage | Error | Do not use the `System.Array` type for array parameters or array return values
CsWinRT1020 | Usage | Error | Do not pass parameters by `ref`
CsWinRT1021 | Usage | Error | Array parameters should not be marked `InAttribute` or `OutAttribute`
CsWinRT1022 | Usage | Error | Parameters should not be marked `InAttribute` or `OutAttribute`
CsWinRT1023 | Usage | Error | Array parameters should not be marked both `ReadOnlyArrayAttribute` and `WriteOnlyArrayAttribute`
CsWinRT1024 | Usage | Error | Array parameter marked `out` should not be declared `ReadOnlyArrayAttribute`
CsWinRT1025 | Usage | Error | Array parameter should be marked either `ReadOnlyArrayAttribute` or `WriteOnlyArrayAttribute`
CsWinRT1026 | Usage | Error | Non-array parameter should not be marked `ReadOnlyArrayAttribute` or `WriteOnlyArrayAttribute`
2 changes: 1 addition & 1 deletion src/Authoring/WinRT.SourceGenerator/DiagnosticHelpers.cs
Original file line number Diff line number Diff line change
Expand Up @@ -193,7 +193,7 @@ private void ParameterHasAttributeErrors(MethodDeclarationSyntax method)
// Nothing can be marked `ref`
if (HasModifier(param, SyntaxKind.RefKeyword))
{
Report(WinRTRules.RefParameterFound, method.GetLocation(), param.Identifier);
Report(WinRTRules.RefParameterFound, method.GetLocation(), method.Identifier, param.Identifier);
}

if (ParamHasInOrOutAttribute(param))
Expand Down
32 changes: 16 additions & 16 deletions src/Authoring/WinRT.SourceGenerator/Generator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -78,12 +78,12 @@ private static string GetCsWinRTWindowsMetadata(GeneratorExecutionContext contex
return cswinrtWindowsMetadata;
}

private static string GetCsWinRTDependentMetadata(GeneratorExecutionContext context)
{
context.AnalyzerConfigOptions.GlobalOptions.TryGetValue("build_property.CsWinRTAuthoringInputs", out var winmds);
return winmds;
}

private static string GetCsWinRTDependentMetadata(GeneratorExecutionContext context)
{
context.AnalyzerConfigOptions.GlobalOptions.TryGetValue("build_property.CsWinRTAuthoringInputs", out var winmds);
return winmds;
}

private string GetTempFolder(bool clearSourceFilesFromFolder = false)
{
if(_tempFolder == null || !File.Exists(_tempFolder))
Expand Down Expand Up @@ -113,15 +113,15 @@ private void GenerateSources(GeneratorExecutionContext context)
string winmdFile = GetWinmdOutputFile(context);
string outputDir = GetTempFolder(true);
string windowsMetadata = GetCsWinRTWindowsMetadata(context);
string winmds = GetCsWinRTDependentMetadata(context);

string arguments = string.Format(
"-component -input \"{0}\" -input {1} -include {2} -output \"{3}\" -input {4} -verbose",
winmdFile,
windowsMetadata,
assemblyName,
outputDir,
winmds);
string winmds = GetCsWinRTDependentMetadata(context);

string arguments = string.Format(
"-component -input \"{0}\" -input {1} -include {2} -output \"{3}\" -input {4} -verbose",
winmdFile,
windowsMetadata,
assemblyName,
outputDir,
winmds);
Logger.Log("Running " + cswinrtExe + " " + arguments);

var processInfo = new ProcessStartInfo
Expand Down Expand Up @@ -201,7 +201,7 @@ public void Execute(GeneratorExecutionContext context)
{
return;
}

Logger.Initialize(context);


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,5 +21,11 @@
<PackageReference Include="Microsoft.CodeAnalysis.CSharp.Workspaces" Version="3.8.0-4.20472.6" PrivateAssets="all" />
<PackageReference Include="Microsoft.CodeAnalysis.Analyzers" Version="3.3.0" PrivateAssets="all" />
</ItemGroup>


<!-- Analyzer Release Tracking -->
<ItemGroup>
<AdditionalFiles Include="AnalyzerReleases.Shipped.md" />
<AdditionalFiles Include="AnalyzerReleases.Unshipped.md" />
</ItemGroup>

</Project>
95 changes: 48 additions & 47 deletions src/Authoring/WinRT.SourceGenerator/WinRTRules.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,124 +18,125 @@ private static DiagnosticDescriptor MakeRule(string id, string title, string mes
category: "Usage",
defaultSeverity: DiagnosticSeverity.Error,
isEnabledByDefault: true,
helpLinkUri: "https://docs.microsoft.com/en-us/previous-versions/hh977010(v=vs.110)");
helpLinkUri: "https://github.com/microsoft/CsWinRT/tree/master/src/Authoring/WinRT.SourceGenerator/AnalyzerReleases.Unshipped.md");
}

public static DiagnosticDescriptor PrivateGetterRule = MakeRule(
"WME",
"CsWinRT1000",
"Property must have public getter",
"Property '{0}' does not have a public getter method. Windows Metadata does not support setter-only properties.");
"Property '{0}' does not have a public getter method. Windows Runtime does not support setter-only properties.");

public static DiagnosticDescriptor DisjointNamespaceRule = MakeRule(
"WME1044",
"CsWinRT1001",
"Namespace is disjoint from main (winmd) namespace",
"A public type has a namespace ('{1}') that shares no common prefix with other namespaces ('{0}'). "
+ "All types within a Windows Metadata file must exist in a sub namespace of the namespace that is "
+ "implied by the file name.");

public static DiagnosticDescriptor NamespacesDifferByCase = MakeRule(
"WME1067",
"CsWinRT1002",
"Namespace names cannot differ only by case",
"Multiple namespaces found with the name '{0}', namespace names cannot differ only by case.");
"Multiple namespaces found with the name '{0}'; namespace names cannot differ only by case in the Windows Runtime.");

public static DiagnosticDescriptor NoPublicTypesRule = MakeRule(
"WME1042",
"CsWinRT1003",
"No public types defined",
"Windows Runtime components must have at least one public type");

public static DiagnosticDescriptor GenericTypeRule = MakeRule(
"WME",
"CsWinRT1004",
"Class (or interface) is generic",
"Type {0} is generic. Windows Runtime types cannot be generic.");


public static DiagnosticDescriptor UnsealedClassRule = MakeRule(
"WME",
"CsWinRT1005",
"Class is unsealed",
"Exporting unsealed types is not supported. Please mark type {0} as sealed.");
"Exporting unsealed types is not supported in CsWinRT. Please mark type {0} as sealed.");

public static DiagnosticDescriptor UnsupportedTypeRule = MakeRule(
"WME",
"CsWinRT1006",
"Exposing unsupported type",
"The member '{0}' has the type '{1}' in its signature. The type '{1}' is not a valid Windows Runtime type\n"
+ "Yet, the type (or its generic parameters) implement interfaces that are valid Windows Runtime types\n"
+ "Consider changing the type '{1} in the member signature to one of the following types from System.Collections.Generic:\n{2}");
"The member '{0}' has the type '{1}' in its signature. The type '{1}' is not a valid Windows Runtime type. "
+ "Yet, the type (or its generic parameters) implement interfaces that are valid Windows Runtime types. "
+ "Consider changing the type '{1} in the member signature to one of the following types from System.Collections.Generic: {2}.");

public static DiagnosticDescriptor StructWithNoFieldsRule = MakeRule(
"WME1060",
"CsWinRT1007",
"Empty struct rule",
"Structure {0} contains no public fields. Windows Runtime structures must contain at least one public field.");

public static DiagnosticDescriptor NonWinRTInterface = MakeRule(
"WME1084",
"CsWinRT1008",
"Invalid Interface Inherited",
"Runtime component class {0} cannot implement interface {1}, as the interface is not a valid Windows Runtime interface");
"Windows Runtime component class {0} cannot implement interface {1}, as the interface is not a valid Windows Runtime interface");

public static DiagnosticDescriptor ClassConstructorRule = MakeRule(
"WME1099",
"CsWinRT1009",
"Class Constructor Rule",
"Runtime component class {0} cannot have multiple constructors of the same arity {1}");
"Classes cannot have multiple constructors of the same arity in the Windows Runtime, class {0} has multiple {1}-arity constructors");

public static DiagnosticDescriptor ParameterNamedValueRule = MakeRule(
"WME1092",
"CsWinRT1010",
"Parameter Named Value Rule",
"The method {0} has a parameter named {1} which is the same as the default return value name. "
+ "Consider using another name for the parameter or use the System.Runtime.InteropServices.WindowsRuntime.ReturnValueNameAttribute "
+ "to explicitly specify the name of the return value.");
"The parameter name {1} in method {0} is the same as the return value parameter name "
+ "used in the generated C#/WinRT interop; use a different parameter name.");

public static DiagnosticDescriptor StructHasPrivateFieldRule = MakeRule(
"WME1060(b)",
"CsWinRT1011",
"Private field in struct",
"Structure {0} has non-public field. All fields must be public for Windows Runtime structures.");

public static DiagnosticDescriptor StructHasConstFieldRule = MakeRule(
"WME1060(b)",
"CsWinRT1012",
"Const field in struct",
"Structure {0} has const field. Constants can only appear on Windows Runtime enumerations.");

public static DiagnosticDescriptor StructHasInvalidFieldRule = MakeRule(
"WME1060",
"CsWinRT1013",
"Invalid field in struct",
"Structure {0} has field of type {1}; {1} is not a valid Windows Runtime field type. Each field "
+ "in a Windows Runtime structure can only be UInt8, Int16, UInt16, Int32, UInt32, Int64, UInt64, Single, Double, Boolean, String, Enum, or itself a structure.");

public static DiagnosticDescriptor OperatorOverloadedRule = MakeRule(
"WME1087",
"CsWinRT1014",
"Operator overload exposed",
"{0} is an operator overload. Managed types cannot expose operator overloads in the Windows Runtime");

public static DiagnosticDescriptor MultipleDefaultOverloadAttribute = MakeRule(
"WME1059",
"CsWinRT1015",
"Only one overload should be designated default",
"In class {2}: Multiple {0}-parameter overloads of '{1}' are decorated with Windows.Foundation.Metadata.DefaultOverloadAttribute. The attribute may only be applied to one overload of the method.");
"In class {2}: Multiple {0}-parameter overloads of '{1}' are decorated with Windows.Foundation.Metadata.DefaultOverloadAttribute. "
+ "The attribute may only be applied to one overload of the method.");

public static DiagnosticDescriptor NeedDefaultOverloadAttribute = MakeRule(
"WME1085",
"CsWinRT1016",
"Multiple overloads seen, one needs a default", // todo better msg
"In class {2}: The {0}-parameter overloads of {1} must have exactly one method specified as the default overload by decorating it with Windows.Foundation.Metadata.DefaultOverloadAttribute.");
"In class {2}: The {0}-parameter overloads of {1} must have exactly one method specified as the default "
+ "overload by decorating it with Windows.Foundation.Metadata.DefaultOverloadAttribute.");

public static DiagnosticDescriptor JaggedArrayRule = MakeRule(
"WME1036",
"CsWinRT1017",
"Array signature found with jagged array, which is not a valid WinRT type",
"Method {0} has a nested array of type {1} in its signature. Arrays in Windows Runtime method signature cannot be nested.");

public static DiagnosticDescriptor MultiDimensionalArrayRule = MakeRule(
"WME1035",
"Array signature found with multi-dimensional array, which is not a valid WinRT type",
"CsWinRT1018",
"Array signature found with multi-dimensional array, which is not a valid Windows Runtime type",
"Method '{0}' has a multi-dimensional array of type '{1}' in its signature. Arrays in Windows Runtime method signatures must be one dimensional.");

public static DiagnosticDescriptor ArraySignature_SystemArrayRule = MakeRule(
"WME1034",
"CsWinRT1019",
"Array signature found with System.Array instance, which is not a valid WinRT type",
"In type {0}: the method {1} has signature that contains a System.Array instance; SystemArray is not a valid Windows Runtime type. Try using a different type like IList");
"In type {0}: the method {1} has signature that contains a System.Array instance; SystemArray is not "
+ "a valid Windows Runtime type. Try using a different type like IList");

public static DiagnosticDescriptor RefParameterFound = MakeRule(
"WME",
"CsWinRT1020",
"Parameter passed by reference",
"Method '{0}' has parameter '{1}' marked `ref`. Reference parameters are not allowed in Windows Runtime.");

public static DiagnosticDescriptor ArrayMarkedInOrOut = MakeRule(
"WME1103",
"CsWinRT1021",
"Array parameter marked InAttribute or OutAttribute",
"Method '{0}' has parameter '{1}' which is an array, and which has either a "
+ "System.Runtime.InteropServices.InAttribute or a System.Runtime.InteropServices.OutAttribute. "
Expand All @@ -144,7 +145,7 @@ private static DiagnosticDescriptor MakeRule(string id, string title, string mes
+ "Runtime attribute if necessary.");

public static DiagnosticDescriptor NonArrayMarkedInOrOut = MakeRule(
"WME1105",
"CsWinRT1022",
"Parameter (not array type) marked InAttribute or OutAttribute",
"Method '{0}' has parameter '{1}' with a System.Runtime.InteropServices.InAttribute "
+ "or System.Runtime.InteropServices.OutAttribute.Windows Runtime does not support "
Expand All @@ -154,29 +155,29 @@ private static DiagnosticDescriptor MakeRule(string id, string title, string mes
+ "System.Runtime.InteropServices.OutAttribute with 'out' modifier instead.");

public static DiagnosticDescriptor ArrayParamMarkedBoth = MakeRule(
"WME1101",
"CsWinRT1023",
"Array paramter marked both ReadOnlyArray and WriteOnlyArray",
"Method '{0}' has parameter '{1}' which is an array, and which has both ReadOnlyArray and WriteOnlyArray. "
+ "In the Windows Runtime, the contents array parameters must be either readable "
+ "or writable.Please remove one of the attributes from '{1}'.");

public static DiagnosticDescriptor ArrayOutputParamMarkedRead = MakeRule(
"WME1102",
"CsWinRT1024",
"Array parameter marked `out` and ReadOnlyArray",
"Method '{0}' has an output parameter '{1}' which is an array, but which has ReadOnlyArray attribute. In the Windows Runtime, "
+ "the contents of output arrays are writable.Please remove the attribute from '{1}'.");

public static DiagnosticDescriptor ArrayParamNotMarked = MakeRule(
"WME1106",
"CsWinRT1025",
"Array parameter not marked ReadOnlyArray or WriteOnlyArray way",
"Method '{0}' has parameter '{1}' which is an array. In the Windows Runtime, the "
+ "contents of array parameters must be either readable or writable.Please apply either ReadOnlyArray or WriteOnlyArray to '{1}'.");

public static DiagnosticDescriptor NonArrayMarked = MakeRule(
"WME1104",
"CsWinRT1026",
"Non-array parameter marked with ReadOnlyArray or WriteOnlyArray",
"Method '{0}' has parameter '{1}' which is not an array, and which has either a "
+ "ReadOnlyArray attribute or a WriteOnlyArray attribute . Windows Runtime does "
+ "ReadOnlyArray attribute or a WriteOnlyArray attribute. Windows Runtime does "
+ "not support marking non-array parameters with ReadOnlyArray or WriteOnlyArray.");
}
}
}
}
Loading

0 comments on commit 5351b4b

Please sign in to comment.