diff options
| author | Gautham Goli | 2017-08-10 19:57:53 +0530 |
|---|---|---|
| committer | Gautham Goli | 2017-08-10 19:57:53 +0530 |
| commit | 4295a4ca788644475f702ddbae3bc592624f7ce4 (patch) | |
| tree | cee26e5b7b00bee96cd445f6a41658831dc9fae9 /Library/Homebrew/rubocops | |
| parent | a92e1eda27d732e0de75592d8fb52e93bb5e0d33 (diff) | |
| download | brew-4295a4ca788644475f702ddbae3bc592624f7ce4.tar.bz2 | |
audit: Port rules from line_problems to rubocop part 4(WIP-2)
Diffstat (limited to 'Library/Homebrew/rubocops')
| -rw-r--r-- | Library/Homebrew/rubocops/extend/formula_cop.rb | 25 | ||||
| -rw-r--r-- | Library/Homebrew/rubocops/lines_cop.rb | 125 |
2 files changed, 147 insertions, 3 deletions
diff --git a/Library/Homebrew/rubocops/extend/formula_cop.rb b/Library/Homebrew/rubocops/extend/formula_cop.rb index 991551585..08c9e6eb8 100644 --- a/Library/Homebrew/rubocops/extend/formula_cop.rb +++ b/Library/Homebrew/rubocops/extend/formula_cop.rb @@ -55,6 +55,7 @@ module RuboCop # Returns all string nodes among the descendants of given node def find_strings(node) return [] if node.nil? + return node if node.str_type? node.each_descendant(:str) end @@ -100,7 +101,9 @@ module RuboCop def find_method_with_args(node, method_name, *args) methods = find_every_method_call_by_name(node, method_name) methods.each do |method| - yield method if parameters_passed?(method, *args) + next unless parameters_passed?(method, *args) + return true unless block_given? + yield method end end @@ -114,6 +117,7 @@ module RuboCop next unless method.receiver && (method.receiver.const_name == instance || method.receiver.method_name == instance) @offense_source_range = method.source_range @offensive_node = method + return true unless block_given? yield method end end @@ -165,6 +169,20 @@ module RuboCop type_match && name_match end + # Find CONSTANTs in the source + # if block given, yield matching nodes + def find_const(node, const_name) + return if node.nil? + node.each_child_node(:const) do |const_node| + next if const_node.const_name != const_name + @offensive_node = const_node + @offense_source_range = const_node.source_range + yield const_node if block_given? + return true + end + nil + end + # To compare node with appropriate Ruby variable def node_equals?(node, var) node == Parser::CurrentRuby.parse(var.inspect) @@ -204,11 +222,12 @@ module RuboCop end # Returns a method definition node with method_name - def find_method_def(node, method_name) + # Returns first method def if method_name is nil + def find_method_def(node, method_name = nil) return if node.nil? node.each_child_node(:def) do |def_node| def_method_name = method_name(def_node) - next unless method_name == def_method_name + next unless method_name == def_method_name || method_name.nil? @offensive_node = def_node @offense_source_range = def_node.source_range return def_node diff --git a/Library/Homebrew/rubocops/lines_cop.rb b/Library/Homebrew/rubocops/lines_cop.rb index 338a3256a..4c357f6ab 100644 --- a/Library/Homebrew/rubocops/lines_cop.rb +++ b/Library/Homebrew/rubocops/lines_cop.rb @@ -88,6 +88,59 @@ module RuboCop end end + find_every_method_call_by_name(body_node, :depends_on).each do |m| + next unless modifier?(m) + dep, option = hash_dep(m) + next if dep.nil? || option.nil? + problem "Dependency #{string_content(dep)} should not use option #{string_content(option)}" + end + + find_instance_method_call(body_node, :version, :==) do |m| + next unless parameters_passed?(m, "HEAD") + problem "Use 'build.head?' instead of inspecting 'version'" + end + + find_instance_method_call(body_node, :ENV, :fortran) do + next if depends_on?(:fortran) + problem "Use `depends_on :fortran` instead of `ENV.fortran`" + end + + find_instance_method_call(body_node, :ARGV, :include?) do |m| + param = parameters(m).first + next unless match = regex_match_group(param, %r{--(HEAD|devel)}) + problem "Use \"if build.#{match[1].downcase}?\" instead" + end + + find_const(body_node, :MACOS_VERSION) do + problem "Use MacOS.version instead of MACOS_VERSION" + end + + find_const(body_node, :MACOS_FULL_VERSION) do + problem "Use MacOS.full_version instead of MACOS_FULL_VERSION" + end + + dependency(body_node) do |m| + # handle symbols and shit: WIP + next unless modifier?(m.parent) + dep = parameters(m).first + condition = m.parent.condition + if (condition.if? && condition.method_name == :include? && parameters_passed(condition, /with-#{string_content(dep)}$/))|| + (condition.if? && condition.method_name == :with? && parameters_passed?(condition, /#{string_content(dep)}$/)) + problem "Replace #{m.parent.source} with #{dep.source} => :optional" + end + if (condition.unless? && condition.method_name == :include? && parameters_passed?(condition, /without-#{string_content(dep)}$/))|| + (condition.unless? && condition.method_name == :without? && parameters_passed?(condition, /#{string_content(dep)}$/)) + problem "Replace #{m.parent.source} with #{dep.source} => :recommended" + end + end + + find_every_method_call_by_name(body_node, :depends_on).each do |m| + next unless modifier?(m.parent) + dep = parameters(m).first + next if dep.hash_type? + condition = m.parent.node_parts + end + find_method_with_args(body_node, :fails_with, :llvm) do problem "'fails_with :llvm' is now a no-op so should be removed" end @@ -154,9 +207,81 @@ module RuboCop problem "Use the `#{method}` Ruby method instead of `#{m.source}`" end + if find_method_def(@processed_source.ast) + problem "Define method #{method_name(@offensive_node)} in the class body, not at the top-level" + end + + find_instance_method_call(body_node, :build, :without?) do |m| + next unless unless_modifier?(m.parent) + correct = m.source.gsub("out?", "?").gsub("unless", "if") + problem "Use #{correct} instead of unless #{m.source}" + end + + find_instance_method_call(body_node, :build, :with?) do |m| + next unless unless_modifier?(m.parent) + correct = m.source.gsub("?", "out?").gsub("unless", "if") + problem "Use #{correct} instead of unless #{m.source}" + end + + find_instance_method_call(body_node, :build, :with?) do |m| + next unless negation?(m) + problem "Don't negate 'build.with?': use 'build.without?'" + end + + find_instance_method_call(body_node, :build, :without?) do |m| + next unless negation?(m) + problem "Don't negate 'build.without?': use 'build.with?'" + end + + find_instance_method_call(body_node, :build, :without?) do |m| + arg = parameters(m).first + next unless match = regex_match_group(arg, %r{-?-?without-(.*)}) + problem "Don't duplicate 'without': Use `build.without? \"#{match[1]}\"` to check for \"--without-#{match[1]}\"" + end + + find_instance_method_call(body_node, :build, :with?) do |m| + arg = parameters(m).first + next unless match = regex_match_group(arg, %r{-?-?with-(.*)}) + problem "Don't duplicate 'with': Use `build.with? \"#{match[1]}\"` to check for \"--with-#{match[1]}\"" + end + find_instance_method_call(body_node, :build, :include?) do |m| + arg = parameters(m).first + next unless match = regex_match_group(arg, %r{with(out)?-(.*)}) + problem "Use build.with#{match[1]}? \"#{match[2]}\" instead of build.include? 'with#{match[1]}-#{match[2]}'" + end + + find_instance_method_call(body_node, :build, :include?) do |m| + arg = parameters(m).first + next unless match = regex_match_group(arg, %r{\-\-(.*)}) + problem "Reference '#{match[1]}' without dashes" + end + + end + + def unless_modifier?(node) + node.modifier_form? && node.unless? end + def modifier?(node) + node.modifier_form? + end + + def_node_search :condition, <<-EOS.undent + (send (send nil :build) $_ $({str sym} _)) + EOS + + def_node_search :dependency, <<-EOS.undent + (send nil :depends_on ({str sym} _)) + EOS + + # Match depends_on with hash as argument + def_node_search :hash_dep, <<-EOS.undent + {$(hash (pair $(str _) $(str _))) + $(hash (pair $(str _) (array $(str _) ...)))} + EOS + + def_node_matcher :negation?, '(send ... :!)' # This is Pattern Matching method for AST # Takes the AST node as argument and yields matching node if block given # Else returns boolean for the match |
