SuppressMessage compiler warning CS1591 for generated code (xsd.exe) - c#

I'm using the tool xsd.exe in several projects to generate classes for my data model.
When turning on documentation file generation in my csproj the compiler starts to show lots of warnings of type: CS1591:Missing XML comment for publicly visible type or member pointing at generated constructors.
As this is kind of intended behavior I am trying to figure out how to suppress these warnings.
But only for the types generated by xsd.exe which are contained in a single source file.
The file content will be replaced by the xsd.exe the next time I run it.
Any modifications to the file will be lost in that process.
So adding a #pragma warning disable to the file is not a solution here
(I sometimes even use a build target which regenerates the code on Build).
But .NET seems to have a builtin mechanic for this case: SuppressMessageAttribute at assembly level (Microsoft Docs: Suppress warnings).
So I went and created a file GlobalSuppressions.cs with the following content:
[assembly: SuppressMessage("Compiler",
"CS1591:MissingXmlCommentForPubliclyVisibleTypeOrMember",
Justification = "Generated code",
Scope = "member",
Target = "M:Company.IO.Component.Concrete.Configuration.ConfigItem.#ctor")]
But the suppression is being ignored.
Anyone any ideas?

I found a solution without having to manipulate the generated source file.
Short
An .editorconfig can be placed in the directory of the generated source files.
The rules contained in the file are applied to this directory and descendants only.
Long
output generated code in a seperate directory containing only generated source files
add .editorconfig to that directory
configure message severity in .editorconfig as desired
In my case this looks as follows
Directory structure
\Configuration
\Schema
\.editorconfig # applied to code files in this directory only
\schema.xsd # template for xsd.exe
\schema.cs # generated by xsd.exe
Project.csproj
Code.cs
Content of .editorconfig
# message severity for generated code files
[*.cs]
dotnet_diagnostic.CS1591.severity = none
This might have worked out better if I generated the code directly to the obj/ folder naming it something like schema.g.cs.
But I wanted to keep the generated file in the repository.
This will possibly be changed later on.

Related

Using Grpc.Tools with Protoc plug-in to generate additional C# files

I am using Grpc.Tools (2.38.1) to generate C# types and gRPC stubs from a Test.proto file containing some service definitions.
To do this I have the following in my project's .csproj file:
<ItemGroup>
<Protobuf Include="**/*.proto" />
</ItemGroup>
This is all working fine: my Test.proto gets compiled to Test.cs and TestGrpc.cs in the obj/Debug folder of my project. The types within them can be referenced from within other types in the project.
But I need to create a WCF interface for the service too, so I thought I could generate this using a custom Protoc plug-in. So I wrote a simple Protoc plug-in that writes out a TestWcf.cs file containing an interface. I then placed this plug-in executable on my path named protoc-gen-blah.exe and updated the entry in the .csproj file to this:
<ItemGroup>
<Protobuf Include="**/*.proto" AdditionalProtocArguments="--blah_out=obj\Debug" />
</ItemGroup>
This correctly creates the C# file, TestWcf.cs, with my interface in: fantastic.
The problem is that my interface within TestWcf.cs cannot be referenced from other types in the project unless I manually include the generated file in the project: something I do not have to do with the other generated files.
Whilst none of the files are included in the project by default―I have to enable 'Show All Files' to see them―Test.cs and TestGrpc.cs have arrows beside them in the Solution Explorer that allow them to be expanded to reveal the types inside. TestWcf.cs does not have this arrow. So Visual Studio is somehow aware that Test.cs and TestGrpc.cs are source code files.
Does anyone know what I need to do for my generated file to be automatically recognised by Visual Studio like the other two files are?
I suspect it has something to do with this part of the Grpc.Tools build target, as I noticed my TestWcf.cs file is not included in the files deleted by the Grpc.Tools clean either, but I can't see why it does not consider my generated file to be C#.
When I build, this is the Protoc call:
D:\...\Src\packages\Grpc.Tools.2.38.1\tools\windows_x86\protoc.exe --csharp_out=obj\Debug ⤶
--plugin=protoc-gen-grpc=D:\...\Src\packages\Grpc.Tools.2.38.1\tools\windows_x86\grpc_csharp_plugin.exe ⤶
--grpc_out=obj\Debug --proto_path=D:\...\Src\packages\Grpc.Tools.2.38.1\build\native\include ⤶
--proto_path=. --dependency_out=obj\Debug\xxxx_Test.protodep --error_format=msvs --blah_out=obj\Debug ⤶
Test.proto
The dependency file looks like this:
obj\Debug/Test.cs \
obj\Debug/TestGrpc.cs \
obj\Debug/TestWcf.cs: Test.proto
Thanks.
I believe the problem is caused some logic in Grpc.Tools that informs MSBuild of the files that have been generated:
public override string[] GetPossibleOutputs(ITaskItem protoItem)
{
...
var outputs = new string[doGrpc ? 2 : 1];
...
outputs[0] = Path.Combine(outdir, filename) + ".cs";
if (doGrpc)
{
...
outputs[1] = Path.Combine(grpcdir, filename) + "Grpc.cs";
}
return outputs;
}
This code only caters for two files being generated from a Protocol Buffer source (name.proto): the Protocol Buffers code generation (name.cs) and the gRPC code generation (nameGrpc.cs). It is not picking up the additional file and informing MSBuild that it exists, hence Visual Studio does not consider it to be code.
There is no away around this short of changing the Grpc.Tools code.

How to disable compiler warnings in only generated code without editing file(s)

I have some generated code that has a bunch of compiler warnings. I want to disable them in the generated file, but keep those warnings in the rest of the project so they can be fixed. I'm using Visual Studio 2019 Community Edition, with the generated files coming from Entity Framework and other NuGet packages.
I want to do this without changing the files, so I won't get the warnings back if they get regenerated. I also don't want to disable the warnings project wide, since they are normally useful warnings. I also don't want to edit the NuGet packages, since that would either require not upgrading them as newer releases are available or possibly having to make changes to the new version.
I've already done plenty of reading, but evidently posting the links is "too much", so I've removed them. Look in the edit history if you want to see them.
The file in question is a Reference.cs for a Connected Service. It has the namespace of Proxy.ProvisioningService and this one file contains a couple of dozen classes. I also have a couple of Entity Framework migration files that have the same problem in a completely different solution.
I have a GlobalSuppressions.cs file that I'd like to add the CS1591 (specifically) to, but my current entry isn't working. Other entries work for other warnings and I've tried variations of the below code to work, including trying to match the format of the other entries, but nothing is working so far. I've changed the "Build" from "Compile", removed the MessageId, changed Scope to be "module", "assembly", and "namespaceanddescendants", and I've tried a couple different ways to set the Target.
[assembly: SuppressMessage("Build", "CS1591:Missing XML comment for publicly visible type or member", Justification = "Generated code", MessageId = "CS1591", Scope = "namespaceanddescendants", Target = "Proxy.ProvisioningService")]
In one of the off-site links, it suggests that I right-click the error, go to Suppress -> In Suppression File, but that's not a listed option. Is that a clue that I can't do it in the GlobalSuppressions.cs file?
I've tried to have Visual Studio 2019 Community Edition automatically suppress the warning by the menu item Analyze -> Build And Suppress Active Issues -> For Project, but that just added a bunch of #pragma directives to the file, which would have to be replaced if the file was regenerated, which I want to avoid.
One of the linked answers suggested writing a script to add the #pragma directives on compile, but that script seems like a hack to me. I'd rather just not edit the generated code at all.
I also don't want to put it in the Project -> Properties -> Build -> Suppress Warnings section, since I want the hand written code to still throw these warnings.
Another SE/SO answer suggests using the GeneratedCodeAttribute attribute to prevent warning from generated files. Unfortunately, my file already has this and it's still throwing the warnings.
Another suggestion was to turn off warnings for these generated files:
To suppress warnings for generated code in a project
Right-click the project in Solution Explorer and then click Properties.
Choose the Code Analysis tab.
Select the Suppress results from generated code check box.
Unfortunately, this option is already selected and not suppressing the CS1591 warning.
So my actual question is:
How can I suppress warnings, specifically CS1591, from generated code files without editing them and without suppressing the warning throughout the whole project?
You said that you consider using a script to update the files to add #pragma a hack, but I can't think of another solution.
I think that you can do this easily with a MSBuild Task by adding something like this to your .csproj file:
<Target Name="DisableWarnings" BeforeTargets="CoreCompile">
<ItemGroup>
<AutoGeneratedFiles Include="**/*.Designer.cs" />
</ItemGroup>
<WriteLinesToFile File="%(AutoGeneratedFiles.FullPath)"
Condition="!$([System.IO.File]::ReadAllText(%(AutoGeneratedFiles.FullPath)).StartsWith("#pragma warning"))"
Lines="$([System.String]::Concat("#pragma warning disable 1591",$([System.IO.File]::ReadAllText(%(AutoGeneratedFiles.FullPath))),"#pragma warning restore 1591"))"
Overwrite="true"
Encoding="Unicode" />
</Target>
The SuppressMessage attribute works only for code analysis warnings. Its summary goes:
Suppresses reporting of a specific code analysis rule violation, allowing multiple suppressions on a single code artifact. Does not apply to compiler diagnostics.
If there is a file name pattern identifying the generated code, compiler warnings can be suppressed in the generated code using EditorConfig. For example, this is how I disabled the warnings for using obsolete code elements in my generated code -- I still need to suppress the warnings in manually written code using #pragma.
[*.generated.cs]
dotnet_diagnostic.CS0612.severity = none
dotnet_diagnostic.CS0618.severity = none
For a WCF connected service, the simplest solution is probably to not have the warning in the first place.
Since the CS1591 warning is about public types, you could use the dotnet-svcutil tool to generate your Reference.cs file and pass the --internal option so that the generated types are internal instead of public, thus getting rid of CS1591 altogether.
For other tools that generate code, look for a similar option to generate internal types instead of public types. For example, you would use the --assemblyVisible option with the xscgen tool.

copy App.config when compiling with CodeAnalysis.Compilation.Emit

I am compiling a C# project using the Roslyn CodeAnalysis APIs, as in the following snipet:
...
EmitResult emitResult = null;
using (FileStream outputFileStream = new FileStream(fileName, FileMode.Create, FileAccess.Write))
{
emitResult = compilation.Emit(outputFileStream, null);
}
...
This works perfectly. However, when I want to compile an executable project that contains an App.Config file, this file is not emitted in the output directory (similar to how it is emitted when compiling via Visual Studio), which is problematic if you want to parse some configs from that file at runtime.
I realize that it should not be emitted by default, but I would probably need to enable some option, or to somehow extract the App.Config path from the Project object and emit it myself? I cannot seem to find any information regarding this, and the Project class does not seem to contain any information regarding config files (unless I am missing something).
Is there some specific API that I need to use to achieve the above? Any pointers to existing code that does this available?
Thanks a lot!
Roslyn is not a build system, it's a compiler. It can only transform code into assemblies (and PDBs). When you compile a .csproj in Visual Studio, MSBuild reads all the properties and items in the project file and translates them into a series of steps that, among other things, call the Roslyn compiler, copies App.config files to the output directory, copies references, etc.
While it's true Roslyn can read MSBuild project files, it only uses this information for compilation purposes, such as locating references.
So, if you're dynamically compiling assemblies, you'll have to copy the App.config file yourself (note - VS doesn't emit this file - it just copies and renames it).

Auto-generated files (Silverlight *.g.i.cs files) dont' seem ignored when Treat warnings as errors is on

I'm trying to be a good dev and turn on treat warnings as errors (as I have always done in the past). The biggest difference is that this time, I'm using Silverlight 4 which generates a ton of code. All of the code starts something like this:
#pragma checksum <some stuff>
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.1
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//---------
However, the treat warnings as errors is not ignoring it. I was under the impression that including such a header would cause the file to be ignored. Apparently, I'm wrong. Does anyone have a (clean) suggestion?
I had the same issue when I deleted all the BIN and OBJ folders from solution directory (to make a smaller backup file of the source files).
I changed the Target Silverlight Version in Project Properties from SL4 to SL3 and then switched backed to SL4. It worked for me.
It took me a long while to find out an acceptable workaround - but it's much better than changing the Target Silverlight version.
The workaround, as mentioned at MSDN, is deleting all your *.g.i.cs files prior to the build.
Here is an F# script to do this (as found in the MSDN workarounds section):
open System
open System.IO
let deleteUserFile file =
printfn "%s" file
File.Delete(file)
Directory.GetFiles( #".", "*g.i.cs", SearchOption.AllDirectories )
|> Array.iter deleteUserFile
This solved the error. Next time it shows up, all I have to is execute a file that'll clean all the g.i.cs files in my projects folder.
Edit: I upgraded to Silverlight 5 and have this issue happen again. None of the suggestions listed here worked (switching to SL4 then back to SL5 or only deleting the g.i.cs files)- however deleting the BIN and OBJ folders of the Silverlight project did the trick.
Okay, so it turns out that, at least in my case, the only warnings coming from the generated files were resulting from my creation of a custom base Silverlight page that my pages inherited from. You can fix the issue of compiler warnings resulting from this type of scenario by removing the XAML file from the project and re-adding the xaml.cs code-behind file back to the project. This causes the LayoutRoot to not be defined, and the code generator to not generate the InitializeComponent method for this base class. Hopefully this will help someone else, too!

Ignoring generated files when using "Treat warnings as errors"

We have started a new project but also have this problem for an existing project. The problem is that when we compile with a warning level of 4 we also want to switch on
'Treat all warnings as errors'
We are unable to do this at the moment because generated files (in particular reference.cs files) are missing things like XML comments and this generates a warning, we do not want to suppress the xml comment warnings totally out of all files just for specific types of files (namely generated code).
I have thought of a way this could be achieved but am not sure if these are the best way to do this or indeed where to start :) My thinking is that we need to do something with T4 templates for the code that is generated such that it does fill in XML documentation for generated code.
Does anyone have any ideas, currently I'm at well over 2k warnings (its a big project) :(
You can selectively disable warnings with a pragma:
// Disable warning messages 4507 and 4034.
#pragma warning( disable : 4507 34 )
If you can emit such warnings (or an #include) in the generated code files, you're done.
Alternatively, you can disable them globally on the command-line for the compiler:
/wd4326 disables compiler warning C4326.
Then re-enable them (via a header file) in the files you want them for:
// Report warning 4326 as an error.
#pragma warning( error : 326 )
Finally, you can set different compile options for each source file by altering the Properties in the project file. Personally I find that a maintenance nightmare, but there are times you have no choice.
Edit: I see that your source files are C#, not C++.
Using the C# command-line:
to suppress CS0028, you could specify /nowarn:28.
Unfortunately, /warnaserror makes all warnings errors.
I've written a PowerShell script that calls svcutil and then wraps the auto-generated code with the #pragma directives to ignore the missing xml, but still allows me to regenerate as needed.
$outFile = 'generatedCode_fromSVCUTIL.cs'
svcutil '..\XML Schema\myXsd.xsd' /dataContractOnly /n:'*,MyNamespace.GeneratedCode' /language:C# /importxmltypes /out:$outFile
# -----------------------------------------------------
# Exempt this file from XML documentation requirements
Write-Host 'Wrapping ', $outFile, ' in #pragma 1591 flags'
$a = Get-Content $outFile
# Set up pragma lines for enabling and disabling the XML doc warning
$disableWarning = '#pragma warning disable 1591'
$restoreWarning = '#pragma warning restore 1591'
# wrap the generated code in the pragma tags
Set-Content $outFile –value $disableWarning, $a, $restoreWarning
Write-Host 'Done.'
In VS 2010 you can right-click on the service reference, select 'Configure Service Reference...' and change the access modifier from Public to Internal.
This may of course not be appropriate for your particular solution but the warnings are not applicable to Internal methods and you can still re-generate the service reference.
For C# you can simply place a
#pragma warning disable 1591
at the beginning of the reference.cs file. Then the warning concerning missing XML documentation will not be issued.
But you have to do this every time, the file is regenerated (i.e. when your service definition changes). I'm not aware of any way to influence the code generation (I'm not sure if they use T4 templates or where these might be located ...)
A couple of thoughts.
1) Do you have the autogenerated tag in your file header (comments at the top of the file), like this:
// <auto-generated>
// This file is auto-generated...
// </auto-generated>
This tag is important (the contents are not), as some tools will skip such files (e.g. StyleCop can be configured to ignore these files).
2) If you are autogenerating code why not autogenerate at least some XML comments? I can understand that you don't want to spend a lot of time documenting code that probably won't ever be read, but when debugging code I often find myself dropping in to some autogenerated proxy and even a simple comment can be helpful, even if it just says "autogenerated code" :)
Edit
3) You can also suppress warnings by adding the pragmas to the build options (right click on the project, choose properties, choose the Build tab). This is more convenient than adding to code. Try adding 1591;1574;1587 to the Suppress Warnings box.
4) You could go in to the Code Analysis tab in the Project Properties and uncheck "Treat Warning as Error" for specific warnings that are causing you problems.
Obviously both these are global settings, they don't just pick on the autogenerated files.

Categories