Giter Club home page Giter Club logo

fsharplint's Introduction

FSharpLint GitHub Actions Build Status

FSharpLint is a style checking tool for F#. It points out locations where a set of rules on how F# is to be styled have been broken. The tool is configurable via JSON and can be run from a console app, or as an MSBuild task. It also provides an interface to easily integrate the tool into other software.

The project aims to let the user know of problems through matching user defined hints a la HLint, and also by using custom rules written in F# similar to the rules in Mascot and StyleCop.

The tool in use (running as an MSBuild task with TreatWarningsAsErrors set to true):

Example

Usage

FSharpLint can be used in several ways:

Documentation

The docs contain an overview of the tool and how to use it, including a list of the available rules for linting.

Nuget Packages

Package Version
dotnet tool NuGet Status
API NuGet Status

How to build

  1. Make sure you've installed the .NET version defined in global.json
  2. Run dotnet tool restore to install all developer tools required to build the project
  3. Run dotnet fake build -t Build to build (which executes the Build target from the FAKE-based build script)
  4. To run tests use dotnet fake build -t Test
  5. To build documentation use dotnet fake build -t Docs

How to work with documentation

  1. Make sure you've installed the .NET version defined in global.json
  2. Run dotnet tool restore to install all developer tools required to build the project
  3. Run dotnet fake build to build default target of build script
  4. Build documentation to make sure everything is fine with dotnet fake build -t Docs
  5. Go to docs folder cd docs and start Fornax in watch mode dotnet fornax watch
  6. Your documentation should be now accessible on localhost:8080 and will be regenerated on every file save

How to release

Please read the Releasing Guidelines if you're a maintainer.

How to contribute

Bug reports, feature requests, and pull requests are very welcome! Please read the Contribution Guidelines to get started.

Licensing

The project is licensed under MIT. For more information on the license see the LICENSE file.

Maintainer(s)

The default maintainer account for projects under "fsprojects" is @fsprojectsgit - F# Community Project Incubation Space (repo management)

fsharplint's People

Contributors

baronfel avatar bleis-tift avatar bryant1410 avatar davidtgillard avatar dungpa avatar enricosada avatar erikschierboom avatar forki avatar fsprojectsgit avatar janus avatar jgardella avatar jhamm avatar jrr avatar knocte avatar krzysztof-cieslak avatar mersho avatar mexx avatar milbrandt avatar numpsy avatar pirrmann avatar rmunn avatar samuela avatar sergey-tihon avatar sideeffffect avatar stevegilham avatar su8898 avatar tehraninasab avatar thorium avatar webwarrior-ws avatar zaymonfc avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

fsharplint's Issues

ParseException for projects targetting F# 4.3.1.0 on Windows

If I create a new console project in VS2013, set the target F# Runtime to 4.3.0.0, and build it, then I can run FSharpLint.exe against it and no warning are produced.
If I then set the runtime to 4.3.1.0 and rebuild, then running FSharpLint produces a crash:
Failed to parse file Program.fs Exception Message: Exception of type 'FSharpLint.Framework.Ast+ParseException' was thrown. Exception Stack Trace: at FSharpLint.Framework.Ast.parse(FSharpFunc2 finishEarly, InteractiveChecke
r checker, ProjectOptions projectOptions, String file, String input, FSharpList 1 visitors) in C:\Git\FSharpLint\src\FSharpLint.Framework\Ast.fs:line 521 at [email protected](Unit unitVar) in C:\Gi t\FSharpLint\src\FSharpLint.Application\RunLint.fs:line 94 at [email protected](AsyncParams1 a
rgs)`

Switching back to 4.3.0.0 and rebuilding makes the error go away again.

Configurable as to whether to type check code or not

There are a few circumstances where we need to lookup more information on an identifier.

Examples:

match 5 with
    | Number -> ()

We need to lookup Number to find out whether it's a discriminated union case or a new identifier.

[<Literal>]
let Cat = 5

We need to lookup the attribute to make sure it's the LiteralAttribute from FSharp.Core (could have been redefined).

Type checking the code makes the linter significantly slower, so the idea here is to let whether the code is type checked be configurable

Support SuppressMessageAttribute in plaintext visitors

Currently the SuppressMessageAttribute isn't supported by the FSharpLint.Typography analyser because it doesn't have access to the AST which is what is being used to get the SuppressMessageAttributes. Seems like the AST needs to be analysed initially to get a map of SuppressMessageAttribute to range for the plaintext visitors.

Fix visual studio extension

The extension needs to have any fluff taken out of it. Just a single button on the tools menu to run the lint on all open projects, display the errors in the error window, and display the progress in the output window. The extension right now is broken because of a bad dependency on FParsec

Simplify the configuration file

Currently the configuration file is more difficult to use than it needs to be as it tried to have a very similar format to StyleCop's configuration. A simpler type safe approach (allowing for an xsd not letting the user enter anything that shouldn't be possible) outweighs imo the benefits of the configuration mimicking StyleCop

add a FAKE task

we are using FSharpLint like this at the moment

Target "Lint" (fun _ ->
    let printException (e:System.Exception) =
        System.Console.WriteLine("Exception Message:")
        System.Console.WriteLine(e.Message)
        System.Console.WriteLine("Exception Stack Trace:")
        System.Console.WriteLine(e.StackTrace)

    let failedToParseFileError (file:string) parseException =
        printfn "%A" file
        printException parseException

    let parserProgress = function
        | FSharpLint.Application.RunLint.Starting(file)
        | FSharpLint.Application.RunLint.ReachedEnd(file) -> ()
        | FSharpLint.Application.RunLint.Failed(file, parseException) ->
            failedToParseFileError file parseException

    let error = System.Action<ErrorHandling.Error>(fun error ->  
        let output = error.Info + System.Environment.NewLine + ErrorHandling.errorInfoLine error.Range error.Input 
        System.Console.WriteLine(output)) 


    let lintOptions: RunLint.ProjectParseInfo =
        {
            /// Function that when returns true cancels the parsing of the project, useful for cancellation tokens etc.
            FinishEarly = System.Func<_>(fun _ -> false)

            /// Absolute path to the .fsproj file.
            ProjectFile = calculonProjectFile

            /// Callback that's called at the start and end of parsing each file (or when a file fails to be parsed).
            Progress = System.Action<RunLint.ParserProgress>(parserProgress)

            /// Callback that's called when a lint error is detected.
            ErrorReceived = error

            /// Optionally force the lint to lookup FSharp.Core.dll from this directory.
            FSharpCoreDirectory = Some fsharpCore
        }
    RunLint.parseProject lintOptions |> printfn "%A"

)

it would be nice to use it like this:

Target "Lint" (fun _ -> 
    !! projectFile
    |> FSharpLint(fun p -> 
    { p with
        Settings = Some settingsFile
        FSharpCoreDirectory =  Some coreDirectory }) 
)

Resolve reference to FSharp.Core directory when no version specified

Currently the FSharp.Core directory is looked up using the version number inside of the reference in the project file e.g. <Reference Include="FSharp.Core, Version=4.3.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"> will use 4.3.0.0. The version number is not required so this case needs to be handled.

I'm thinking that it should try and find the most recent version of FSharp.Core if no version is specified

Ignore files

Add a section to the configuration file that lets users specify files not to be linted

failwith/failwithf warning support

feature request.

failwith "%s" str // typo of failwith*f*. but this code has no warnings...
failwithf "%s %s" str1 str2 str3 // %s is not enough or str3 is extra.

I want to detect these cases.

Create Github pages site using the pages branch

Currently all of the documentation is in markdown, parts of it have become difficult to read and could do with further styling. We need to use the current markdown documentation to generate HTML documentation on the pages branch. It looks like FSharp.Formatting is the tool for this job, looking at other F# projects it tends to be tied up to the build script to push to the pages branch on build.

False positive for hints matched in method calls

type Bar() =
    static member SomeMethod(foo: bool) = ()

Bar.SomeMethod(foo = true)

This currently warns with x=true can be refactored into x because it's interpreting the named parameter as checking for equivalence rather than being assigned a value

We need more hints

Currently there's very few hints (20 in total)

Adding new hints is going to be an ongoing process, a good start will be to see what we can convert from the default HLint rules to F# hints. It would be great to build up a sizable collection of hints for the FSharp.Core library and the .NET framework.

At the moment there's limitations in which rules can be written e.g. we can't currently match against tuples or lists, these limitations are going to be the next priority

Create a control flow graph

A control flow graph will make analysing code in certain ways much simpler than using the visitor approach.

The goals I have in mind with it are so that we can: detect code that will never be hit and write hints in the config file like HLint's

The project needs a logo

I have no idea how logo for lint project should looks like, but I pretty sure that FSharpLint project and twitter account needs logo. And I have some options for you ;)

Option 1 (I like this one):
image
Option 2:
image
Option 3:
image
Option 4:
image
Option 5:
image
Option 6:
image

Any ideas/suggestions about logo?

Error on running on MonoDevelop

Running on MonoDevelop I get the following error:

/Users/dave/code/monodevelop/main/external/fsharpbinding/monodevelop/MonoDevelop.FSharpBinding/packages/FSharpLint.0.1.11/build/FSharpLint.targets: Warning: Lint failed while analysing /Users/dave/code/monodevelop/main/external/fsharpbinding/FSharp.CompilerBinding/FSharp.CompilerBinding.fsproj.
Failed with: Could not find any resources appropriate for the specified culture or the neutral culture.  Make sure "Text.resources" was correctly embedded or linked into assembly "FSharpLint.Framework" at compile time, or that all the satellite assemblies required are loadable and fully signed.
Stack trace:   at System.Resources.ResourceManager.AssemblyResourceMissing (System.String fileName) [0x00000] in <filename unknown>:0 
  at System.Resources.ResourceManager.InternalGetResourceSet (System.Globalization.CultureInfo culture, Boolean createIfNotExists, Boolean tryParents) [0x00000] in <filename unknown>:0 
  at System.Resources.ResourceManager.InternalGetResourceSet (System.Globalization.CultureInfo culture, Boolean createIfNotExists, Boolean tryParents) [0x00000] in <filename unknown>:0 
  at System.Resources.ResourceManager.InternalGetResourceSet (System.Globalization.CultureInfo culture, Boolean createIfNotExists, Boolean tryParents) [0x00000] in <filename unknown>:0 
  at System.Resources.ResourceManager.GetString (System.String name, System.Globalization.CultureInfo culture) [0x00000] in <filename unknown>:0 
  at System.Resources.ResourceManager.GetString (System.String name) [0x00000] in <filename unknown>:0 
  at FSharpLint.Framework.Resources.GetString (System.String name) [0x00000] in <filename unknown>:0 
  at FSharpLint.MSBuildIntegration.FSharpLintTask.logError (System.String resouce, System.Object[] args) [0x00000] in <filename unknown>:0 
  at FSharpLint.MSBuildIntegration.FSharpLintTask.Execute () [0x00000] in <filename unknown>:0  (FSharp.CompilerBinding)

Linkage issues using v0.1.6

I created a new F# console application with main file consisting of simply

let x = 23
printfn "%d" x

and added the 0.1.6 package to the project with the NuGet Gui. On building it I get errors every time I try

In VS2010SP1 on both Vista and Win7

This is reproducible on different machines, just so long as I'm using VS2010

D:\temp\ConsoleApplication1\packages\FSharpLint.0.1.6\build\FSharpLint.targets(16,5): warning : Lint failed while analysing D:\temp\ConsoleApplication1\ConsoleApplication1\ConsoleApplication1.fsproj.
Failed with: Method not found: 'ParserResult`2<!!0,Microsoft.FSharp.Core.Unit> FParsec.CharParsers.run(Microsoft.FSharp.Core.FSharpFunc`2<FParsec.CharStream`1<Microsoft.FSharp.Core.Unit>,FParsec.Reply`1<!!0>>, System.String)'.
Stack trace:    at [email protected](String hint)
   at Microsoft.FSharp.Primitives.Basics.List.map[T,TResult](FSharpFunc`2 mapping, FSharpList`1 x)
   at Microsoft.FSharp.Collections.ListModule.Map[T,TResult](FSharpFunc`2 mapping, FSharpList`1 list)
   at [email protected](FSharpMap`2 config)
   at FSharpLint.Framework.HintMatcher.RegisterHintVisitor.FSharpLint-Framework-LoadVisitors-IRegisterPluginWithConfigChecker-CheckConfig(FSharpMap`2 config)
   at Microsoft.FSharp.Primitives.Basics.List.map[T,TResult](FSharpFunc`2 mapping, FSharpList`1 x)
   at FSharpLint.Framework.LoadVisitors.checkConfigsForFailures(FSharpMap`2 config, FSharpList`1 checkConfigs)
   at FSharpLint.Application.ProjectFile.checkConfig@196(FSharpList`1 configCheckers, FSharpMap`2 config)
   at FSharpLint.Application.ProjectFile.loadConfigForProject(String projectFilePath)
   at FSharpLint.Application.ProjectFile.loadProjectFile$cont@219(String projectFile, FSharpOption`1 userSuppliedFSharpCoreDirectory, Result`1 matchValue, Unit unitVar)
   at FSharpLint.Application.ProjectFile.loadProjectFile(String projectFile, FSharpOption`1 userSuppliedFSharpCoreDirectory)
   at FSharpLint.Application.RunLint.parseProject(ProjectParseInfo projectInformation)
   at FSharpLint.MSBuildIntegration.FSharpLintTask.Execute()
========== Rebuild All: 1 succeeded, 0 failed, 0 skipped ==========

In VS2013 Update 3

D:\temp\ConsoleApplication1\packages\FSharpLint.0.1.6\build\FSharpLint.targets(16,5): warning : Lint failed while analysing D:\temp\ConsoleApplication1\ConsoleApplication1\ConsoleApplication1.fsproj.
Failed with: Could not load type 'Microsoft.FSharp.Compiler.SourceCodeServices.InteractiveChecker' from assembly 'FSharp.Compiler.Service, Version=0.0.76.0, Culture=neutral, PublicKeyToken=null'.
Stack trace:    at FSharpLint.Application.RunLint.parseProject(ProjectParseInfo projectInformation)
   at FSharpLint.MSBuildIntegration.FSharpLintTask.Execute()
========== Rebuild All: 1 succeeded, 0 failed, 0 skipped ==========

The consistent thing is that this is all on a separate logical drive to the system drive.

Add documentation for the FAKE task

Currently we have docs for:

  • Using the command line tool.
  • Using the MSBuild task.

It would be great to also have the usage of the FAKE task documented:

  • Using the command line tool.
  • Using the MSBuild task.
  • Using the FAKE task.

False positives for UselessBinding rule

The useless binding rule checks for any values that are then bound to the same name, there are cases where this is not useless i.e. a mutable value is bound to the same name but as immutable. Lint errors for this rule should only occur when an immutable value is bound to the same name as immutable

Lint FSharpLint

Now that SuppressMessageAttribute is supported it seems like a good time to set up the projects in the solution to be linted as part of the build process and failing the build if there are any warnings

Fix the FSharpLint.Typography analyser

Currently FSharpLint.Typography is turned off by default in the config, this is because at the moment it warns far too easily (hundreds of errors for most projects).

What I see that needs to be done:

  • MaxCharactersOnLine should be given a higher default than 80, bumping it up to 120 seems reasonable - keeps the code from vertical scroll in most windows.
  • TrailingWhitespaceOnLine needs to be either given a config setting to allow a certain number of spaces on the end of the line or to allow for a single space at the end of the line for certain statements e.g. fun () -> with the body of the lambda on the next line as that seems to be a reasonable instance for having a space on the end of the line.

Possible compatibility issue with the F# Power Tools extension (split from issue#46)

In VS2013 Update 3 or 4 with F# Power Tools extension v1.6.1, which links in the later FSharp.Compiler.Service version, installed:

D:\temp\ConsoleApplication1\packages\FSharpLint.0.1.6\build\FSharpLint.targets(16,5): warning : Lint failed while analysing D:\temp\ConsoleApplication1\ConsoleApplication1\ConsoleApplication1.fsproj.
Failed with: Could not load type 'Microsoft.FSharp.Compiler.SourceCodeServices.InteractiveChecker' from assembly 'FSharp.Compiler.Service, Version=0.0.76.0, Culture=neutral, PublicKeyToken=null'.
Stack trace:    at FSharpLint.Application.RunLint.parseProject(ProjectParseInfo projectInformation)
   at FSharpLint.MSBuildIntegration.FSharpLintTask.Execute()
========== Rebuild All: 1 succeeded, 0 failed, 0 skipped ==========

Tests have magically stopped passing

Tests have stopped passing with no changes to the project. Seems to be another issue with the wrong FSharp.Core being picked up (not having .sigdata and .optdata in the same directory), strange as it never required any references before - and a backup of the project i have still passes all the tests but I can't spot a difference between them...

Targets file needs to be able to pass the FSharp.Core directory to the MSBuild task

The MSBuild task has an optional argument that let's the user specify the directory of FSharp.Core if the tool is unable to look it up itself. Right now the targets file in the nuget package has no way of letting the user specify that property from their project file - it needs to be possible to specify the directory using an MSBuild property that the targets file will try to pass to the MSBuild task

New rule to find uses of global mutable state

"Find all uses of global mutable state in all code and referenced DLLs"

Seems like we'll need to inspect the MSIL of the referenced assemblies to find (in c# terms) public static mutable fields, and encapsulated static mutable fields that can be mutated via the public interface

Linting fails on .net 3.5 projects built against FSharp.Core 2.3.0.0

I created a default console application in VS2013u4, and set it to .net 3.5 (full profile), so F# core version 2.3.0.0.
I added F#Lint 1.10.0 through the NuGet UI in Visual Studio.
I then did a rebuild and got

Failed with: Exception of type 'FSharpLint.Framework.Ast+ParseException' was thrown.
Stack trace:    at FSharpLint.Framework.Ast.parseFile(FSharpChecker checker, FSharpProjectOptions projectOptions, String file, String input)
   at FSharpLint.Application.RunLint.parseFile(FSharpFunc`2 finishEarly, Action`1 errorReceived, Action`1 progress, ProjectFile project, FSharpChecker checker, FSharpList`1 plugins, FSharpProjectOptions projectOptions, String file)
   at [email protected](String file)
   at Microsoft.FSharp.Primitives.Basics.List.iter[T](FSharpFunc`2 f, FSharpList`1 x)
   at FSharpLint.Application.RunLint.parseProject(ProjectParseInfo projectInformation)
   at FSharpLint.MSBuildIntegration.FSharpLintTask.Execute()

(this is the simplified repro case of a problem I hit in more complicated circumstances)

Repeating the same steps for VS2010 (which links against core version 2.0.0.0) gives no problem

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.