Skip to content
Open
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
1 change: 1 addition & 0 deletions docs/content/how-tos/rule-configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -132,3 +132,4 @@ The following rules can be specified for linting.
- [FavourSingleton (FL0089)](rules/FL0089.html)
- [NoAsyncRunSynchronouslyInLibrary (FL0090)](rules/FL0090.html)
- [FavourNestedFunctions (FL0091)](rules/FL0091.html)
- [DisallowShadowing (FL0092)](rules/FL0092.html)
29 changes: 29 additions & 0 deletions docs/content/how-tos/rules/FL0092.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
---
title: FL0092
category: how-to
hide_menu: true
---

# DisallowShadowing (FL0092)

*Introduced in `0.26.12`*

## Cause

A variable or parameter shadows another one with the same name.

## Rationale

Sometimes shadowing can cause confusion.

## How To Fix

Rename varaible or parameter in question so it has unique name in its scope.

## Rule Settings

{
"disallowShadowing": {
"enabled": false
}
}
28 changes: 14 additions & 14 deletions src/FSharpLint.Console/Program.fs
Original file line number Diff line number Diff line change
Expand Up @@ -109,25 +109,25 @@ let internal inferFileType (target:string) =

/// Must be called only once per process.
/// We're calling it globally so we can call main multiple times from our tests.
let toolsPath = Ionide.ProjInfo.Init.init (DirectoryInfo <| Directory.GetCurrentDirectory()) None
let globalToolsPath = Ionide.ProjInfo.Init.init (DirectoryInfo <| Directory.GetCurrentDirectory()) None

[<EntryPoint>]
let main argv =
let parserProgress (output:Output.IOutput) = function
| Starting file ->
String.Format(Resources.GetString("ConsoleStartingFile"), file) |> output.WriteInfo
| ReachedEnd (_, warnings) ->
String.Format(Resources.GetString("ConsoleFinishedFile"), List.length warnings) |> output.WriteInfo
| Failed (file, parseException) ->
String.Format(Resources.GetString("ConsoleFailedToParseFile"), file) |> output.WriteError
output.WriteError
$"Exception Message:{Environment.NewLine}{parseException.Message}{Environment.NewLine}Exception Stack Trace:{Environment.NewLine}{parseException.StackTrace}{Environment.NewLine}"

let lint
(lintArgs: ParseResults<LintArgs>)
(output: Output.IOutput)
(toolsPath:Ionide.ProjInfo.Types.ToolsPath)
: ExitCode =
let parserProgress (output:Output.IOutput) = function
| Starting file ->
String.Format(Resources.GetString("ConsoleStartingFile"), file) |> output.WriteInfo
| ReachedEnd (_, warnings) ->
String.Format(Resources.GetString("ConsoleFinishedFile"), List.length warnings) |> output.WriteInfo
| Failed (file, parseException) ->
String.Format(Resources.GetString("ConsoleFailedToParseFile"), file) |> output.WriteError
output.WriteError
$"Exception Message:{Environment.NewLine}{parseException.Message}{Environment.NewLine}Exception Stack Trace:{Environment.NewLine}{parseException.StackTrace}{Environment.NewLine}"

let mutable exitCode = ExitCode.Success

let handleError (str:string) =
Expand Down Expand Up @@ -181,9 +181,9 @@ let main argv =
handleLintResult lintResult
with
| exn ->
let target = if fileType = FileType.Source then "source" else target
let targetStr = if fileType = FileType.Source then "source" else target
handleError
$"Lint failed while analysing %s{target}.{Environment.NewLine}Failed with: %s{exn.Message}{Environment.NewLine}Stack trace: {exn.StackTrace}"
$"Lint failed while analysing %s{targetStr}.{Environment.NewLine}Failed with: %s{exn.Message}{Environment.NewLine}Stack trace: {exn.StackTrace}"

exitCode

Expand Down Expand Up @@ -217,5 +217,5 @@ let main argv =
| _ -> Some ConsoleColor.Red)
let parser = ArgumentParser.Create<ToolArgs>(programName = "fsharplint", errorHandler = errorHandler)
let parseResults = parser.ParseCommandLine argv
start parseResults toolsPath
start parseResults globalToolsPath
|> int
37 changes: 20 additions & 17 deletions src/FSharpLint.Core/Application/Configuration.fs
Original file line number Diff line number Diff line change
Expand Up @@ -107,16 +107,14 @@ module IgnoreFiles =
match remainingPath with
| [_] when isDirectory -> false
| currentSegment::remaining ->
let currentlyMatchingGlobs = globs::currentlyMatchingGlobs
let updatedCurrentlyMatchingGlobs = getRemainingGlobSeqForMatches currentSegment (globs::currentlyMatchingGlobs)

let currentlyMatchingGlobs = getRemainingGlobSeqForMatches currentSegment currentlyMatchingGlobs

let aGlobWasCompletelyMatched = List.exists List.isEmpty currentlyMatchingGlobs
let aGlobWasCompletelyMatched = List.exists List.isEmpty updatedCurrentlyMatchingGlobs

let matched = aGlobWasCompletelyMatched && (isDirectory || (not isDirectory && List.isEmpty remaining))

if matched then true
else doesGlobSeqMatchPathSeq globs isDirectory remaining currentlyMatchingGlobs
else doesGlobSeqMatchPathSeq globs isDirectory remaining updatedCurrentlyMatchingGlobs
| [] -> false

let private pathMatchesGlob (globs:Regex list) (path:string list) isDirectory =
Expand Down Expand Up @@ -387,7 +385,8 @@ type ConventionsConfig =
suggestUseAutoProperty:EnabledConfig option
usedUnderscorePrefixedElements:EnabledConfig option
ensureTailCallDiagnosticsInRecursiveFunctions:EnabledConfig option
favourNestedFunctions:EnabledConfig option }
favourNestedFunctions:EnabledConfig option
disallowShadowing:EnabledConfig option}
with
member this.Flatten() =
Array.concat
Expand Down Expand Up @@ -416,6 +415,7 @@ with
this.ensureTailCallDiagnosticsInRecursiveFunctions |> Option.bind (constructRuleIfEnabled EnsureTailCallDiagnosticsInRecursiveFunctions.rule) |> Option.toArray
this.indexerAccessorStyleConsistency |> Option.bind (constructRuleWithConfig IndexerAccessorStyleConsistency.rule) |> Option.toArray
this.favourNestedFunctions |> Option.bind (constructRuleIfEnabled FavourNestedFunctions.rule) |> Option.toArray
this.disallowShadowing |> Option.bind (constructRuleIfEnabled DisallowShadowing.rule) |> Option.toArray
|]

[<Obsolete(ObsoleteMsg, ObsoleteWarnTreatAsError)>]
Expand Down Expand Up @@ -557,7 +557,8 @@ type Configuration =
InterpolatedStringWithNoSubstitution:EnabledConfig option
FavourSingleton:EnabledConfig option
NoAsyncRunSynchronouslyInLibrary:EnabledConfig option
FavourNestedFunctions:EnabledConfig option }
FavourNestedFunctions:EnabledConfig option
DisallowShadowing:EnabledConfig option }
with
static member Zero = {
Global = None
Expand Down Expand Up @@ -661,6 +662,7 @@ with
FavourSingleton = None
NoAsyncRunSynchronouslyInLibrary = None
FavourNestedFunctions = None
DisallowShadowing = None
}

// fsharplint:enable RecordFieldNames
Expand Down Expand Up @@ -688,7 +690,7 @@ let defaultConfiguration =
use stream = assembly.GetManifestResourceStream(resourceName)
match stream with
| null -> failwithf "Resource '%s' not found in assembly '%s'" resourceName (assembly.FullName)
| stream ->
| _ ->
use reader = new System.IO.StreamReader(stream)

reader.ReadToEnd()
Expand All @@ -705,8 +707,8 @@ type LoadedRules =
LineRules:LineRules
DeprecatedRules:Rule [] }

let getGlobalConfig (globalConfig:GlobalConfig option) =
globalConfig
let getGlobalConfig (maybeGlobalConfig: GlobalConfig option) =
maybeGlobalConfig
|> Option.map (fun globalConfig -> {
Rules.GlobalRuleConfig.numIndentationSpaces = globalConfig.numIndentationSpaces |> Option.defaultValue Rules.GlobalRuleConfig.Default.numIndentationSpaces
}) |> Option.defaultValue Rules.GlobalRuleConfig.Default
Expand Down Expand Up @@ -747,11 +749,11 @@ let findDeprecation config deprecatedAllRules allRules =
// fsharplint:disable MaxLinesInFunction
let flattenConfig (config:Configuration) =
let parseHints (hints:string []) =
let parseHint hint =
match FParsec.CharParsers.run HintParser.phint hint with
let parseHint hintString =
match FParsec.CharParsers.run HintParser.phint hintString with
| FParsec.CharParsers.Success(hint, _, _) -> hint
| FParsec.CharParsers.Failure(error, _, _) ->
raise <| ConfigurationException $"Failed to parse hint: {hint}{Environment.NewLine}{error}"
raise <| ConfigurationException $"Failed to parse hint: {hintString}{Environment.NewLine}{error}"

hints
|> Array.filter (System.String.IsNullOrWhiteSpace >> not)
Expand All @@ -765,12 +767,12 @@ let flattenConfig (config:Configuration) =
Array.concat
[|
// Deprecated grouped configs. TODO: remove in next major release
config.formatting |> Option.map (fun config -> config.Flatten()) |> Option.toArray |> Array.concat
config.conventions |> Option.map (fun config -> config.Flatten()) |> Option.toArray |> Array.concat
config.typography |> Option.map (fun config -> config.Flatten()) |> Option.toArray |> Array.concat
config.formatting |> Option.map (fun formattingConfig -> formattingConfig.Flatten()) |> Option.toArray |> Array.concat
config.conventions |> Option.map (fun conventionsConfig -> conventionsConfig.Flatten()) |> Option.toArray |> Array.concat
config.typography |> Option.map (fun typographyConfig -> typographyConfig.Flatten()) |> Option.toArray |> Array.concat
// </Deprecated>

config.Hints |> Option.map (fun config -> HintMatcher.rule { HintMatcher.Config.HintTrie = parseHints (getOrEmptyList config.add) }) |> Option.toArray
config.Hints |> Option.map (fun hintsConfig -> HintMatcher.rule { HintMatcher.Config.HintTrie = parseHints (getOrEmptyList hintsConfig.add) }) |> Option.toArray
|]

let allRules =
Expand Down Expand Up @@ -868,6 +870,7 @@ let flattenConfig (config:Configuration) =
config.FavourSingleton |> Option.bind (constructRuleIfEnabled FavourSingleton.rule)
config.NoAsyncRunSynchronouslyInLibrary |> Option.bind (constructRuleIfEnabled NoAsyncRunSynchronouslyInLibrary.rule)
config.FavourNestedFunctions |> Option.bind (constructRuleIfEnabled FavourNestedFunctions.rule)
config.DisallowShadowing |> Option.bind (constructRuleIfEnabled DisallowShadowing.rule)
|]

findDeprecation config deprecatedAllRules allRules
6 changes: 3 additions & 3 deletions src/FSharpLint.Core/Application/Lint.fs
Original file line number Diff line number Diff line change
Expand Up @@ -523,12 +523,12 @@ module Lint =

let (successes, failures) =
lintResults
|> Array.fold (fun (successes, failures) result ->
|> Array.fold (fun (successList, failureList) result ->
match result with
| LintResult.Success warnings ->
(List.append warnings successes, failures)
(List.append warnings successList, failureList)
| LintResult.Failure err ->
(successes, err :: failures)) (List.Empty, List.Empty)
(successList, err :: failureList)) (List.Empty, List.Empty)

match failures with
| [] ->
Expand Down
1 change: 1 addition & 0 deletions src/FSharpLint.Core/FSharpLint.Core.fsproj
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@
<Compile Include="Rules\Conventions\FailwithBadUsage.fs" />
<Compile Include="Rules\Conventions\FavourSingleton.fs" />
<Compile Include="Rules\Conventions\FavourNestedFunctions.fs" />
<Compile Include="Rules\Conventions\DisallowShadowing.fs" />
<Compile Include="Rules\Conventions\SourceLength\SourceLengthHelper.fs" />
<Compile Include="Rules\Conventions\SourceLength\MaxLinesInLambdaFunction.fs" />
<Compile Include="Rules\Conventions\SourceLength\MaxLinesInMatchLambdaFunction.fs" />
Expand Down
8 changes: 4 additions & 4 deletions src/FSharpLint.Core/Framework/AbstractSyntaxArray.fs
Original file line number Diff line number Diff line change
Expand Up @@ -250,7 +250,7 @@ module AbstractSyntaxArray =
tryAddPossibleSkips depth

// Strip out "extra info".
let node =
let strippedNode =
let extractExtraInfo actual extraInfoNode =
possibleSkips.Push (PossibleSkip(nodes.Count, depth))
nodes.Add (TempNode(Utilities.hash2 extraInfoNode 0, actual))
Expand All @@ -262,13 +262,13 @@ module AbstractSyntaxArray =
| Else(body) -> extractExtraInfo (Expression(body)) SyntaxNode.Else
| _ -> node

traverseNode node (fun node -> left.Push (StackedNode(node, depth + 1)))
traverseNode strippedNode (fun aNode -> left.Push (StackedNode(aNode, depth + 1)))

match astNodeToSyntaxNode node with
match astNodeToSyntaxNode strippedNode with
| SyntaxNode.Other -> ()
| syntaxNode ->
possibleSkips.Push (PossibleSkip(nodes.Count, depth))
nodes.Add (TempNode(Utilities.hash2 syntaxNode (getHashCode node), node))
nodes.Add (TempNode(Utilities.hash2 syntaxNode (getHashCode strippedNode), strippedNode))

tryAddPossibleSkips 0

Expand Down
4 changes: 2 additions & 2 deletions src/FSharpLint.Core/Framework/AstInfo.fs
Original file line number Diff line number Diff line change
Expand Up @@ -120,9 +120,9 @@ module AstInfo =
if Seq.isEmpty str then
true
else
let operator = List.tryFind (fun (op: string) -> str.StartsWith(op)) operators
let maybeOperator = List.tryFind (fun (op: string) -> str.StartsWith(op)) operators

match operator with
match maybeOperator with
| Some(operator) -> str.Substring(operator.Length) |> isSequenceOfOperators
| None -> false

Expand Down
4 changes: 2 additions & 2 deletions src/FSharpLint.Core/Framework/HintParser.fs
Original file line number Diff line number Diff line change
Expand Up @@ -83,9 +83,9 @@ module HintParser =
[ attempt pident
.>>. many (attempt (skipChar '.' >>. pident))
.>>. opt (skipChar '.' >>. pidentorop)
|>> (fun ((startIdent, idents), operator) ->
|>> (fun ((startIdent, idents), maybeOperator) ->
let identifiers = startIdent::idents
match operator with
match maybeOperator with
| Some(operator) -> identifiers@[operator]
| None -> identifiers)
attempt (pidentorop |>> fun identOrOpChars -> [identOrOpChars])
Expand Down
23 changes: 11 additions & 12 deletions src/FSharpLint.Core/Framework/Suppression.fs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ type SuppressionInfo =
type LineSuppression = { Line:int; Suppressions:SuppressionInfo list }

/// Parses a given file to find lines containing rule suppressions.
let parseSuppressionInfo (rules:Set<String>) (lines:string list) =
let parseSuppressionInfo (originalRuleNames:Set<String>) (lines:string list) =
/// Extracts rule names from a whitespace separated string of rule names.
let extractRules (rules:Set<String>) (str:string) =
let (splitOnWhitespace:char[]) = null
Expand All @@ -29,16 +29,16 @@ let parseSuppressionInfo (rules:Set<String>) (lines:string list) =
// If no rules set, then all rules are applied.
if Seq.isEmpty entries then rules else entries

let rules = Set.map (fun (rule: String) -> rule.ToLowerInvariant()) rules
let lowerCasedRules = Set.map (fun (rule: String) -> rule.ToLowerInvariant()) originalRuleNames

let choose lineNum line =
let matched = Regex.Match (line, ".*fsharplint:([a-z\-]+)\s*(.*)$")
if matched.Success then
let suppressionTarget =
if matched.Groups.Count = 3 then
extractRules rules matched.Groups.[2].Value
extractRules lowerCasedRules matched.Groups.[2].Value
else
rules
lowerCasedRules
match matched.Groups.[1].Value with
| "enable" -> Some (lineNum, Enable suppressionTarget)
| "disable" -> Some (lineNum, Disable suppressionTarget)
Expand All @@ -62,26 +62,25 @@ let isSuppressed (rule:String) (line:int) (lineSuppressions:LineSuppression list
if List.isEmpty lineSuppressions then
false
else
let rule = rule.ToLowerInvariant()

let ruleLowercase = rule.ToLowerInvariant()

let fold (disabledRules:Set<String>) (lineSuppression:LineSuppression) =
let innerFold (disabledRules:Set<String>) suppression =
let innerFold (currentDisabledRules:Set<String>) suppression =
match suppression with
| Enable(rules) ->
Set.difference disabledRules rules
Set.difference currentDisabledRules rules
| Disable(rules) ->
Set.union disabledRules rules
Set.union currentDisabledRules rules
| DisableLine(rules) ->
if line = lineSuppression.Line then
Set.union disabledRules rules
Set.union currentDisabledRules rules
else
disabledRules
currentDisabledRules
List.fold innerFold disabledRules lineSuppression.Suppressions

let disabledRules =
lineSuppressions
|> List.takeWhile (fun lineSupression -> lineSupression.Line <= line)
|> List.fold fold Set.empty

disabledRules.Contains(rule)
disabledRules.Contains(ruleLowercase)
9 changes: 5 additions & 4 deletions src/FSharpLint.Core/Framework/Utilities.fs
Original file line number Diff line number Diff line change
Expand Up @@ -88,10 +88,10 @@ module ExpressionUtilities =

/// Tries to find the source code within a given range.
let tryFindTextOfRange (range:Range) (text:string) =
let startIndex = findPos range.Start text
let endIndex = findPos range.End text
let maybeStartIndex = findPos range.Start text
let maybeEndIndex = findPos range.End text

match (startIndex, endIndex) with
match (maybeStartIndex, maybeEndIndex) with
| Some(startIndex), Some(endIndex) ->
text.Substring(startIndex, endIndex - startIndex) |> Some
| _ -> None
Expand Down Expand Up @@ -142,7 +142,8 @@ module ExpressionUtilities =
|> Option.defaultValue 0

let rangeContainsOtherRange (containingRange:Range) (range:Range) =
range.StartLine >= containingRange.StartLine && range.EndLine <= containingRange.EndLine
(range.StartLine, range.StartColumn) >= (containingRange.StartLine, containingRange.StartColumn)
&& (range.EndLine, range.EndColumn) <= (containingRange.EndLine, containingRange.EndColumn)

module String =

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ and [<TailCall>] private checkExprContinuationPassingStyle (arguments: CheckExpr
arguments.Continuation Array.empty

let runner (args: AstNodeRuleParams) =
let checkExpr (args: AstNodeRuleParams) (expr: SynExpr) (outerArgExpr: SynExpr) (range: FSharp.Compiler.Text.range) (parentList: AstNode list): WarningDetails array =
let checkExpr (expr: SynExpr) (outerArgExpr: SynExpr) (range: FSharp.Compiler.Text.range) (parentList: AstNode list): WarningDetails array =
checkExprContinuationPassingStyle
{
Args = args
Expand All @@ -110,7 +110,7 @@ let runner (args: AstNodeRuleParams) =
// function has extra arguments
Array.empty
| _ ->
checkExpr args funcExpr argExpr range (args.GetParents args.NodeIndex)
checkExpr funcExpr argExpr range (args.GetParents args.NodeIndex)
| _ ->
Array.empty

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ open FSharpLint.Framework.Rules

let private checkForBindingToAWildcard pattern range fileContent (expr: SynExpr) letBindingRange =
let rec findWildAndIgnoreParens = function
| SynPat.Paren(pattern, _) -> findWildAndIgnoreParens pattern
| SynPat.Paren(pat, _) -> findWildAndIgnoreParens pat
| SynPat.Wild(_) -> true
| _ -> false

Expand Down
Loading
Loading