Stylecopanalyzers: Document build customization to disable analyzers when building in Visual Studio

Created on 30 Oct 2015  路  19Comments  路  Source: DotNetAnalyzers/StyleCopAnalyzers

Some users are interested in disabling analyzers in Visual Studio to improve build performance. Specifically:

  • Enable analyzers for IntelliSense purposes
  • Enable analyzers for command line builds
  • Disable analyzers when actually building the project inside of Visual Studio

The documentation for this functionality should be preceded by a clear notice regarding the potential downside of this behavior.

:warning: Using this build customization may change the build behavior in ways that increase the chances of developers submitting code which does not compile in the automated build environment. In particular, projects with any of the following characteristics are advised to avoid the use of this:

  • Projects with /warnaserror enabled
  • Projects with one or more analyzers installed that have a default severity of Error
  • Projects which use a rule set file to set the severity of one or more analyzers to Error

This can be accomplished by adding the following to a project file:

<Target Name="DisableAnalyzersForVisualStudioBuild"
        BeforeTargets="CoreCompile"
        Condition="'$(BuildingInsideVisualStudio)' == 'True' And '$(BuildingProject)' == 'True'">
  <!--
    Disable analyzers when building a project inside Visual Studio. Note that analyzer behavior for IntelliSense
    purposes is not altered by this.
  -->
  <ItemGroup>
    <Analyzer Remove="@(Analyzer)"/>
  </ItemGroup>
</Target>
enhancement

Most helpful comment

@SeidChr I'm not sure which version of the compiler tools first supports it, but you can pass /p:RunAnalyzersDuringBuild=false to the build to turn them off for the command line.

All 19 comments

:+1:

@sharwell Have you considered following the CA setting treating warnings as errors?

<CodeAnalysisTreatWarningsAsErrors>true</CodeAnalysisTreatWarningsAsErrors>

I find this setting helpful where i want to show warnings to dev's on localhost, but Errors in a CI build..allowing me to keep the same rulesets for both scenarios.

  <PropertyGroup Condition=" '$(TF_BUILD)' == 'True' ">
    <CodeAnalysisTreatWarningsAsErrors>true</CodeAnalysisTreatWarningsAsErrors>
  </PropertyGroup>

@felickz We don't have access to that from inside an analyzer, so I'm not sure there's anything we can do to support it directly.

btw Resharper Build now sets 'BuildingByReSharper' just like VS sets BuildingInsideVisualStudio.

@sharwell the workaround was working until VS Update 1 but doesn't seem to work anymore in VS 2015 Update 3 (not sure if it was broken in update 2 since I went from 1 to 3). Are you aware of any changes or an easier way in order to disable Analyzers when building inside VS 2015 Update 3 ?

Thanks!

HI @claudiopi did you find a way to disable Analyzer inside VS 2015 Update 3? We have the same issue here.
We are using .NET Core application.

@sharwell Unfortunately this doesn't work in VS 2017 15.3 with "new" csproj format. The condition evaluates as true even for "IntelliSense" phase, effectively removing analyzers completely even from project view.

An example of project file for VS2017 15.3:

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <TargetFramework>netstandard2.0</TargetFramework>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="StyleCop.Analyzers" Version="1.1.0-beta004" />
  </ItemGroup>

  <Target Name="DisableAnalyzersForVisualStudioBuild" BeforeTargets="CoreCompile" Condition="'$(BuildingInsideVisualStudio)' == 'True' And '$(BuildingProject)' == 'True'">
    <ItemGroup>
      <Analyzer Remove="@(Analyzer)"/>
    </ItemGroup>
  </Target>
</Project>

I was able to "fix" the problem by using adding the And '$(BuildProjectReferences)' == 'True' to condition, but I'm not sure this doesn't have any unintended side effects since my knowledge of MSBuild is mostly a cargo cult one.

@onyxmaster Thanks for the heads-up. Can you try the following?

  1. First, explicitly import the Sdk.props and Sdk.targets files:

    <Project> <!-- No 'Sdk' attribute -->
      <Import Sdk="Microsoft.NET.Sdk" Project="Sdk.props" /> <!-- First line -->
    
      <!-- ... -->
    
      <Import Sdk="Microsoft.NET.Sdk" Project="Sdk.targets" /> <!-- Last line -->
    </Project>
    
  2. Then, move the <Target> definition from far above after the import of Sdk.targets (at the end of the project).

  3. Modify the condition by replacing '$(BuildingProject)' == 'true' with the following:

    '$(DesignTimeBuild)' != 'True' And '$(BuildingProject)' == 'True'
    

馃挱 Using the above approach, it may actually be possible to eliminate the <Target> altogether and simply use an <ItemGroup>, but I haven't investigated this.

<!-- ItemGroup must be placed after explicit Sdk.targets import -->
<ItemGroup Condition="'$(BuildingInsideVisualStudio)' == 'True' And '$(DesignTimeBuild)' != 'True' And '$(BuildingProject)' == 'True'">
  <Analyzer Remove="@(Analyzer)" />
</ItemGroup>

Thank you, I'll try this when I finish upgrading our projects.

Another approach is to #ifdef-out C# source code that you don't want Intellisense (etc.) to see. The following currently works for that purpose:

<PropertyGroup>
    <DefineConstants Condition="'$(BuildingProject)' == 'false'">ANALYZER;$(DefineConstants)</DefineConstants>
</PropertyGroup>

With this defined, you can do things like the following example, which provides the required Intellisense stub for an otherwise-stock use of a .netmodule source file getting compiled into a standard MsBuild C# project.

#if ANALYZER
public static class ABCDE
{
    [MethodImpl(MethodImplOptions.ForwardRef)]
    public static extern String Test();
}
#endif

The MsBuild "item" entry for providing the implementation behind this MethodImplOptions.ForwardRef would be, e.g.:

<ItemGroup>
    <AddModules Include="ABCDE.netmodule" />
</ItemGroup>

Fwiw, the .netmodule itself can also be built using with a fairly unadulterated MsBuild csproj with type using <OutputType>Module</OutputType>. It's critical for this to set NoWin32Manifest to 'true'. Better yet, change that project tag to <Project DefaultTargets="Compile" ... and pick up the .netmodule from the \obj directory. The goal here is to prevent the usual adding of additional junk into the result binary which usually occurs after csc.exe.

@onyxmaster Works for me in 15.7.2 with a .NET Standard library.

@sharwell Any plans to include this in the documentation then? There have been a number of requests and complaints about this, I personally have a solution that normally takes ~5 seconds for an incremental build but ~15 seconds with these analyzers enabled. Only thing missing is allowing the analyzers to run when choosing the "Run Code Analysis on Solution" option, not sure if there's another MSBuild variable to check for that.

@glenn-slayden Coincidence indeed! Wouldn't your approach require surrounding every file with those ifdefs and also break the build (since nothing gets compiled then) or am I misunderstanding something?

Yes, it would. My note is not as well suited if you're looking for ways to improve build performance in bulk. As noted, I guess it's mostly suitable for fixing issues that (e.g.) intellisense currently gets fatally wrong.

Ist there currently anything "out of the box" i can set on build-level (wihtout modifying the 30+ project files where we use stylecop) to disable the analyzers for this build completely?
We need this in visual studio builds and tfs builds. Only thing we want is Highlighting.
If not, it shouldn't be that hard to add a check for an env var before running the analysis, or is it?

@SeidChr I'm not sure which version of the compiler tools first supports it, but you can pass /p:RunAnalyzersDuringBuild=false to the build to turn them off for the command line.

Perfect, thank you!

Is there a way to make this work with mono? I've just about tried everything I can, but I just can't get builds working so that I would have a configuration that would allow me faster debugging by not needing to run the analysis every time.

Update: I found a hacky way to do this: I made a script that updates my build config xml based on if I want the checks to be on or not, and then runs nuget restore. That seems to work fine as my build times go down with that.

Was this page helpful?
0 / 5 - 0 ratings