dotnet / roslyn

The Roslyn .NET compiler provides C# and Visual Basic languages with rich code analysis APIs.
https://docs.microsoft.com/dotnet/csharp/roslyn-sdk/
MIT License
19.04k stars 4.03k forks source link

VB projects, by default, suppress warnings from 3rd party analyzers. #24235

Open CyrusNajmabadi opened 6 years ago

CyrusNajmabadi commented 6 years ago

I have an analyzer that reports warnings for C# and VB. C# warnings show up fine in the IDE, but VB warnings do not show up at all (either squiggles or error list). I debugged through both and found what the issue is. However, i can't understand the logic and i don't know what the right fix is.

Here's the parts that are going wrong:

First:

>   Microsoft.VisualStudio.LanguageServices.VisualBasic.ProjectSystemShim.VisualBasicProjectOptionsHelper.CreateCompilationOptions(baseCompilationOptionsOpt, newParseOptions, compilerOptions, compilerHost, globalImports, projectDirectoryOpt, ruleSetOpt) Line 52   Basic
    Microsoft.VisualStudio.LanguageServices.VisualBasic.ProjectSystemShim.VisualBasicProject.CreateCompilationOptions(commandLineArguments, newParseOptions) Line 389   Basic
    Microsoft.VisualStudio.LanguageServices.Implementation.ProjectSystem.AbstractProject.UpdateOptions() Line 65    C#
    Microsoft.VisualStudio.LanguageServices.VisualBasic.ProjectSystemShim.VisualBasicProject.UpdateOptions() Line 409   Basic
    Microsoft.VisualStudio.LanguageServices.VisualBasic.ProjectSystemShim.VisualBasicProject.SetCompilerOptions(pCompilerOptions) Line 380  Basic

https://github.com/dotnet/roslyn/blob/master/src/VisualStudio/VisualBasic/Impl/ProjectSystemShim/VisualBasicProjectOptionsHelper.vb#L50-L53

            Dim generalDiagnosticOption As ReportDiagnostic = DetermineGeneralDiagnosticOption(compilerOptions.WarningLevel, ruleSetFileGeneralDiagnosticOption)
            Dim specificDiagnosticOptions As IReadOnlyDictionary(Of String, ReportDiagnostic) = DetermineSpecificDiagnosticOptions(compilerOptions, ruleSetFileSpecificDiagnosticOptions)
            Dim outputKind = GetOutputKind(compilerOptions)

At this point we set 'generalDiagnosticOption' to ReportDiagnostic.Supress.

Later on when the analyzer reports the diagnostic, we get to:

>   Microsoft.CodeAnalysis.Diagnostics.AnalyzerDriver.GetDiagnosticSink.AnonymousMethod__0(diagnostic, analyzer, isSyntaxDiagnostic) Line 1161  C#
    Microsoft.CodeAnalysis.Diagnostics.AnalyzerExecutor.GetAddDiagnostic.AnonymousMethod__0(diagnostic) Line 1472   C#
    Microsoft.CodeAnalysis.Diagnostics.SemanticModelAnalysisContext.ReportDiagnostic(diagnostic) Line 626   C#

This does:

                var filteredDiagnostic = GetFilteredDiagnostic(diagnostic, compilation);
                if (filteredDiagnostic != null)
                {
                    addLocalDiagnosticCore(filteredDiagnostic, analyzer, isSyntaxDiagnostic);
                }

We end up filtering out the diagnostic. The reason for this is:

>   Microsoft.CodeAnalysis.VisualBasic.VisualBasicDiagnosticFilter.GetDiagnosticReport(severity, isEnabledByDefault, id, location, category, generalDiagnosticOption, caseInsensitiveSpecificDiagnosticOptions, hasDisableDirectiveSuppression) Line 109    Basic
    Microsoft.CodeAnalysis.VisualBasic.VisualBasicDiagnosticFilter.Filter(diagnostic, generalDiagnosticOption, specificDiagnosticOptions) Line 71   Basic
    Microsoft.CodeAnalysis.VisualBasic.VisualBasicCompilationOptions.FilterDiagnostic(diagnostic) Line 1030 Basic
    Microsoft.CodeAnalysis.Diagnostics.AnalyzerDriver.GetFilteredDiagnostic(diagnostic, compilation) Line 1183  C#

https://github.com/dotnet/roslyn/blob/master/src/Compilers/VisualBasic/Portable/Compilation/VisualBasicDiagnosticFilter.vb#L107-L110

            If generalDiagnosticOption = ReportDiagnostic.Suppress AndAlso
            (severity = DiagnosticSeverity.Warning OrElse severity = DiagnosticSeverity.Info) Then
                Return ReportDiagnostic.Suppress
            End If

Basically, because the 'generalDiagnosticOption' is Suppress (due to the top bit i linked), and because we reported something at Warning level, the diagnostic is Suppressed.

CyrusNajmabadi commented 6 years ago

Tagging @heejaechang @mavasani Can you shed some light on what's going on here?

mavasani commented 6 years ago

@CyrusNajmabadi Thanks for the detailed report. I will investigate.

mavasani commented 6 years ago

@CyrusNajmabadi This seems to be by design. VB compiler supports /nowarn to be specified without specific warning IDs, and this suppresses all suppressable diagnostics (unless explicitly overriden in a ruleset file): https://docs.microsoft.com/en-us/dotnet/visual-basic/reference/command-line-compiler/nowarn

C# compiler on the other hand does not allow such a blanket suppression: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/compiler-options/nowarn-compiler-option

DetermineGeneralDiagnosticOption would suppress all warnings if your VB compilation has a blanket /nowarn. Can you please verify this is the case?

CyrusNajmabadi commented 6 years ago

I do not have that option on:

image

I think that's the problem actually. That even though this is off, it's being inferred to be on because of some faulty logic along hte path.

CyrusNajmabadi commented 6 years ago

Here's the problem:

       Private Shared Function ConvertWarningLevel(level As WarningLevel) As ReportDiagnostic
            Select Case level
                Case WarningLevel.WARN_None
                    Return ReportDiagnostic.Suppress

It thinks we're at WARN_None (but i don't know why). Maybe a project system bug?

CyrusNajmabadi commented 6 years ago

This is my project file:

<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
  <PropertyGroup>
    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
    <ProjectGuid>{129DE555-C9E6-46F9-8569-36BAE4E87A6A}</ProjectGuid>
    <OutputType>Exe</OutputType>
    <StartupObject>ConsoleApp1.Module1</StartupObject>
    <RootNamespace>ConsoleApp1</RootNamespace>
    <AssemblyName>ConsoleApp1</AssemblyName>
    <FileAlignment>512</FileAlignment>
    <MyType>Console</MyType>
    <TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion>
    <AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
  </PropertyGroup>
  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
    <PlatformTarget>AnyCPU</PlatformTarget>
    <DebugSymbols>true</DebugSymbols>
    <DebugType>full</DebugType>
    <DefineDebug>true</DefineDebug>
    <DefineTrace>true</DefineTrace>
    <OutputPath>bin\Debug\</OutputPath>
    <DocumentationFile>ConsoleApp1.xml</DocumentationFile>
    <NoWarn>42016,41999,42017,42018,42019,42032,42036,42020,42021,42022</NoWarn>
  </PropertyGroup>
  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
    <PlatformTarget>AnyCPU</PlatformTarget>
    <DebugType>pdbonly</DebugType>
    <DefineDebug>false</DefineDebug>
    <DefineTrace>true</DefineTrace>
    <Optimize>true</Optimize>
    <OutputPath>bin\Release\</OutputPath>
    <DocumentationFile>ConsoleApp1.xml</DocumentationFile>
    <NoWarn>42016,41999,42017,42018,42019,42032,42036,42020,42021,42022</NoWarn>
  </PropertyGroup>
  <PropertyGroup>
    <OptionExplicit>On</OptionExplicit>
  </PropertyGroup>
  <PropertyGroup>
    <OptionCompare>Binary</OptionCompare>
  </PropertyGroup>
  <PropertyGroup>
    <OptionStrict>Off</OptionStrict>
  </PropertyGroup>
  <PropertyGroup>
    <OptionInfer>On</OptionInfer>
  </PropertyGroup>
  <ItemGroup>
    <Reference Include="Newtonsoft.Json, Version=10.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
      <HintPath>..\packages\Newtonsoft.Json.10.0.3\lib\net45\Newtonsoft.Json.dll</HintPath>
    </Reference>
    <Reference Include="System" />
    <Reference Include="System.Data" />
    <Reference Include="System.Deployment" />
    <Reference Include="System.ValueTuple, Version=4.0.2.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
      <HintPath>..\packages\System.ValueTuple.4.4.0\lib\net461\System.ValueTuple.dll</HintPath>
    </Reference>
    <Reference Include="System.Xml" />
    <Reference Include="System.Core" />
    <Reference Include="System.Xml.Linq" />
    <Reference Include="System.Data.DataSetExtensions" />
    <Reference Include="System.Net.Http" />
  </ItemGroup>
  <ItemGroup>
    <Import Include="Microsoft.VisualBasic" />
    <Import Include="System" />
    <Import Include="System.Collections" />
    <Import Include="System.Collections.Generic" />
    <Import Include="System.Data" />
    <Import Include="System.Diagnostics" />
    <Import Include="System.Linq" />
    <Import Include="System.Xml.Linq" />
    <Import Include="System.Threading.Tasks" />
  </ItemGroup>
  <ItemGroup>
    <Compile Include="Module1.vb" />
    <Compile Include="My Project\AssemblyInfo.vb" />
    <Compile Include="My Project\Application.Designer.vb">
      <AutoGen>True</AutoGen>
      <DependentUpon>Application.myapp</DependentUpon>
    </Compile>
    <Compile Include="My Project\Resources.Designer.vb">
      <AutoGen>True</AutoGen>
      <DesignTime>True</DesignTime>
      <DependentUpon>Resources.resx</DependentUpon>
    </Compile>
    <Compile Include="My Project\Settings.Designer.vb">
      <AutoGen>True</AutoGen>
      <DependentUpon>Settings.settings</DependentUpon>
      <DesignTimeSharedInput>True</DesignTimeSharedInput>
    </Compile>
  </ItemGroup>
  <ItemGroup>
    <EmbeddedResource Include="My Project\Resources.resx">
      <Generator>VbMyResourcesResXFileCodeGenerator</Generator>
      <LastGenOutput>Resources.Designer.vb</LastGenOutput>
      <CustomToolNamespace>My.Resources</CustomToolNamespace>
      <SubType>Designer</SubType>
    </EmbeddedResource>
  </ItemGroup>
  <ItemGroup>
    <None Include="My Project\Application.myapp">
      <Generator>MyApplicationCodeGenerator</Generator>
      <LastGenOutput>Application.Designer.vb</LastGenOutput>
    </None>
    <None Include="My Project\Settings.settings">
      <Generator>SettingsSingleFileGenerator</Generator>
      <CustomToolNamespace>My</CustomToolNamespace>
      <LastGenOutput>Settings.Designer.vb</LastGenOutput>
    </None>
    <None Include="App.config" />
    <None Include="packages.config" />
  </ItemGroup>
  <Import Project="$(MSBuildToolsPath)\Microsoft.VisualBasic.targets" />
</Project>
Pilchie commented 6 years ago

Can you update to 15.5.4 (released today) and delete your .suo file? I suspect this might be a bug in design time batch builds that we just fixed. @huizhonglong

CyrusNajmabadi commented 6 years ago

@Pilchie I'm observing this in 15.6 preview 2. Will it have the same issue?

Thanks!

Pilchie commented 6 years ago

Yes - the fix won't be in that build, but should be in 15.6 Preview 3 when it comes out.

CyrusNajmabadi commented 6 years ago

Great. Thanks!