-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'main' into add_partialappanalyzer
- Loading branch information
Showing
11 changed files
with
240 additions
and
46 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,25 +1,26 @@ | ||
<Project Sdk="Microsoft.NET.Sdk"> | ||
<Project Sdk="Microsoft.NET.Sdk"> | ||
|
||
<PropertyGroup> | ||
<TargetFramework>net6.0</TargetFramework> | ||
<GenerateDocumentationFile>true</GenerateDocumentationFile> | ||
<IsPackable>true</IsPackable> | ||
<AssemblyName>G-Research.FSharp.Analyzers</AssemblyName> | ||
<Tailcalls>true</Tailcalls> | ||
</PropertyGroup> | ||
<PropertyGroup> | ||
<TargetFramework>net6.0</TargetFramework> | ||
<GenerateDocumentationFile>true</GenerateDocumentationFile> | ||
<IsPackable>true</IsPackable> | ||
<AssemblyName>G-Research.FSharp.Analyzers</AssemblyName> | ||
<Tailcalls>true</Tailcalls> | ||
</PropertyGroup> | ||
|
||
<ItemGroup> | ||
<Compile Include="ASTCollecting.fs"/> | ||
<Compile Include="TASTCollecting.fs" /> | ||
<Compile Include="StringAnalyzers.fs"/> | ||
<Compile Include="JsonSerializerOptionsAnalyzer.fs" /> | ||
<Compile Include="UnionCaseAnalyzer.fs" /> | ||
<Compile Include="PartialAppAnalyzer.fs" /> | ||
</ItemGroup> | ||
|
||
<ItemGroup> | ||
<PackageReference Update="FSharp.Core"/> | ||
<PackageReference Include="FSharp.Analyzers.SDK" /> | ||
<PackageReference Include="FSharp.Compiler.Service"/> | ||
</ItemGroup> | ||
<ItemGroup> | ||
<PackageReference Update="FSharp.Core"/> | ||
<PackageReference Include="FSharp.Analyzers.SDK" /> | ||
<PackageReference Include="FSharp.Compiler.Service"/> | ||
</ItemGroup> | ||
|
||
</Project> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,133 @@ | ||
namespace ``G-Research``.FSharp.Analyzers | ||
|
||
open FSharp.Analyzers.SDK | ||
open FSharp.Compiler.CodeAnalysis | ||
open FSharp.Compiler.Symbols | ||
open FSharp.Compiler.Syntax | ||
open FSharp.Compiler.Text | ||
|
||
module UnionCaseAnalyzer = | ||
|
||
[<Literal>] | ||
let Code = "GRA-UNIONCASE-001" | ||
|
||
let findAllShadowingCases | ||
(ast : ParsedInput) | ||
(checkFileResults : FSharpCheckFileResults) | ||
(sourceText : ISourceText) | ||
: range list | ||
= | ||
let collector = ResizeArray<range> () | ||
|
||
let namesToWarnAbount = | ||
set | ||
[ | ||
"Choice1Of2" | ||
"Choice2Of2" | ||
"Choice1Of3" | ||
"Choice2Of3" | ||
"Choice3Of3" | ||
"Choice1Of4" | ||
"Choice2Of4" | ||
"Choice3Of4" | ||
"Choice4Of4" | ||
"Choice1Of5" | ||
"Choice2Of5" | ||
"Choice3Of5" | ||
"Choice4Of5" | ||
"Choice5Of5" | ||
"Choice1Of6" | ||
"Choice2Of6" | ||
"Choice3Of6" | ||
"Choice4Of6" | ||
"Choice5Of6" | ||
"Choice6Of6" | ||
"Choice1Of7" | ||
"Choice2Of7" | ||
"Choice3Of7" | ||
"Choice4Of7" | ||
"Choice5Of7" | ||
"Choice6Of7" | ||
"Choice7Of7" | ||
"None" | ||
"Some" | ||
"ValueNone" | ||
"ValueSome" | ||
"Ok" | ||
"Error" | ||
] | ||
|
||
let handleCase (SynUnionCase (ident = (SynIdent (ident, _)))) = | ||
if (namesToWarnAbount |> Set.contains ident.idText) then | ||
collector.Add ident.idRange | ||
|
||
() | ||
|
||
let walker = | ||
{ new SyntaxCollectorBase() with | ||
override _.WalkTypeDefn | ||
(SynTypeDefn (typeInfo = SynComponentInfo (attributes = synAttributeLists) ; typeRepr = repr)) | ||
= | ||
let hasReqQualAccAttribute = | ||
synAttributeLists | ||
|> List.exists (fun lst -> | ||
lst.Attributes | ||
|> Seq.exists (fun (a : SynAttribute) -> | ||
let lineText = sourceText.GetLineString (a.Range.EndLine - 1) | ||
let name = (List.last a.TypeName.LongIdent).idText | ||
|
||
let symbolUseOpt = | ||
checkFileResults.GetSymbolUseAtLocation ( | ||
a.Range.EndLine, | ||
a.Range.EndColumn, | ||
lineText, | ||
[ name ] | ||
) | ||
|
||
match symbolUseOpt with | ||
| Some symbolUse -> | ||
match symbolUse.Symbol with | ||
| :? FSharpMemberOrFunctionOrValue as mfv -> | ||
mfv.FullName = "Microsoft.FSharp.Core.RequireQualifiedAccessAttribute" | ||
| _ -> false | ||
| _ -> false | ||
) | ||
) | ||
|
||
if not hasReqQualAccAttribute then | ||
match repr with | ||
| SynTypeDefnRepr.Simple (SynTypeDefnSimpleRepr.Union (unionCases = synUnionCases), _) -> | ||
synUnionCases |> List.iter handleCase | ||
| _ -> () | ||
else | ||
() | ||
} | ||
|
||
walkAst walker ast | ||
|
||
collector |> Seq.toList | ||
|
||
[<CliAnalyzer "UnionCaseAnalyzer">] | ||
let unionCaseAnalyzer : Analyzer<CliContext> = | ||
fun ctx -> | ||
async { | ||
|
||
let ranges = | ||
findAllShadowingCases ctx.ParseFileResults.ParseTree ctx.CheckFileResults ctx.SourceText | ||
|
||
let msgs = | ||
ranges | ||
|> List.map (fun r -> | ||
{ | ||
Type = "UnionCase analyzer" | ||
Message = | ||
"This discriminated union contains a case with the same name as a case from FSharp.Core. Consider renaming it or applying RequireQualifiedAccess to avoid clashes." | ||
Code = Code | ||
Severity = Warning | ||
Range = r | ||
Fixes = [] | ||
} | ||
) | ||
|
||
return msgs | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
namespace ``G-Research``.FSharp.Analyzers.Tests | ||
|
||
module UnionCaseAnalyzerTests = | ||
|
||
open System.Collections | ||
open System.IO | ||
open NUnit.Framework | ||
open FSharp.Compiler.CodeAnalysis | ||
open FSharp.Analyzers.SDK.Testing | ||
open ``G-Research``.FSharp.Analyzers | ||
open Testing | ||
|
||
let mutable projectOptions : FSharpProjectOptions = FSharpProjectOptions.zero | ||
|
||
[<SetUp>] | ||
let Setup () = | ||
task { | ||
let! options = mkOptionsFromProject "net7.0" [] | ||
|
||
projectOptions <- options | ||
} | ||
|
||
type TestCases() = | ||
static member DataFolder = Path.Combine (__SOURCE_DIRECTORY__, "..", "data") | ||
|
||
interface IEnumerable with | ||
member _.GetEnumerator () : IEnumerator = | ||
constructTestCaseEnumerator [| "unioncase" |] | ||
|
||
[<TestCaseSource(typeof<TestCases>)>] | ||
let UnionCaseTests (fileName : string) = | ||
task { | ||
let dataFolder = TestCases.DataFolder | ||
let fileName = Path.Combine (dataFolder, fileName) | ||
|
||
let! messages = | ||
File.ReadAllText fileName | ||
|> getContext projectOptions | ||
|> UnionCaseAnalyzer.unionCaseAnalyzer | ||
|
||
do! assertExpected fileName messages | ||
} | ||
|
||
type NegativeTestCases() = | ||
|
||
interface IEnumerable with | ||
member _.GetEnumerator () : IEnumerator = | ||
constructTestCaseEnumerator [| "unioncase" ; "negative" |] | ||
|
||
[<TestCaseSource(typeof<NegativeTestCases>)>] | ||
let NegativeTests (fileName : string) = | ||
task { | ||
let fileName = Path.Combine (TestCases.DataFolder, fileName) | ||
|
||
let! messages = | ||
File.ReadAllText fileName | ||
|> getContext projectOptions | ||
|> UnionCaseAnalyzer.unionCaseAnalyzer | ||
|
||
Assert.IsEmpty messages | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
type MyU = | ||
| Case1 | ||
| None | ||
| Case3 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
GRA-UNIONCASE-001 | Warning | (3,6 - 3,10) | This discriminated union contains a case with the same name as a case from FSharp.Core. Consider renaming it or applying RequireQualifiedAccess to avoid clashes. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
[<RequireQualifiedAccess>] | ||
type MyU = | ||
| Case1 | ||
| None | ||
| Case3 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
[<FSharp.Core.RequireQualifiedAccess>] | ||
type MyU = | Choice7Of7 |