crystal-ameba / ameba Goto Github PK
View Code? Open in Web Editor NEWA static code analysis tool for Crystal
Home Page: https://crystal-ameba.github.io
License: MIT License
A static code analysis tool for Crystal
Home Page: https://crystal-ameba.github.io
License: MIT License
In many cases single character String
s could be safely replaced by Char
s ("."
=> '.'
), e.g.:
- "foo/bar".index("/")
+ "foo/bar".index('/')
⚡️ Benchmark:
require "benchmark"
Benchmark.ips do |x|
io1 = IO::Memory.new
io2 = IO::Memory.new
x.report("<< Char") do
io1 << 'a' << 'b' << 'c'
end
x.report("<< String") do
io2 << "a" << "b" << "c"
end
end
~ ❯ crystal run x.cr --release
<< Char 47.06M ( 21.25ns) (±23.32%) fastest
<< String 29.56M ( 33.83ns) (±17.99%) 1.59× slower
~ ❯ crystal run x.cr --release
<< Char 54.37M ( 18.39ns) (±31.44%) fastest
<< String 28.09M ( 35.61ns) (±15.39%) 1.94× slower
~ ❯ crystal run x.cr --release
<< Char 48.6M ( 20.58ns) (±23.82%) fastest
<< String 28.97M ( 34.51ns) (±17.46%) 1.68× slower
Several PRs regarding this, made by yours truly:
Just the affected line alone doesn't always provide enough information, thus oftentimes it's helpful to see several (ought to be configurable, usually 3/5 is a good default) lines of context before and after it.
Hi @veelenga, I think we should remove the --release
flag here 👉 https://github.com/veelenga/ameba/blob/master/Makefile#L6
Optimizations are very expensive on some environments. Compiling ameba using --release
after executing shards install
changes deploy time from seconds to minutes in some cases
Ameba is a CLI tool and is still very fast without --release
flag. So, I think we are spending extra compilation time with no gain.
Current the following code would trigger the Performance/SizeAfterFilter
rule
{{[1, 2, 3].select { |v| v > 1 }.size}}
However in a macro, there is not currently an ArrayLiteral#count
method, so there is no solution to this besides disabling it.
This rule should be disabled for ArrayLiteral
for now. Could be re-enabled if/when an ArrayLiteral#count
gets added.
Hello, since update to 0.28 for Clear my build fail on call to ameba, both in dev and travis environment, while all the checks are passed:
Output of my dev env:
$ bin/ameba src
Inspecting 122 files.
..........................................................................................................................
Finished in 497.43 milliseconds
122 inspected, 0 failures.
04:06 me@x1e ~/W/clear crystal-28 …1 ./rw
$ echo $status 1
(note: echo $status
stands for echo $?
in fish)
Output of the TravisCI build: https://travis-ci.org/anykeyh/clear/builds/524188305#L509
Try and see if var e
was defined and then called in "{e.inspect_with_backtrace}" and notify "#" is missing before interpolation.
etc..
Example:
def build_exception_with_cause
begin
raise Exception.new "Exception A"
rescue ex
raise Exception.new "Exception B", ex
end
rescue exception
exception
end
This of curse is illegal for Crystal.
PredicateName: Favour method name '404?' over 'is_404?'
I'd love for ameba to report on overly complex methods. I guess cyclomatic complexity needs no introduction.
Would probably make sense to open a Metrics/CyclomatixComplexity
group for that.
For example, this in a crystal file
data = "for template"
Kilt.render(template_path.ecr)
and a template that looks like this:
<p>some data <%= data %></p>
results in UselessAssign: Useless assignment to variable 'data'
# A rule that disallows comparison to booleans.
#
# For example, these are considered invalid:
#
# ```crystal
# foo == true
# bar != false
# false === baz
# ```
# This is because these expressions evaluate to `true` or `false`, so you
# could get the same result by using either the variable directly, or negating
# the variable.
As said here, comparison to booleans sometimes makes sense in Crystal:
a : Bool | Nil = some_value
if a == true
end
if a == false
end
if a == nil
end
It is not possible to check a type of the variable and implement it properly, so probably this rule just need to be removed.
I have two failures. I don't know how to solve it. I hope I can get help.
Lint/LiteralInCondition: Literal value found in conditional
> case {index, line}
^
Sample code:
private def v0_msg_spec(message_lines, index = 0, line = String.new)
case {index, line}
when {1, ""}
else
end
end
Lint/UselessAssign: Useless assignment to variable `proto`
> if (token = env.request.headers["Token"]?) && (proto = env.request.headers["Proto"]?)
^
Sample code:
post "/api/test" do |env|
if (token = env.request.headers["Token"]?) && (proto = env.request.headers["Proto"]?)
# Use token and proto variables
end
end
😀 Especially the second one, will it be a bug?
record Foo, foo = "foo" # Useless assignment to variable `foo`
I guess all assignments used as macro arguments shouldn't be treated as a useless assign because you can't know how it will be used in the macro.
I'd like to use ameba as part of a Gitlab CI build pipeline. While I could use an internal Docker image for this step, I think a public, ameba/ameba
image on Docker Hub would be useful to others as well.
Be glad to work on this and submit a PR if the maintainers agree.
Is it possible to do something like follows
# ameba:disable LargeNumbers
time = Time.epoch(1483859302)
I think it may be possible to add, if you're interested, by using the #doc
object on the AST node
Thanks!
Generate a configuration file acting as a TODO list. Disables rules failing in a current project.
Example:
ameba --gen-config
Hey there, I'm pretty certain this is a little bug, can you confirm?
data = [{1, "a"}, {2, "b"}, {3, "c"}]
data.each do |_, string|
data.each do |number, _|
puts string, number
end
end
And the error is:
test.cr:4:25
Lint/ShadowingOuterLocalVar: Shadowing outer local variable `_`
However _
should be used for unused values should it not and thus shadowing this particular variable shouldn't be a problem?
Kindest Regards
Fotis
Scenario:
$ ameba --gen-config
$ ameba --gen-config
The first command creates .ameba.yml
with all the excluded files. The second command uses created .ameba.yml
and the run ignores all the errors. As a result, a new file .ameba.yml
is generated and is empty.
giving me this HashDuplicatedKey: Duplicated keys in hash literal.
for a big hash is helpful but not really, I need to go manually and check which key is duplicated.
It could be nice to know which key is duplicated, or even better what lines both keys resides at.
Given the following code:
abstract class Parent
def initialize(@name : String); end
end
class Child < Parent
def initialize(name : String)
super
end
end
The child's initializer isn't required since it is the same as the parent.
in crystal 0.25 added annotations:
require "json"
class A
include JSON::Serializable
@[JSON::Field(ignore: true)]
property bla : Int32
end
Inspecting 1 file.
F
1.cr:5:9
Syntax: expecting token ']', not '::'
Finished in 14.49 milliseconds
1 inspected, 1 failure.
Hello,
I've an issue with my build here: https://travis-ci.org/anykeyh/clear/jobs/488396058
Failed make bin:
/usr/bin/shards build
Dependencies are satisfied
Building: ameba
Error target ameba failed to compile:
Unhandled exception: Overflow (OverflowError)
Failed to raise an exception: END_OF_STACK
[0x2b57a994fa76] ???
[0x2b57a8ea3a09] ???
[0x2b57a8eb71c2] ???
[0x2b57a8eade78] ???
[0x2b57a8eaa824] ???
[0x2b57a8ee2542] ???
[0x2b57a8ea6ced] ???
[0x2b57aad8cf5e] ???
I'm using crystal v0.27.1 and ameba v0.9
$ crystal --version
Crystal 0.27.1 [64137d045] (2019-01-30)
LLVM: 4.0.0
Default target: x86_64-unknown-linux-gnu
Any ideas? It works well on my dev machine. It might be related to LLVM since I'm using the 6.0 on my dev machine vs 4.0 on the travis build.
I'm not sure this is an error on ameba itself, but I'm trying to deploy an amber application to heroku and the deploy is failing.
the error trace is
remote: Compressing source files... done.
remote: Building source:
remote:
remote: -----> Amber app detected
remote: -----> Installing Crystal (v0.24.1 due to latest release at https://github.com/crystal-lang/crystal) from https://github.com/crystal-lang/crystal/releases/download/v0.24.1/crystal-0.24.1-2-linux-x86_64.tar.gz... done
remote: -----> Install project dependencies...
remote:
remote: Fetching https://github.com/amberframework/amber.git
remote: Fetching https://github.com/luislavena/radix.git
remote: Fetching https://github.com/jeromegn/kilt.git
remote: Fetching https://github.com/jeromegn/slang.git
remote: Fetching https://github.com/stefanwille/crystal-redis.git
remote: Fetching https://github.com/amberframework/cli.git
remote: Fetching https://github.com/mosop/optarg.git
remote: Fetching https://github.com/mosop/callback.git
remote: Fetching https://github.com/mosop/string_inflection.git
remote: Fetching https://github.com/amberframework/teeplate.git
remote: Fetching https://github.com/juanedi/micrate.git
remote: Fetching https://github.com/crystal-lang/crystal-db.git
remote: Fetching https://github.com/jwaldrip/shell-table.cr.git
remote: Fetching https://github.com/askn/spinner.git
remote: Fetching https://github.com/will/crystal-pg.git
remote: Fetching https://github.com/crystal-lang/crystal-mysql.git
remote: Fetching https://github.com/crystal-lang/crystal-sqlite3.git
remote: Fetching https://github.com/amberframework/granite-orm.git
remote: Fetching https://github.com/amberframework/quartz-mailer.git
remote: Fetching https://github.com/amberframework/smtp.cr.git
remote: Fetching https://github.com/amberframework/jasper-helpers.git
remote: Fetching https://github.com/amberframework/garnet-spec.git
remote: Fetching https://github.com/ysbaddaden/selenium-webdriver-crystal.git
remote: Installing amber (0.6.4)
remote: Installing radix (0.3.8)
remote: Installing kilt (0.4.0)
remote: Installing slang (1.7.1 at master)
remote: Installing redis (1.9.0)
remote: Installing cli (0.7.0)
remote: Installing optarg (0.5.8)
remote: Installing callback (0.6.3)
remote: Installing string_inflection (0.2.1)
remote: Installing teeplate (0.5.0)
remote: Installing micrate (0.3.0)
remote: Installing db (0.5.0)
remote: Installing shell-table (0.9.2)
remote: Installing spinner (0.1.1)
remote: Installing pg (0.14.1)
remote: Installing mysql (0.4.0)
remote: Installing sqlite3 (0.9.0)
remote: Installing granite_orm (0.8.2)
remote: Installing quartz_mailer (0.4.0)
remote: Installing smtp (0.3.0)
remote: Installing jasper_helpers (0.1.8)
remote: Installing garnet_spec (0.1.1)
remote: Installing selenium (0.3.0)
remote: done
remote: -----> Amber CLI not compiled... -----> Installing amber CLI... Fetching https://github.com/luislavena/radix.git
remote: Fetching https://github.com/jeromegn/kilt.git
remote: Fetching https://github.com/jeromegn/slang.git
remote: Fetching https://github.com/stefanwille/crystal-redis.git
remote: Fetching https://github.com/amberframework/cli.git
remote: Fetching https://github.com/mosop/optarg.git
remote: Fetching https://github.com/mosop/callback.git
remote: Fetching https://github.com/mosop/string_inflection.git
remote: Fetching https://github.com/amberframework/teeplate.git
remote: Fetching https://github.com/juanedi/micrate.git
remote: Fetching https://github.com/crystal-lang/crystal-db.git
remote: Fetching https://github.com/jwaldrip/shell-table.cr.git
remote: Fetching https://github.com/askn/spinner.git
remote: Fetching https://github.com/will/crystal-pg.git
remote: Fetching https://github.com/crystal-lang/crystal-mysql.git
remote: Fetching https://github.com/veelenga/ameba.git
remote: Error shard name (ameba) doesn't match dependency name (sqlite3)
remote: ! Push rejected, failed to compile Amber app.
remote:
remote: ! Push failed
remote: Verifying deploy...
remote:
remote: ! Push rejected to xxxx
remote:
As far as I can see I have no dependency to ameba inside my source, so I guess it might be required within any of the other shards.
Thanks a lot
Scenario:
.ameba.yml
:MySuperRule:
Exclude: **/src/controllers/*.cr
MySuperRule
should be disabled on all files matching the path.See crystal-lang/crystal#5179 for details.
I'm playing with amber framework and following error occurred while installing the dependencies when I executed shards install
in amber-stable folder:
Failed make bin:
/usr/bin/shards build --no-debug
Dependencies are satisfied
Building: ameba
Error target ameba failed to compile:
/usr/bin/ld: cannot find -lyaml
collect2: error: ld returned 1 exit status
Error: execution of command failed with code: 1: `cc "${@}" -o '/home/me/workspace/amber-stable/lib/ameba/bin/ameba' -rdynamic -lyaml -lpcre -lm -lgc -lpthread /usr/share/crystal/src/ext/libcrystal.a -levent -lrt -ldl -L/usr/lib -L/usr/local/lib`
Makefile:7: recipe for target 'build' failed
make: *** [build] Error 1
Crystal Version:
Crystal 0.24.2 [4f9ed8d03] (2018-03-08)
LLVM: 4.0.0
Default target: x86_64-unknown-linux-gnu
Hey there, thanks so much for writing Ameba, love it! 😄
I'm seeing a strange behaviour which I suspect might be a bug; given this code:
...
def process
# Determine the pip executable
executable : String? = nil
if @virtualenv
["pip", "pip3", "pip2"].each do |pip|
pip_path = File.join([@virtualenv.as(String), "bin", pip])
if File.exists?(pip_path)
executable = pip_path
break
end
end
unless executable
raise ActionProcessingError.new(
"Unable to find a pip executable in the virtualenv supplied"
)
end
...
Ameba says:
UselessAssign: Useless assignment to variable `executable`
However as you can see, I use executable
in the unless
block. By declaring executable : String? = nil
outside the if
statement block, the value of executable
is retained outside of the nested block.
Am I perhaps missing something or is this a bug in Ameba?
Thanks heaps
Fotis
Code below incorrectly triggers Style/RedundantBegin: Redundant 'begin' block detected
:
foo = ->{
begin
raise "Foo!"
rescue ex
pp ex
end
}
So that it will be possible to do
$ ameba --no-color | pbcopy
and have a correct output
I'm just raising a question. crlint looks more consistent in the world of tools like eslint, jslint, stylelint etc. If a developer sees "crlint", he would immediately assume that it's a linter for "cr", which is better than abstract Ameba thing. The same for .crlint.yaml
or .crlint.json
.
Changed the method name_column_number
to name_location
, so currently Ameba doesn't compile against master. Just a heads up for the upcoming 0.29.0
release.
For easier editor integration the Language Server Protocol can be used for lint tools like this.
See:
VSCode's TSLint LSP Server
VSCode's ESLint LSP Server
For Scry we have a Crystal implementation of the protocol, and I believe that this would be a very good reason to modularize it as a lsp
shard.
/cc @faustinoaq
The ability to autocorrect sources using a list of found errors. For example, me as a user seeing this error:
def has_user? # PredicateName: Favour method name 'user?' over 'has_user?'
end
would love to be able to automatically convert it to:
def user?
end
Should be doable with Crystal::Transformer
. Here is a simple example:
https://github.com/crystal-lang/crystal/blob/master/samples/compiler/transformer_example.cr
in src/ameba/cli/cmd.cr:10: instantiating 'Ameba::Config:Class#load(String)'
config = Config.load opts.config
^~~~
in src/ameba/config.cr:48: instantiating 'Ameba::Config:Class#new(YAML::Any)'
Config.new YAML.parse(content)
^~~
in src/ameba/config.cr:33: instance variable '@rules' of Ameba::Config must be Array(Ameba::Rule::Base), not Array(Ameba::Rule::ComparisonToBoolean | Ameba::Rule::ConstantNames | Ameba::Rule::DebuggerStatement | Ameba::Rule::EmptyEnsure | Ameba::Rule::EmptyExpression | Ameba::Rule::HashDuplicatedKey | Ameba::Rule::LargeNumbers | Ameba::Rule::LineLength | Ameba::Rule::LiteralInCondition | Ameba::Rule::LiteralInInterpolation | Ameba::Rule::MethodNames | Ameba::Rule::NegatedConditionsInUnless | Ameba::Rule::PercentArrays | Ameba::Rule::PredicateName | Ameba::Rule::RandZero | Ameba::Rule::RedundantBegin | Ameba::Rule::ShadowedException | Ameba::Rule::Syntax | Ameba::Rule::TrailingBlankLines | Ameba::Rule::TrailingWhitespace | Ameba::Rule::TypeNames | Ameba::Rule::UnlessElse | Ameba::Rule::UnneededDisableDirective | Ameba::Rule::UnusedArgument | Ameba::Rule::UselessAssign | Ameba::Rule::UselessConditionInWhen | Ameba::Rule::VariableNames | Ameba::Rule::WhileTrue)
@rules = Rule.rules.map &.new(config)
^~~~~~
User should be able to disable particular rules.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.