Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 0 additions & 2 deletions Directory.Packages.props
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,7 @@
<PackageVersion Include="xunit.extensibility.execution" Version="2.9.3" />
</ItemGroup>
<ItemGroup Label="Analyzer">
<PackageVersion Include="Microsoft.CodeAnalysis.CSharp" Version="4.0.1" />
<PackageVersion Include="Microsoft.CodeAnalysis.Analyzers" Version="3.11.0" /><!-- We explicitly reference these analyzers to get the latest version even though we might not use the latest version of Microsoft.CodeAnalysis everywhere. -->
<PackageVersion Include="Microsoft.CodeAnalysis.CSharp.Workspaces" Version="4.0.1" />
<PackageVersion Include="Microsoft.VSSDK.BuildTools" Version="17.0.1597"/>
</ItemGroup>
</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<RoslynApiVersion>4.0.1</RoslynApiVersion>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\Funcky.Analyzers\Funcky.Analyzers.Roslyn4.0.csproj" PrivateAssets="all" />
</ItemGroup>
<Import Project="Funcky.Analyzers.CodeFixes.targets" />
</Project>
Original file line number Diff line number Diff line change
@@ -1,26 +1,13 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<IsPackable>false</IsPackable>
<RootNamespace>Funcky.Analyzers</RootNamespace>
<LangVersion>preview</LangVersion>
<Nullable>enable</Nullable>
<IsPackable>false</IsPackable>
<AnalysisLevel>5</AnalysisLevel>
<AnalyzerRoslynVersion>4.4.0</AnalyzerRoslynVersion>
<DefineConstants>$(DefineConstants);ROSLYN_4_4_0</DefineConstants>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="PolySharp" PrivateAssets="all" />
<PackageReference Include="Microsoft.CodeAnalysis.CSharp.Workspaces" />
<None Include="Funcky.Analyzers.CodeFixes.Roslyn4.0.csproj" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\Funcky.Analyzers\Funcky.Analyzers.csproj" />
</ItemGroup>

<ItemGroup>
<Compile Update="CodeFixResources.Designer.cs" DesignTime="True" AutoGen="True" DependentUpon="CodeFixResources.resx" />
<EmbeddedResource Update="CodeFixResources.resx" Generator="ResXFileCodeGenerator" LastGenOutput="CodeFixResources.Designer.cs" />
<ProjectReference Include="..\Funcky.Analyzers\Funcky.Analyzers.csproj" PrivateAssets="all" />
</ItemGroup>
<Import Project="Funcky.Analyzers.CodeFixes.targets" />
</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<Project>
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<IsPackable>false</IsPackable>
<RootNamespace>Funcky.Analyzers</RootNamespace>
<AssemblyName>Funcky.Analyzers.CodeFixes</AssemblyName>
<LangVersion>preview</LangVersion>
<Nullable>enable</Nullable>
<IsPackable>false</IsPackable>
<AnalysisLevel>5</AnalysisLevel>
</PropertyGroup>
<PropertyGroup>
<AnalyzerLanguage>cs</AnalyzerLanguage>
<RoslynApiVersion Condition="'$(RoslynApiVersion)' == '' And '$(AnalyzerRoslynVersion)' != ''">$(AnalyzerRoslynVersion)</RoslynApiVersion>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="PolySharp" PrivateAssets="all" />
<PackageReference Include="Microsoft.CodeAnalysis.CSharp.Workspaces" VersionOverride="$(RoslynApiVersion)" PrivateAssets="all" />
</ItemGroup>
<ItemGroup>
<Compile Update="CodeFixResources.Designer.cs" DesignTime="True" AutoGen="True" DependentUpon="CodeFixResources.resx" />
<EmbeddedResource Update="CodeFixResources.resx" Generator="ResXFileCodeGenerator" LastGenOutput="CodeFixResources.Designer.cs" />
</ItemGroup>
<Import Project="..\Funcky.Analyzers.Package\Packing.targets" />
</Project>
Original file line number Diff line number Diff line change
Expand Up @@ -17,20 +17,34 @@
<PackageTags>funcky, analyzers, roslyn</PackageTags>
<DevelopmentDependency>true</DevelopmentDependency>
</PropertyGroup>
<PropertyGroup>
<TargetsForTfmSpecificContentInPackage>$(TargetsForTfmSpecificContentInPackage);_AddAnalyzersToOutput</TargetsForTfmSpecificContentInPackage>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\Funcky.Analyzers.CodeFixes\Funcky.Analyzers.CodeFixes.csproj" />
<ProjectReference Include="..\Funcky.Analyzers\Funcky.Analyzers.csproj" />
<ProjectReference Include="..\Funcky.Analyzers\Funcky.Analyzers.csproj" PackAsAnalyzer="true" />
<ProjectReference Include="..\Funcky.Analyzers\Funcky.Analyzers.Roslyn4.0.csproj" PackAsAnalyzer="true" />
<ProjectReference Include="..\Funcky.Analyzers.CodeFixes\Funcky.Analyzers.CodeFixes.csproj" PackAsAnalyzer="true" />
<ProjectReference Include="..\Funcky.Analyzers.CodeFixes\Funcky.Analyzers.CodeFixes.Roslyn4.0.csproj" PackAsAnalyzer="true" />
</ItemGroup>
<ItemGroup>
<None Update="tools\*.ps1" CopyToOutputDirectory="Always" Pack="true" PackagePath="" />
</ItemGroup>
<Target Name="_AddAnalyzersToOutput">
<!-- Adapted from https://github.com/dotnet/runtime/blob/4bd597ffde128555b4ff017e87c60adc2fedd178/eng/packaging.targets#L136 -->
<PropertyGroup>
<BeforePack>$(BeforePack);IncludeAnalyzersInPackage</BeforePack>
</PropertyGroup>
<Target Name="IncludeAnalyzersInPackage"
Condition="'@(ProjectReference)' != '' and @(ProjectReference->AnyHaveMetadataValue('PackAsAnalyzer', 'true'))">
<MSBuild Projects="@(ProjectReference->WithMetadataValue('PackAsAnalyzer', 'true'))"
Targets="GetAnalyzerPackFiles"
RemoveProperties="SetTargetFramework">
<Output TaskParameter="TargetOutputs" ItemName="_AnalyzerFile" />
</MSBuild>

<ItemGroup>
<TfmSpecificPackageFile Include="$(OutputPath)\Funcky.Analyzers.dll" PackagePath="analyzers/dotnet/cs" />
<TfmSpecificPackageFile Include="$(OutputPath)\Funcky.Analyzers.CodeFixes.dll" PackagePath="analyzers/dotnet/cs" />
<Content Include="@(_AnalyzerFile)" Pack="True" Condition="!%(_AnalyzerFile.IsSymbol)" />
<!-- Symbols don't honor PackagePath. By default they are placed in lib/%(TargetFramework).
Pack does honor TargetPath and does Path.Combine("lib/%(TargetFramework)", "%(TargetPath)"),
so a rooted path value for TargetPath will override lib.
https://github.com/NuGet/Home/issues/10860 -->
<_TargetPathsToSymbols Include="@(_AnalyzerFile)" TargetPath="/%(_AnalyzerFile.PackagePath)" Condition="%(_AnalyzerFile.IsSymbol)" />
</ItemGroup>
</Target>
</Project>
27 changes: 27 additions & 0 deletions Funcky.Analyzers/Funcky.Analyzers.Package/Packing.targets
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Adapted from https://github.com/dotnet/runtime/blob/4bd597ffde128555b4ff017e87c60adc2fedd178/eng/generatorProjects.targets -->
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<!-- This file is included in the individual analyzer project files and allows
Funcky.Analyzers.Package project to retrieve the files to package. It
does this by invoking the `GetAnalyzerPackFiles` target. -->
<Target Name="GetAnalyzerPackFiles"
DependsOnTargets="$(GenerateNuspecDependsOn)"
Returns="@(_AnalyzerPackFile)">
<PropertyGroup>
<_analyzerPath>analyzers/dotnet</_analyzerPath>
<_analyzerRoslynVersion Condition="'$(AnalyzerRoslynVersion)' != ''">$([System.Version]::Parse($(AnalyzerRoslynVersion)).Major).$([System.Version]::Parse($(AnalyzerRoslynVersion)).Minor)</_analyzerRoslynVersion>
<_analyzerPath Condition="'$(AnalyzerRoslynVersion)' != ''">$(_analyzerPath)/roslyn$(_analyzerRoslynVersion)</_analyzerPath>
<_analyzerPath Condition="'$(AnalyzerLanguage)' != ''">$(_analyzerPath)/$(AnalyzerLanguage)</_analyzerPath>
</PropertyGroup>

<!-- Filter on netstandard2.0 so that generator projects can multi-target for the purpose of enabling nullable reference type compiler checks. -->
<ItemGroup>
<_AnalyzerPackFile Include="@(_BuildOutputInPackage->WithMetadataValue('TargetFramework', 'netstandard2.0'))" IsSymbol="false" />
<_AnalyzerPackFile Include="@(_TargetPathsToSymbols->WithMetadataValue('TargetFramework', 'netstandard2.0'))" IsSymbol="true" />
<_AnalyzerPackFile PackagePath="$(_analyzerPath)/%(TargetPath)" />
</ItemGroup>

<Error Text="Analyzers must target netstandard2.0 since they run in the compiler which targets netstandard2.0. $(MSBuildProjectFullPath) targets '$([MSBuild]::ValueOrDefault('$(TargetFrameworks)', '$(TargetFramework)'))' instead."
Condition="'@(_AnalyzerPackFile)' == ''" />
</Target>
</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<RoslynApiVersion>4.0.1</RoslynApiVersion>
</PropertyGroup>
<Import Project="Funcky.Analyzers.targets" />
</Project>
32 changes: 4 additions & 28 deletions Funcky.Analyzers/Funcky.Analyzers/Funcky.Analyzers.csproj
Original file line number Diff line number Diff line change
@@ -1,34 +1,10 @@
<Project Sdk="Microsoft.NET.Sdk">

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

<!-- Avoid ID conflicts with the package project. -->
<PackageId>*$(MSBuildProjectFile)*</PackageId>
<LangVersion>preview</LangVersion>
<Nullable>enable</Nullable>
<IsPackable>false</IsPackable>
<AnalysisLevel>5</AnalysisLevel>
<EnforceExtendedAnalyzerRules>true</EnforceExtendedAnalyzerRules>
<AnalyzerRoslynVersion>4.4.0</AnalyzerRoslynVersion>
<DefineConstants>$(DefineConstants);ROSLYN_4_4_0</DefineConstants>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="PolySharp" PrivateAssets="all" />
<PackageReference Include="Microsoft.CodeAnalysis.Analyzers" />
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" />
<None Include="Funcky.Analyzers.Roslyn4.0.csproj" />
</ItemGroup>

<ItemGroup>
<Compile Update="Resources.Designer.cs">
<DesignTime>True</DesignTime>
<AutoGen>True</AutoGen>
<DependentUpon>Resources.resx</DependentUpon>
</Compile>
</ItemGroup>

<ItemGroup>
<EmbeddedResource Update="Resources.resx" Generator="ResXFileCodeGenerator" LastGenOutput="Resources.Designer.cs" />
</ItemGroup>

<Import Project="Funcky.Analyzers.targets" />
</Project>
35 changes: 35 additions & 0 deletions Funcky.Analyzers/Funcky.Analyzers/Funcky.Analyzers.targets
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
<?xml version="1.0" encoding="utf-8"?>
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<IsPackable>false</IsPackable>
<!-- Avoid ID conflicts with the package project. -->
<PackageId>*$(MSBuildProjectFile)*</PackageId>
<AssemblyName>Funcky.Analyzers</AssemblyName>
<LangVersion>preview</LangVersion>
<Nullable>enable</Nullable>
<IsPackable>false</IsPackable>
<AnalysisLevel>5</AnalysisLevel>
<EnforceExtendedAnalyzerRules>true</EnforceExtendedAnalyzerRules>
</PropertyGroup>
<PropertyGroup>
<AnalyzerLanguage>cs</AnalyzerLanguage>
<RoslynApiVersion Condition="'$(RoslynApiVersion)' == '' And '$(AnalyzerRoslynVersion)' != ''">$(AnalyzerRoslynVersion)</RoslynApiVersion>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="PolySharp" PrivateAssets="all" />
<PackageReference Include="Microsoft.CodeAnalysis.Analyzers" PrivateAssets="all" />
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" VersionOverride="$(RoslynApiVersion)" PrivateAssets="all" />
</ItemGroup>
<ItemGroup>
<Compile Update="Resources.Designer.cs">
<DesignTime>True</DesignTime>
<AutoGen>True</AutoGen>
<DependentUpon>Resources.resx</DependentUpon>
</Compile>
</ItemGroup>
<ItemGroup>
<EmbeddedResource Update="Resources.resx" Generator="ResXFileCodeGenerator" LastGenOutput="Resources.Designer.cs" />
</ItemGroup>
<Import Project="..\Funcky.Analyzers.Package\Packing.targets" />
</Project>
44 changes: 44 additions & 0 deletions Funcky.Analyzers/readme.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# Analyzers
## Analyzers and Code Fixes In Separate Projects
Analyzers and code fixes are split in two projects.

This is to prevent us from accidentally referencing `Microsoft.CodeAnalysis.*.Workspaces`
which is only available in the IDE, but not during `dotnet build`.

## BuiltinAnalyzers
These are analyzers that in our eyes are *mandatory* (disallow `TryGetValue`),
so we package them directly in the Funcky package to ensure that every user is using them.

## Roslyn Multi-Targeting
In order to support newer C# features (which in turn requires an upgrade of the `Microsoft.CodeAnalysis.*` packages)
we would break compatibility with older .NET SDK / Visual Studio Versions.

To work around this, Roslyn supports shipping different analyzer assemblies
in the NuGet package based on the Roslyn version i.e. ["multi-targeting" but for Roslyn][multi-targeting].

The .NET SDK supports "multi-targeting" analyzers on the Roslyn version.
This means that we ship multiple copies of the analyzer assembly in the following structure:

```
╰─ analyzers
╰─ dotnet
├─ cs
│ ├─ Funcky.Analyzers.dll
│ ╰─ ...
╰─ roslyn4.12
╰─ cs
├─ Funcky.Analyzers.dll
╰─ ...
```

## Roslyn Version Compatibility
There are three documents that help figure out what version of Roslyn to target:
* [.NET compiler platform package version reference](https://learn.microsoft.com/en-us/visualstudio/extensibility/roslyn-version-support): \
Maps Roslyn version to Visual Studio version
* [.NET SDK, MSBuild, and Visual Studio versioning](https://learn.microsoft.com/en-gb/dotnet/core/porting/versioning-sdk-msbuild-vs): \
Maps .NET SDK version to Visual Studio version
* [The history of C#](https://learn.microsoft.com/en-us/dotnet/csharp/whats-new/csharp-version-history): \
Lists C# versions and their release date which helps find the minimum Visual Studio version for a given C# version.


[multi-targeting]: https://github.com/dotnet/sdk/issues/20355
3 changes: 3 additions & 0 deletions Funcky.sln
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,9 @@ EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Funcky.Xunit.Test", "Funcky.Xunit.Test\Funcky.Xunit.Test.csproj", "{C2400B4E-63DD-475E-BF7B-5D5079601F51}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Analyzers", "Analyzers", "{BBE35279-7416-4B9D-B89D-B6D1FF369681}"
ProjectSection(SolutionItems) = preProject
Funcky.Analyzers\readme.md = Funcky.Analyzers\readme.md
EndProjectSection
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Funcky.Analyzers", "Funcky.Analyzers\Funcky.Analyzers\Funcky.Analyzers.csproj", "{38795B14-3E1A-4491-AEA0-173A73CE9E3A}"
EndProject
Expand Down