diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index 6efb4acfb..6f1d22130 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -1,3 +1,7 @@ +##### 0.8.1 - October 10 2017 + +* Fixed https://github.com/fsprojects/FSharpLint/issues/240 + ##### 0.8.0 - September 05 2017 * Updated `FSharp.Compiler.Service` diff --git a/src/FSharpLint.Core/Framework/ParseFile.fs b/src/FSharpLint.Core/Framework/ParseFile.fs index a08a06071..d8932bb79 100644 --- a/src/FSharpLint.Core/Framework/ParseFile.fs +++ b/src/FSharpLint.Core/Framework/ParseFile.fs @@ -93,9 +93,10 @@ module ParseFile = parse configuration file source (checker, projectOptions) /// Parses source code using `FSharp.Compiler.Service`. - let parseSource source configuration (checker:FSharpChecker) = - let file = "test.fsx" - - let options = getProjectOptionsFromScript checker file source + let parseSourceFile fileName source configuration (checker:FSharpChecker) = + let options = getProjectOptionsFromScript checker fileName source - parse configuration file source (checker, options) \ No newline at end of file + parse configuration fileName source (checker, options) + + let parseSource source configuration (checker:FSharpChecker) = + parseSourceFile "test.fsx" source configuration checker \ No newline at end of file diff --git a/src/FSharpLint.Core/Rules/NameConventions.fs b/src/FSharpLint.Core/Rules/NameConventions.fs index 1707c2673..36809d899 100644 --- a/src/FSharpLint.Core/Rules/NameConventions.fs +++ b/src/FSharpLint.Core/Rules/NameConventions.fs @@ -410,6 +410,15 @@ module NameConventions = | SynSimplePat.Id(ident, _, _, _, _, _) -> Some(ident) | SynSimplePat.Typed(p, _, _) -> identFromSimplePat p | SynSimplePat.Attrib(_) -> None + + /// Is module name implicitly created from file name? + let private isImplicitModule (SynModuleOrNamespace.SynModuleOrNamespace(longIdent, _, isModule, _, _, _, _, range)) = + let zeroLengthRange (r:range) = + (r.EndColumn - r.StartColumn) = 0 && r.StartLine = r.EndLine + + // Check the identifiers in the module name have no length. + // Not ideal but there's no attribute in the AST indicating the module is implicit from the file name. + isModule && longIdent |> List.forall (fun x -> zeroLengthRange x.idRange) let analyser (args: AnalyserArgs) : unit = let syntaxArray, skipArray = args.SyntaxArray, args.SkipArray @@ -441,12 +450,13 @@ module NameConventions = let checkRule = checkNamingRule i match syntaxArray.[i].Actual with - | AstNode.ModuleOrNamespace(SynModuleOrNamespace.SynModuleOrNamespace(identifier, _, isModule, _, _, _, _, _)) -> - let checkIdent = - if isModule then checkRule rules.ModuleNames - else checkRule rules.NamespaceNames + | AstNode.ModuleOrNamespace(SynModuleOrNamespace.SynModuleOrNamespace(identifier, _, isModule, _, _, _, _, _) as synModule) -> + if not <| isImplicitModule synModule then + let checkIdent = + if isModule then checkRule rules.ModuleNames + else checkRule rules.NamespaceNames - identifier |> List.collect checkIdent |> List.iter args.Info.Suggest + identifier |> List.collect checkIdent |> List.iter args.Info.Suggest | AstNode.UnionCase(SynUnionCase.UnionCase(_, identifier, _, _, _, _)) -> checkRule rules.UnionCasesNames identifier |> List.iter args.Info.Suggest | AstNode.Field(SynField.Field(_, _, identifier, _, _, _, _, _)) -> diff --git a/tests/FSharpLint.Core.Tests/Rules/TestNameConventionRules.fs b/tests/FSharpLint.Core.Tests/Rules/TestNameConventionRules.fs index b653628e0..826113e12 100644 --- a/tests/FSharpLint.Core.Tests/Rules/TestNameConventionRules.fs +++ b/tests/FSharpLint.Core.Tests/Rules/TestNameConventionRules.fs @@ -2,6 +2,7 @@ open NUnit.Framework open FSharpLint.Rules.NameConventions +open FSharpLint.Framework open FSharpLint.Framework.Configuration let config = @@ -63,6 +64,24 @@ type TestNameConventionRules() = member this.``Performance of naming analyser``() = Assert.Less(this.TimeAnalyser(100, defaultConfiguration), 20) + /// Regression test for: https://github.com/fsprojects/FSharpLint/issues/240 + [] + member this.``Linter must not complain about naming of fsx file``() = + this.Parse(input = """ +type MyClass2() as this = + member this.PrintMessage() = ()""", fileName = "3i-3.fsx") + + this.AssertNoWarnings() + + /// Regression test for: https://github.com/fsprojects/FSharpLint/issues/240 + [] + member this.``Linter must not complain about naming of fsx file with long name``() = + this.Parse(input = """ +type MyClass2() as this = + member this.PrintMessage() = ()""", fileName = "foo.3i-3.fsx") + + this.AssertNoWarnings() + [] member __.IsPascalCase() = Assert.IsTrue(isPascalCase "DogInBin") diff --git a/tests/FSharpLint.Core.Tests/Rules/TestRuleBase.fs b/tests/FSharpLint.Core.Tests/Rules/TestRuleBase.fs index 36276dabf..676bdba73 100644 --- a/tests/FSharpLint.Core.Tests/Rules/TestRuleBase.fs +++ b/tests/FSharpLint.Core.Tests/Rules/TestRuleBase.fs @@ -76,7 +76,7 @@ type TestRuleBase(analyser, ?analysers) = result - member __.Parse(input:string, ?overrideAnalysers, ?checkInput, ?fsharpVersion): unit = + member __.Parse(input:string, ?overrideAnalysers, ?checkInput, ?fsharpVersion, ?fileName): unit = let config = match overrideAnalysers with | Some(overrideAnalysers) -> @@ -91,8 +91,13 @@ type TestRuleBase(analyser, ?analysers) = Suggest = postSuggestion FSharpVersion = version Text = input } + + let parseResults = + match fileName with + | Some(fileName) -> parseSourceFile fileName input config (FSharpChecker.Create()) + | None -> parseSource input config (FSharpChecker.Create()) - match parseSource input config (FSharpChecker.Create()) with + match parseResults with | Success(parseInfo) -> let (syntaxArray, skipArray) = AbstractSyntaxArray.astToArray parseInfo.Ast analyser