diff --git a/README.md b/README.md index 29fa049..ae9634f 100644 --- a/README.md +++ b/README.md @@ -20,9 +20,13 @@ dotnet run --project src\FSharp.Analyzers.Cli\FSharp.Analyzers.Cli.fsproj -- --p You can also set up a run configuration of FSharp.Analyzers.Cli in your favorite IDE using similar arguments. This also allows you to debug FSharp.Analyzers.Cli. +## Using Analyzers + +Checkout our [Getting Started](https://ionide.io/FSharp.Analyzers.SDK/content/Getting%20Started%20Using.html) guide for analyzer users! + ## Writing Analyzers -Checkout our [Getting Started](https://ionide.io/FSharp.Analyzers.SDK/content/Getting%20Started.html) guide! +Checkout our [Getting Started](https://ionide.io/FSharp.Analyzers.SDK/content/Getting%20Started%20Writing.html) guide for analyzer authors! ## How to contribute diff --git a/docs/content/Dual Analyzer.fsx b/docs/content/Dual Analyzer.fsx index ee47bd5..0953040 100644 --- a/docs/content/Dual Analyzer.fsx +++ b/docs/content/Dual Analyzer.fsx @@ -2,7 +2,7 @@ --- category: end-users categoryindex: 1 -index: 2 +index: 3 --- # Writing an analyzer for both console and editor diff --git a/docs/content/Getting Started Using.fsx b/docs/content/Getting Started Using.fsx new file mode 100644 index 0000000..4b52afb --- /dev/null +++ b/docs/content/Getting Started Using.fsx @@ -0,0 +1,189 @@ +(** +--- +category: end-users +categoryindex: 1 +index: 1 +--- + +# Getting started using analyzers + +## Premise + +We assume the analyzers you want to use are distributed as a nuget package. + +## Using analyzers in a single project + +A dotnet CLI tool, called [fsharp-analyzers](https://www.nuget.org/packages/fsharp-analyzers), is used to run analyzers outside the context of an IDE. +Add it to your tool-manifest with: +```shell +dotnet tool install fsharp-analyzers +``` + +Next, add the `PackageReference` pointing to your favorite analyzers to the `.fsproj` file of the project you want to analyze: + +```xml + + all + build + +``` + +At the time of writing, the [G-Research analyzers](https://github.com/g-research/fsharp-analyzers) [package](https://www.nuget.org/packages/G-Research.FSharp.Analyzers) contains the only analyzers compatible with the latest CLI tool. +With the package downloaded, we can run the CLI tool: + +```shell +dotnet fsharp-analyzers --project ./YourProject.fsproj --analyzers-path C:\Users\yourusername\.nuget\packages\g-research.fsharp.analyzers\0.1.6\analyzers\dotnet\fs\ --verbose +``` + +As you can see, the path to the analyzer DLL files could be tricky to get right across a wide range of setups. +Luckily, we can use an MSBuild custom target to take care of the path construction. +Add the following target to the `.fsproj` file for easy invocation of the analyzer: + +```xml + + + + + + + + +``` + +You may need to adjust the `Command` to be compatible with your specific analyzer. Think about how you want warnings to be treated. + +To locate the analyzer DLLs in the filesystem, we use the variable `$(PkgG-Research_FSharp_Analyzers)`. It's produced by NuGet and normalized to be usable by [MSBuild](https://learn.microsoft.com/en-us/nuget/consume-packages/package-references-in-project-files#generatepathproperty). +In general, a `Pkg` prefix is added and dots in the package ID are replaced by underscores. But make sure to look at the [nuget.g.props](https://learn.microsoft.com/en-us/nuget/reference/msbuild-targets#restore-outputs) file in the `obj` folder for the exact string. +The `\analyzers\dotnet\fs` subpath is a convention analyzer authors should follow when creating their packages. + +At last, you can run the analyzer from the project folder: + +```shell +dotnet msbuild /t:AnalyzeProject +``` + +## Using analyzers in a solution + +Adding the custom target from above to all `.fsproj` files of a solution doesn't scale very well. +So we use the MSBuild infrastructure to add the needed package reference and the MSBuild target to all projects in one go. + +We start with adding the `PackageReference` pointing to your favorite analyzers to the [Directory.Build.props](https://learn.microsoft.com/en-us/visualstudio/msbuild/customize-by-directory?view=vs-2022) file. +This adds the package reference to all `.fsproj` files that are in a subfolder of the file location of `Directory.Build.props`: + +```xml + + + all + build + + +``` + +Likewise we add the following custom target to the [Directory.Build.targets](https://learn.microsoft.com/en-us/visualstudio/msbuild/customize-by-directory?view=vs-2022) file. +This is effectively the same as adding a target to each `*proj` file which exists in a subfolder. +```xml + + + + + + + + + + + + + + +``` + +You may need to adjust the `Command` to be compatible with your specific analyzer. Think about how you want warnings to be treated. + +As we don't want to list all projects of the solution explicitly when analyzing the solution, we create a second custom MSBuild target that calls the project-specific target for all projects. +Add the following custom target to the [Directory.Solution.targets](https://learn.microsoft.com/en-us/visualstudio/msbuild/customize-solution-build?view=vs-2022) file to be able to invoke analysis of the whole solution in one simple command: + +```xml + + + + + + + + + + + +``` + +At last, you can run the analyzer from the solution folder: + +```shell +dotnet msbuild /t:AnalyzeSolution +``` + +## Project Cracking + +If all this seems a bit complex to you, let us explain some inner details to give you a better understanding: + +The way the analyzers work is that we will programmatically type-check a project and process the results with our analyzers. In order to do this programmatically we need to construct the [FSharpProjectOptions](https://fsharp.github.io/fsharp-compiler-docs/reference/fsharp-compiler-codeanalysis-fsharpprojectoptions.html). +This is essentially a type that represents all the fsharp compiler arguments. When using `--project`, we will use [ProjInfo](https://github.com/ionide/proj-info) to invoke a set of MSBuild targets in the project to perform a design-time build. +A design-time build is basically an empty invocation of a build. It won't produce assemblies but will have constructed the correct arguments to theoretically invoke the compiler. + +There's an alternative way to do this. Instead of using the `--project` argument, it's possible to use the `--fsc-args` argument to let the CLI tool construct the needed `FSharpProjectOptions`. +This also uses MSBuild, but in a more efficient way to provide us with the needed information. +Here's how the `Directory.Solution.targets` file would look like to make the use of `--fsc-args` possible: + +```xml + + + + + + + + + + + + +``` + +And here's the `Directory.Build.targets`: +```xml + + + + + + + + + + + + + + +*) + +(** + +[Next]({{fsdocs-next-page-link}}) + +*) diff --git a/docs/content/Getting Started.fsx b/docs/content/Getting Started Writing.fsx similarity index 86% rename from docs/content/Getting Started.fsx rename to docs/content/Getting Started Writing.fsx index 49d3d35..63eb0a1 100644 --- a/docs/content/Getting Started.fsx +++ b/docs/content/Getting Started Writing.fsx @@ -2,10 +2,10 @@ --- category: end-users categoryindex: 1 -index: 1 +index: 2 --- -# Getting started +# Getting started writing an analyzer ## Premise @@ -111,42 +111,15 @@ dotnet tool install --global fsharp-analyzers fsharp-analyzers --project YourProject.fsproj --analyzers-path ./OptionAnalyzer/bin/Release --verbose ``` -## Packaging and Distribution +### Packaging and Distribution Since analyzers are just .NET core libraries, you can distribute them to the nuget registry just like you would with a normal .NET package. - -In the Roslyn world, analyzers are stored in a special folder inside your nuget package. We recommend you follow this structure by adding some additional MSBuild properties: - -```xml - - true - true - true - $(TargetsForTfmSpecificContentInPackage);_AddAnalyzersToOutput - false - - - - - - - -``` - -`SuppressDependenciesWhenPacking` will prevent NuGet from taking your analyzer dependencies into account when it is being installed in a project. This most common use-case here would be `FSharp.Core`. - -`TargetsForTfmSpecificContentInPackage` will make sure the `_AddAnalyzersToOutput` runs to copy the assembly into the `analyzers/dotnet/fs` folder. - -`IncludeBuildOutput` will ensure your `*.nupkg` doesn't have a `lib` folder. - Simply run `dotnet pack --configuration Release` against the analyzer project to get a nuget package and publish it with ```shell dotnet nuget push {NugetPackageFullPath} -s nuget.org -k {NugetApiKey} ``` -### Third-party dependencies - However, the story is different and slightly more complicated when your analyzer package has third-party dependencies also coming from nuget. Since the SDK dynamically loads the package assemblies (`.dll` files), the assemblies of the dependencies have to be right *next* to the main assembly of the analyzer. Using `dotnet pack` will **not** include these dependencies into the output Nuget package. More specifically, the `./lib/net6.0` directory of the nuget package must have all the required assemblies, also those from third-party packages. In order to package the analyzer properly with all the assemblies, you need to take the output you get from running: ```shell @@ -217,7 +190,7 @@ Target.create ) (** - +[Previous]({{fsdocs-previous-page-link}}) [Next]({{fsdocs-next-page-link}}) *) diff --git a/docs/content/Programmatic access.fsx b/docs/content/Programmatic access.fsx index c8efac7..d1ebffb 100644 --- a/docs/content/Programmatic access.fsx +++ b/docs/content/Programmatic access.fsx @@ -2,7 +2,7 @@ --- category: end-users categoryindex: 1 -index: 3 +index: 4 --- # Programmatically running an analyzer diff --git a/docs/content/Running during CI.md b/docs/content/Running during CI.md index 6504e9c..061068d 100644 --- a/docs/content/Running during CI.md +++ b/docs/content/Running during CI.md @@ -1,7 +1,7 @@ --- category: end-users categoryindex: 1 -index: 5 +index: 6 --- # Running analyzers during continuous integration diff --git a/docs/content/Unit Testing.fsx b/docs/content/Unit Testing.fsx index 880820c..3224664 100644 --- a/docs/content/Unit Testing.fsx +++ b/docs/content/Unit Testing.fsx @@ -2,7 +2,7 @@ --- category: end-users categoryindex: 1 -index: 4 +index: 5 --- # Unit testing an analyzer diff --git a/docs/index.md b/docs/index.md index 758b975..592f0e1 100644 --- a/docs/index.md +++ b/docs/index.md @@ -20,9 +20,13 @@ dotnet run --project src\FSharp.Analyzers.Cli\FSharp.Analyzers.Cli.fsproj -- --p You can also set up a run configuration of FSharp.Analyzers.Cli in your favorite IDE using similar arguments. This also allows you to debug FSharp.Analyzers.Cli. +## Using Analyzers + +Checkout our [Getting Started](https://ionide.io/FSharp.Analyzers.SDK/content/Getting%20Started%20Using.html) guide for analyzer users! + ## Writing Analyzers -Checkout our [Getting Started](content/Getting%20Started.html) guide! +Checkout our [Getting Started](https://ionide.io/FSharp.Analyzers.SDK/content/Getting%20Started%20Writing.html) guide for analyzer authors! ## How to contribute