-
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.
* Extract EndsWith functionality. * Add String.StartsWith analyzer * Use FSharp.Analyzers.SDK.Testing * Restore project reference * Assert function signature. * Add positive test for String.IndexOf. * Update StringAnalyzer to latest changes. * Correctly run other string tests. * Add negative tests for String.IndexOf * Rename Testing to Common. * Remove old files * Update string analyzers to use the typed tree. * Add unit tests for overloads.
- Loading branch information
Showing
42 changed files
with
279 additions
and
161 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
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,127 @@ | ||
module GR.FSharp.Analyzers.StringAnalyzer | ||
|
||
open FSharp.Analyzers.SDK | ||
open FSharp.Compiler.Symbols | ||
open FSharp.Compiler.Text | ||
open GR.FSharp.Analyzers.TASTCollecting | ||
|
||
[<Literal>] | ||
let StringEndsWithCode = "GRA-STRING-001" | ||
|
||
[<Literal>] | ||
let StringStartsWithCode = "GRA-STRING-002" | ||
|
||
[<Literal>] | ||
let StringIndexOfCode = "GRA-STRING-003" | ||
|
||
let (|StringExpr|_|) (e : FSharpExpr) = | ||
if e.Type.ErasedType.BasicQualifiedName = "System.String" then | ||
Some () | ||
else | ||
None | ||
|
||
let (|IntExpr|_|) (e : FSharpExpr) = | ||
if e.Type.ErasedType.BasicQualifiedName = "System.Int32" then | ||
Some () | ||
else | ||
None | ||
|
||
let invalidStringFunctionUseAnalyzer | ||
functionName | ||
code | ||
message | ||
severity | ||
(typedTree : FSharpImplementationFileContents) | ||
(typedArgumentPredicate : FSharpExpr list -> bool) | ||
= | ||
let invocations = ResizeArray<range> () | ||
|
||
let handler : Handler = | ||
Handler.CallHandler (fun (m : range) (mfv : FSharpMemberOrFunctionOrValue) (args : FSharpExpr list) -> | ||
if | ||
mfv.Assembly.SimpleName = "System.Runtime" | ||
&& mfv.FullName = $"System.String.{functionName}" | ||
&& typedArgumentPredicate args | ||
then | ||
invocations.Add m | ||
) | ||
|
||
for decl in typedTree.Declarations do | ||
visitDeclaration handler decl | ||
|
||
invocations | ||
|> Seq.map (fun mFunctionName -> | ||
{ | ||
Type = $"String.{functionName} analyzer" | ||
Message = message | ||
Code = code | ||
Severity = severity | ||
Range = mFunctionName | ||
Fixes = [] | ||
} | ||
) | ||
|> Seq.toList | ||
|
||
[<CliAnalyzer "String.EndsWith Analyzer">] | ||
let endsWithAnalyzer (ctx : CliContext) : Async<Message list> = | ||
async { | ||
match ctx.TypedTree with | ||
| None -> return List.empty | ||
| Some typedTree -> | ||
|
||
return | ||
invalidStringFunctionUseAnalyzer | ||
"EndsWith" | ||
StringEndsWithCode | ||
"The usage of String.EndsWith with a single string argument is discouraged. Signal your intention explicitly by calling an overload." | ||
Warning | ||
typedTree | ||
(fun (args : FSharpExpr list) -> | ||
match args with | ||
| [ StringExpr ] -> true | ||
| _ -> false | ||
) | ||
} | ||
|
||
[<CliAnalyzer "String.StartsWith Analyzer">] | ||
let startsWithAnalyzer (ctx : CliContext) : Async<Message list> = | ||
async { | ||
match ctx.TypedTree with | ||
| None -> return List.empty | ||
| Some typedTree -> | ||
return | ||
invalidStringFunctionUseAnalyzer | ||
"StartsWith" | ||
StringStartsWithCode | ||
"The usage of String.StartsWith with a single string argument is discouraged. Signal your intention explicitly by calling an overload." | ||
Warning | ||
typedTree | ||
(fun (args : FSharpExpr list) -> | ||
match args with | ||
| [ StringExpr ] -> true | ||
| _ -> false | ||
) | ||
} | ||
|
||
[<CliAnalyzer "String.IndexOf Analyzer">] | ||
let indexOfAnalyzer (ctx : CliContext) : Async<Message list> = | ||
async { | ||
match ctx.TypedTree with | ||
| None -> return List.empty | ||
| Some typedTree -> | ||
|
||
return | ||
invalidStringFunctionUseAnalyzer | ||
"IndexOf" | ||
StringIndexOfCode | ||
"The usage of String.IndexOf with a single string argument is discouraged. Signal your intention explicitly by calling an overload." | ||
Warning | ||
typedTree | ||
(fun args -> | ||
match args with | ||
| [ StringExpr ] | ||
| [ StringExpr ; IntExpr ] | ||
| [ StringExpr ; IntExpr ; IntExpr ] -> true | ||
| _ -> false | ||
) | ||
} |
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,21 @@ | ||
module GR.FSharp.Analyzers.StringAnalyzer | ||
|
||
open FSharp.Analyzers.SDK | ||
|
||
[<Literal>] | ||
val StringEndsWithCode : string = "GRA-STRING-001" | ||
|
||
[<Literal>] | ||
val StringStartsWithCode : string = "GRA-STRING-002" | ||
|
||
[<Literal>] | ||
val StringIndexOfCode : string = "GRA-STRING-003" | ||
|
||
[<CliAnalyzer "String.EndsWith Analyzer">] | ||
val endsWithAnalyzer : ctx : CliContext -> Async<Message list> | ||
|
||
[<CliAnalyzer "String.StartsWith Analyzer">] | ||
val startsWithAnalyzer : ctx : CliContext -> Async<Message list> | ||
|
||
[<CliAnalyzer "String.IndexOf Analyzer">] | ||
val indexOfAnalyzer : ctx : CliContext -> Async<Message list> |
This file was deleted.
Oops, something went wrong.
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
Oops, something went wrong.