Flaky execution of Code Analysis - c#

I'm trying to have Code Analysis going for my .NET Standard 2.0 class library. As described here, I've added a reference to Microsoft.CodeAnalysis.FxCopAnalyzers. At the beginning, everything looked good and I started getting CA* warnings when building the project. However, after a while, these warnings disappeared although I hadn't touched the code.
Only after closing VS 2017, deleting all bin directories, restarting VS 2017, I started getting back the CA* warnings. However, this doesn't seem to be the recipe to get them back: in my CI environment, the same thing happened. I lost the warnings after an unrelated commit and I still didn't manage to bring them back although I've cleaned the checkout directory completely.
I wonder what could be the reason that at moments the Code Analysis stops working. Unfortunately, I haven't figured out a way to reproduce this - thus my question.
As a matter of fact, I'm eager to understand why adding a NuGet to a project can modify the outcome of the compilation process at all. How does that magic work? Any pointers are welcome.

As to how Roslyn Analyzers are loaded from NuGet
The new C# and VB compilers are based on Roslyn. Roslyn is an extensible compiler framework where a number of analyzers can run at different stages of the compilation process.
MsBuild will pass the analyzers references from the project file to the call to the Roslyn compiler, which will load these in turn and will execute them after the sources have been parsed and interpreted.
The NuGet packages have special metadata that ensures that these analyzers are added as a special type of reference to the MsBuild project file so that MsBuild can pass these along to the compiler.
As to why the analyzers sometimes fail
This is hard to say. Some metadata of projects is stored. Setting the options to clear the workspace/working directory and start afresh may fix this. Setting the build.clean variable to all should help with that. Deleting the bin, obj and .vs folder as well as the packages folder and performing a nuget restore + build should bring you back into a usable state.
The new FxCop analyzer project still isn't complete and is still being updated. A bug in the analyzer infrastructure can cause the analysis to fail. Unfortunately, this is generally very hard to debug. Turning off rules one by one may help you find the culprit.
There seems to be an option built into Roslyn to enable ETW Logging, which should give you a lot more details, but this isn't very well documented.
In Visual Studio there is another thing that can break the analyzers, Visual Studio Extensions can load analyzers as well, which Visual Studio will then inject into the build process. These extensions are not part of your project and thus won't show up in source control in any way. Any recently updated extension could thus also be the culprit. Setting the MsBuild verbosity level to Diagnostics should show you which analyzers are passed to csc, which should help you figure out where your problem may be coming from.

Related

Error CS7038 (failed to emit module) only in Edit and Continue

I'm debugging a .NET 4.0 application in Visual Studio 2015. My application builds and runs fine, but when I try to edit and continue while running under the debugger, regardless of what changes I make or where I make them in my main project, I get a dialog that says:
Edits were made which cannot be compiled. Execution cannot continue
until the compiler errors are fixed.
As an example of the sort of change I'm talking about, I've tried adding this line in various methods:
Console.WriteLine("foo");
When I look in Visual Studio's Error List pane, I see only one error, CS7038, with the description "Failed to emit module '<my app name>'." No filename, line number, or character is given. There are no squiggly red underlines in my code. If I stop the running application, build with the changes, and run again, everything builds and runs just fine. So there seems to be some discrepancy between what the build-time compiler and the edit-and-continue compiler consider acceptable.
Does anyone know of a way to get more information about why the compile fails in Edit and Continue mode? I read something about attaching to and debugging the VBCSCompiler process, so I tried that, but even with all exception types set to break when thrown, the attached VS never broke.
I'm not sharing any code because this isn't a question about my code but rather about strategies for finding out what the Edit and Continue compiler thinks is wrong, and for all I know the source of the compiler error could be anywhere in my entire project.
Edit:
As mentioned in the comments, I was able to attach a debugger to Visual Studio and break when an exception was thrown upon clicking "Continue" after editing code. The exception was a System.NotSupportedException with the following message: "Changing the version of an assembly reference is not allowed during debugging". It listed the name of the assembly in question, which was a small VB.Net project used by my application, which is mostly in C#. I'm trying to build up an MCVE to submit to Microsoft, but currently I'm unable to reproduce the problem in a smaller solution with just one VB and one C# project.
Edit 2:
I've found a workaround and self-answered the question in case anyone else ever encounters this weird problem, but I'm reserving the "Answered" check mark for anyone who can explain what's going on (why the compiler thinks the version number of the referenced project has changed during the edit).
I found a workaround for the problem, but I don't fully understand what was going on. In the VB.NET project whose assembly version the Edit and Continue compiler said was changing, there was a file called "AssemblyInfo.vb". That file contained the following line:
<Assembly: AssemblyVersion("3.0.*")>
The assembly version can also be set in the Project Properties, via the "Assembly Information" button in the Application tab:
When I removed the AssemblyVersion line from AssemblyInfo.vb, my Edit and Continue problem went away. At first I thought this was because the fields in the Assembly Information window were saved to a different file from AssemblyInfo.vb and there was some conflict between the two, but now I see that the Assembly Information window is just a handy way to edit AssemblyInfo.vb: if I delete the line in AssemblyInfo.vb, it gets cleared in the Assembly Information window.
After some more experimentation, it appears that the asterisk in the version number is the culprit. If I fully specify the assembly version, my Edit and Continue problem goes away. And the referenced project has to be a VB.NET project. I tried the same setup with a C# project, and I could Edit and Continue just fine.
This appears to be very much an edge case, and I'll submit a bug report to Microsoft, but in the meantime I'd love to know what is actually going on with the compiler--why it's getting two different assembly versions of an assembly that really shouldn't need to be recompiled during the debugging.... If you have a good explanation for what's happening, please add it as an answer.
Edit: here's the bug report I filed.
This happened with me in a .net 4.8 app with Visual Studio 2019.
I have a mix vb and cs projects, here the problem appears when a vbproj references a csproj that uses the wildcast operator '*' to specify the version of the assembly.
As commented above by #Wai-Ha-Hee, the wildcast uses the current time, I belive when VS rebuild the application to apply the edits you have made, the version of the assembly changes causing the error.
In assemblyInfo file (of the project present in error) Change:
[assembly: AssemblyVersion("1.0.*")]
To:
[assembly: AssemblyVersion("1.0.0.0")]
It Solved for me.
An important thing to say is the use of wildcast '*' make the assembly non-deterministic, it means each build produces a different assembly. This has been considered bad practice because build the source code in the same conditions generates different assemblies.
In Visual Studio 2019:
New csproj/vbproj with non-sdk style projects file are generated with:
<Deterministic>true</Deterministic>
And new csproj/vbproj with Sdk style projects file omits this line but assumes deterministic as default too.
I recommend considerate other ways to version the assembly.
More about Deterministic:
http://blog.paranoidcoding.com/2016/04/05/deterministic-builds-in-roslyn.html
https://reproducible-builds.org/
One of my C# projects in a mixed solution was .NET Framework 2.0 (while others - both C# and VB.NET - were .NET Framework 4). After I changed it to .NET Framework 4 it began to work.

Compilation succeeded even though there were some errors from Roslyn Diagnostic Analyzer

The DiagnosticAnalyzer is a custom Roslyn based extension whose DiagnosticDescriptor with DiagnosticSeverity.Error is as shown below
internal static DiagnosticDescriptor Rule = new DiagnosticDescriptor(DiagnosticId, Description, MessageFormat, Category, DiagnosticSeverity.Error);
When the extension is used it does show the red squiggles over the codes that is against the Diagnostic Analyzers custom rule emphasising that it is an error, it is even shown in the Error List window of Visual Studio.
But when compiled, this code gets a compilation succeeded message in the Output Window of Visual Studio. This is working against the whole concept of emphasising an error as severity for a diagnostic analyzer.
If this is the default way of working for Roslyn, then do we have a work around for stopping the compilation.
I'm using:
Visual Studio 2013 Update 3
Roslyn End User Preview.vsix
VSIX extension containing the DiagnosticAnalyzer made using Roslyn SDK Project Templates.vsix
The integration of diagnostics into the actual build pipeline has been happening as part of VS "14". If you try the same scenario there, it will cause a compilation error.
Additionally, diagnostics are now attached to projects and distributed via NuGet so that the errors will happen consistently for the entire team, continuous integration build, etc.
I'm using VS2015 Update 3 and this issue is still there. I wanted to enforce local variable and parameter naming conventions, it turned out Roslyn doesn't support these by default, only by workaround: SO link
Then I wanted to fail the build if there is such an error, but Roslyn is not capable of this.
Roslyn could have been a very robust and powerful tool, but it is still failing in the most basic tasks. What a pity.
(For the moderators: I still don't have 50 rep to comment and I don't think I will ever have)

Why does the ASP.NET Compiler rebuild all binaries in every build?

When I recompile my project (asp.net, c#) with aspnet_compiler the rebuilt binaries change (when compared to the previous build) even if no code changes have been made.
This, I understand, is due to the build generating a new Module Version ID (guid) each time it builds (to distinguish between builds), another similar question talks about this: Can i specify the module version id (MVID) when building a .net assembly?
The above linked question seems to suggest there is no way to rebuild a project and have the binaries match a previous build of the same unchanged code.. ok, fine, I understand - but why are all the binaries being rebuilt at all?
I would think, according to the documentation ( http://msdn.microsoft.com/en-us/library/ms229863(v=vs.80).aspx ), that unless -c is specified as an argument the aspnet_compiler should only rebuild those binaries that actually need to be (due to changed code). Am I misunderstanding or maybe missing something?
The aspnet_compiler arguments I'm using:
aspnet_compiler -f -u -fixednames -nologo -v / -p .\myproject\ .\mybuild\
Note that this issue occurs only with a WebSite project, not a Web Application project (they are compiled differently).
Also this issue occurs even if you create a WebSite project and page with no functionality, and never open it or change it in anyway between builds.
Decompiling the binaries that are produced shows no differences. Comparing the binaries of two "identical" builds shows small differences in the same part of the binaries each time - which I believe is probably related to the random build guid. I've found no way of avoiding this change between builds.
Check out this excellent answer by Eric Lippert on how does the C# compiler makes multi passes to compile the source code. There can me many reasons why your build was not identical to the previous one, although the functionality is same.
Compilers replace special language features such as using block with with IL equivalents
The compilers does many optimizations on your code, each iteration may produce slightly different output.
Compilers have to create materialized names for anonymous method names and they are different each time you compile
And many more reasons you could easily figure it out using a dis-assembler
Check out these dis-assemblers and decompile your library or executable to gain better understanding.
http://ilspy.net/ , http://www.telerik.com/products/decompiler.aspx
I've found in many cases using the aspnet_compiler especially in situations where my projects have references to other project in the same solution results in full rebuilds that are often hard to explain. (though the few times I've investigated there were "changes" even if they don't truly effect anything such as changes to whitespace, comments, etc)
I've also had problems with a number of plugins in visual studio that have done everything from manipulate tabulation and other white space, the actual project file, etc. While these changes have no noticeable change to us humans, the compiler takes one look and goes "I see a change! REBUILD ALL THE THINGS!!!"
Not sure my answer is any help, but I would disable your plugins, run the compiler, then run the compiler again and see what happens...

C# Interface Debug Information not linked to sources

I'm trying to re-jig the layout of a very large solution which has become impossibly hard (and s l o w) to work with. My plan is to create a number of solutions containing related projects, and then use binary references where necessary to link to libraries produced by the other solutions.
The thing we rely on to make this usable is Resharper's Navigate to External Sources functionality, so we can easily browse the source of the projects we are referencing from other solutions. Quite why VS can't do this out of the box is beyond me.
This is all working very nicely for classes with implementation. However, for C# interfaces and classes containing only auto-implemented properties, Resharper isn't able to browse to the sources, and falls back to cruddy metadata viewer.
I used srctool.exe, which comes with the Symbol Server tools in MS Debugging Tools For Windows, to browse the sources listed in the .pdb file, and it's clear that the sources for these interfaces and empty(ish) classes are not referenced in the pdb file. If I switch the auto-implemented properties to those with backing fields, then the source link appears in the pdb.
I'm guessing the sources are excluded because there are no places you could set breakpoints on interfaces and auto-implemented properties.
I'm wondering, though, if there is some exotic compiler option or workaround we can employ to force the PDB file to include references to the source of C# interfaces.
Thanks,
Mark
The question doesn't have enough detail. Shooting off the hip, I'd guess that you tackled the problems with the slow massive solution by converting project references to assembly references. And used the Release build of those projects as the reference.
And yes, that stumps any tool that tries to find source code files from the PDB. The release build of a .NET project uses a stripped version of the PDB, all the source code file and line number info has been removed from it. That's a pretty normal thing to do with real release builds. Release built code normally is optimized. That causes code to be re-ordered, no longer matching the logical position of the code in the source file. Any info you get from the source+line PDB info now tends to get between harmful and useless, you start looking in the wrong place for a problem.
That is however not a concern for IDE tooling or while debugging your app. The optimizer is automatically disabled in a case like this. Actually a configuration item in VS: Tools + Options, Debugging, General, "Suppress JIT optimization on module load" option. Turned on by default.
Clearly any tooling that uses the PDB is going to catatonic when they don't have a chance to find source files. The fix is to go back to the original project, select the Release configuration again and change a setting: Project + Properties, Build tab, scroll down, Advanced button. Change the "Debug info" combo from "pdb-only" to "full". Rebuild the project.
Should fix your problem. Also revives the debugger, you can step into the source code again.
Don't move files around too much btw, you might stump the chumps again. At least keep the PDB with the DLL in the same directory. If the source code is no longer present in the same directory but you checked it out again in another one then you have to tell the IDE about it. Right-click the solution, Properties, Debug Source Files setting.

How can I retain compiler warnings in Hudson (CI) when using SVN Update?

I've got a continuous integration setup using Hudson and lately I've configured the jobs to use svn update to get the latest version of the code. I really like this approach since it allows msbuild to version appropriately and only build the effected assemblies.
However, I've noticed that since I'm not doing a build of all the assemblies again, I loose all of the compiler warnings for those assemblies if they aren't built.
For example, if I have 3 assemblies with dependencies demonstrated via indenting:
Assembly 1 10 warnings
Assembly 2 (Depends on 1) 10 warnings
Assembly 3 (Depends on 2) 10 warnings
The first build will build all 3 assemblies and log 30 warnings.
Next build, if I only change Assembly 3, Hudson will only build Assembly 3 and I will only get 10 warnings for that build, effectively marking 20 warnings as "fixed".
As far as I can tell, there isn't going to be any way around this, but I would love to know if anyone has configured Hudson to retain these compiler warnings from one build to another.
Edit: Yes I realize that this can turn into a debate of "you should / shouldn't be doing an update on a CI box", but there are reasons we went with the update approach.
Its roughly 3x faster
We're still producing the most up to date assemblies
msbuild can version the assemblies appropriately.
I would change your approach to a CI build. Doing an incremental build on a build machine is very misleading, and only of marginal value (IMHO) and unless your system is the size of an operating system you are probably not saving yourself much time.
If you have assemblies which do not change often or ever, package them away as "third party" dependencies (maybe even in a merge module so your deployment can pick them up easily) and don't rebuild them with your CI.
On the other hand, if all your assemblies are volatile (need to be rebuilt more than once in a release cycle) build them all, all the time.
Well, msbuild is doing what it should be doing: Its only logging the warnings that it encountered.
If you must use svn update, the only way would be to somehow:
parse the build log and determine what assemblies were not built
foreach unbuilt assembly
look up the warnings for the last time that particular assembly was built
manually carry those warnings forward, into the current build.
It may / may not be unwieldy and it would have to have a decent understanding of the msbuild log format.
One could also argue that it is misleading since you'd be recording warnings that were not logged for that particular build.
You do the continuous integration to see how one assembly interferes the other assemblies. So if they have dependencies you should build all. If they don't have dependencies at all, create one job per assembly (in your case 3).
The version you describe is not a full build it is only an update build and should be done on the developers machine.
EDIT: Versioning Issue
You can configure Hudson (in connection with SVN) to ignore commits by certain users. Using this black list, there should be no issue with msbuild doing the versioning.

Categories