Permalink
Browse files

WIP: Store SourceFile fields source, lines and ast in ETS tables

  • Loading branch information...
rrrene committed May 13, 2017
1 parent d3660ed commit c717c66bcc7203eb410cdd1ebcae4bdf64d4a814
Showing with 284 additions and 246 deletions.
  1. +3 −1 .template.check.ex
  2. +3 −2 lib/credo.ex
  3. +12 −5 lib/credo/check/code_helper.ex
  4. +4 −4 lib/credo/check/consistency/exception_names.ex
  5. +2 −2 lib/credo/check/consistency/exception_names/prefix_and_suffix_collector.ex
  6. +3 −1 lib/credo/check/consistency/line_endings/unix.ex
  7. +3 −1 lib/credo/check/consistency/line_endings/windows.ex
  8. +4 −3 lib/credo/check/consistency/multi_alias_import_require_use/multi.ex
  9. +4 −3 lib/credo/check/consistency/multi_alias_import_require_use/single.ex
  10. +2 −2 lib/credo/check/consistency/parameter_pattern_matching/position_collector.ex
  11. +3 −3 lib/credo/check/consistency/space_around_operators/with_space.ex
  12. +1 −1 lib/credo/check/consistency/space_around_operators/without_space.ex
  13. +3 −1 lib/credo/check/consistency/tabs_or_spaces/spaces.ex
  14. +3 −1 lib/credo/check/consistency/tabs_or_spaces/tabs.ex
  15. +4 −2 lib/credo/check/design/alias_usage.ex
  16. +3 −1 lib/credo/check/design/duplicated_code.ex
  17. +3 −2 lib/credo/check/design/tag_fixme.ex
  18. +2 −1 lib/credo/check/design/tag_todo.ex
  19. +1 −1 lib/credo/check/readability/large_numbers.ex
  20. +4 −3 lib/credo/check/readability/max_line_length.ex
  21. +2 −2 lib/credo/check/readability/module_doc.ex
  22. +1 −1 lib/credo/check/readability/parentheses_in_condition.ex
  23. +1 −1 lib/credo/check/readability/parentheses_on_zero_arity_defs.ex
  24. +1 −1 lib/credo/check/readability/predicate_function_names.ex
  25. +1 −1 lib/credo/check/readability/prefer_implicit_try.ex
  26. +3 −2 lib/credo/check/readability/redundant_blank_lines.ex
  27. +1 −1 lib/credo/check/readability/semicolons.ex
  28. +2 −2 lib/credo/check/readability/single_pipe.ex
  29. +1 −0 lib/credo/check/readability/space_after_commas.ex
  30. +1 −1 lib/credo/check/readability/specs.ex
  31. +2 −1 lib/credo/check/readability/string_sigils.ex
  32. +5 −2 lib/credo/check/readability/trailing_blank_line.ex
  33. +3 −2 lib/credo/check/readability/trailing_white_space.ex
  34. +2 −2 lib/credo/check/refactor/abc_size.ex
  35. +1 −1 lib/credo/check/refactor/append_single_item.ex
  36. +2 −2 lib/credo/check/refactor/case_trivial_matches.ex
  37. +2 −2 lib/credo/check/refactor/cond_statements.ex
  38. +2 −2 lib/credo/check/refactor/cyclomatic_complexity.ex
  39. +1 −1 lib/credo/check/refactor/double_boolean_negation.ex
  40. +2 −2 lib/credo/check/refactor/function_arity.ex
  41. +2 −2 lib/credo/check/refactor/match_in_condition.ex
  42. +2 −2 lib/credo/check/refactor/nesting.ex
  43. +2 −2 lib/credo/check/refactor/perceived_complexity.ex
  44. +2 −2 lib/credo/check/refactor/pipe_chain_start.ex
  45. +2 −2 lib/credo/check/refactor/variable_rebinding.ex
  46. +1 −1 lib/credo/check/warning/iex_pry.ex
  47. +1 −1 lib/credo/check/warning/io_inspect.ex
  48. +1 −1 lib/credo/check/warning/lazy_logging.ex
  49. +2 −2 lib/credo/check/warning/map_get_unsafe_pass.ex
  50. +1 −1 lib/credo/check/warning/unused_enum_operation.ex
  51. +1 −1 lib/credo/check/warning/unused_file_operation.ex
  52. +2 −2 lib/credo/check/warning/unused_function_return_helper.ex
  53. +2 −1 lib/credo/check/warning/unused_keyword_operation.ex
  54. +2 −1 lib/credo/check/warning/unused_list_operation.ex
  55. +2 −1 lib/credo/check/warning/unused_path_operation.ex
  56. +2 −1 lib/credo/check/warning/unused_regex_operation.ex
  57. +2 −1 lib/credo/check/warning/unused_string_operation.ex
  58. +2 −1 lib/credo/check/warning/unused_tuple_operation.ex
  59. +0 −2 lib/credo/cli/command/list.ex
  60. +1 −1 lib/credo/cli/output/explain.ex
  61. +3 −2 lib/credo/cli/output/issue_helper.ex
  62. +1 −1 lib/credo/cli/output/issues_by_scope.ex
  63. +27 −9 lib/credo/code.ex
  64. +9 −2 lib/credo/priority.ex
  65. +45 −0 lib/credo/service/ets_table_helper.ex
  66. +3 −0 lib/credo/service/source_file_ast.ex
  67. +0 −40 lib/credo/service/source_file_code_only.ex
  68. +3 −0 lib/credo/service/source_file_lines.ex
  69. +1 −37 lib/credo/service/source_file_scopes.ex
  70. +3 −0 lib/credo/service/source_file_source.ex
  71. +0 −39 lib/credo/service/source_file_without_strings_and_sigils.ex
  72. +52 −16 lib/credo/source_file.ex
  73. +1 −1 test/credo/sources_test.exs
  74. +1 −2 test/test_helper.exs
@@ -19,7 +19,9 @@ defmodule <%= @check_name %> do
use Credo.Check, base_priority: :high, category: :custom, exit_status: 0
@doc false
def run(%SourceFile{ast: ast, lines: lines} = source_file, params \\ []) do
def run(source_file, params \\ []) do
lines = SourceFile.lines(source_file)
# IssueMeta helps us pass down both the source_file and params of a check
# run to the lower levels where issues are created, formatted and returned
issue_meta = IssueMeta.for(source_file, params)
@@ -10,9 +10,10 @@ defmodule Credo do
[
worker(Credo.CLI.Output.Shell, []),
worker(Credo.Service.Commands, []),
worker(Credo.Service.SourceFileWithoutStringAndSigils, []),
worker(Credo.Service.SourceFileCodeOnly, []),
worker(Credo.Service.SourceFileScopes, []),
worker(Credo.Service.SourceFileAST, []),
worker(Credo.Service.SourceFileLines, []),
worker(Credo.Service.SourceFileSource, []),
]
opts = [strategy: :one_for_one, name: Credo.Supervisor]
@@ -95,11 +95,14 @@ defmodule Credo.Check.CodeHelper do
{:defmodule, "Foo.Bar"}
]
"""
def scope_list(%SourceFile{filename: filename, ast: ast, lines: lines}) do
def scope_list(%SourceFile{filename: filename} = source_file) do
case SourceFileScopes.get(filename) do
{:ok, value} ->
value
:notfound ->
ast = SourceFile.ast(source_file)
lines = SourceFile.lines(source_file)
result =
Enum.map(lines, fn({line_no, _}) ->
Scope.name(ast, line: line_no)
@@ -125,8 +128,10 @@ defmodule Credo.Check.CodeHelper do
Takes a SourceFile and returns its source code stripped of all Strings, Sigils
and code comments.
"""
def clean_charlists_strings_sigils_and_comments(%SourceFile{filename: filename, source: source}) do
clean_charlists_strings_sigils_and_comments(source)
def clean_charlists_strings_sigils_and_comments(%SourceFile{filename: filename} = source_file) do
source_file
|> SourceFile.source
|> clean_charlists_strings_sigils_and_comments
end
def clean_charlists_strings_sigils_and_comments(source) do
source
@@ -140,8 +145,10 @@ defmodule Credo.Check.CodeHelper do
Takes a SourceFile and returns its source code stripped of all Strings and
Sigils.
"""
def clean_charlists_strings_and_sigils(%SourceFile{filename: filename, source: source}) do
clean_charlists_strings_and_sigils(source)
def clean_charlists_strings_and_sigils(%SourceFile{filename: filename} = source_file) do
source_file
|> SourceFile.source
|> clean_charlists_strings_and_sigils
end
def clean_charlists_strings_and_sigils(source) do
source
@@ -72,14 +72,14 @@ defmodule Credo.Check.Consistency.ExceptionNames do
end
end
defp find_exception_modules_without_suffix(%SourceFile{ast: ast}, suffix) do
ast
defp find_exception_modules_without_suffix(%SourceFile{} = source_file, suffix) do
source_file
|> Credo.Code.prewalk(&find_exception_modules(&1, &2))
|> Enum.reject(&name_with_suffix?(&1, suffix))
end
defp find_exception_modules_without_prefix(%SourceFile{ast: ast}, prefix) do
ast
defp find_exception_modules_without_prefix(%SourceFile{} = source_file, prefix) do
source_file
|> Credo.Code.prewalk(&find_exception_modules(&1, &2))
|> Enum.reject(&name_with_prefix?(&1, prefix))
end
@@ -7,8 +7,8 @@ defmodule Credo.Check.Consistency.ExceptionNames.PrefixAndSuffixCollector do
def property_value, do: nil
def property_value_for(%SourceFile{ast: ast, filename: filename}, _params) do
Credo.Code.prewalk(ast, &traverse(&1, &2, filename))
def property_value_for(%SourceFile{filename: filename} = source_file, _params) do
Credo.Code.prewalk(source_file, &traverse(&1, &2, filename))
end
defp traverse({:defmodule, _meta, [{:__aliases__, _, _name_arr}, _arguments]} = ast, property_values, filename) do
@@ -3,7 +3,9 @@ defmodule Credo.Check.Consistency.LineEndings.Unix do
def property_value, do: :unix
def property_value_for(%SourceFile{lines: lines, filename: filename}, _params) do
def property_value_for(%SourceFile{filename: filename} = source_file, _params) do
lines = SourceFile.lines(source_file)
Enum.map(lines, &property_value_for_line(&1, filename))
end
@@ -3,7 +3,9 @@ defmodule Credo.Check.Consistency.LineEndings.Windows do
def property_value, do: :windows
def property_value_for(%SourceFile{lines: lines, filename: filename}, _params) do
def property_value_for(%SourceFile{filename: filename} = source_file, _params) do
lines = SourceFile.lines(source_file)
Enum.map(lines, &property_value_for_line(&1, filename))
end
@@ -5,13 +5,14 @@ defmodule Credo.Check.Consistency.MultiAliasImportRequireUse.Multi do
def property_value, do: :multi_alias_import_require_use
def property_value_for(%SourceFile{ast: ast, filename: filename}, _params) do
ast
def property_value_for(%SourceFile{filename: filename} = source_file, _params) do
source_file
|> SourceFile.ast
|> ReuseOpHelper.multi_names
|> Enum.map(&(property_value_for_namespace(&1, filename)))
end
defp property_value_for_namespace(%{names: names, line_no: line_no, reuse_op: reuse_op}, filename) do
PropertyValue.for(property_value(), %{line_no: line_no, filename: filename, names: names, reuse_op: reuse_op})
end
end
end
@@ -5,8 +5,9 @@ defmodule Credo.Check.Consistency.MultiAliasImportRequireUse.Single do
def property_value, do: :single_alias_import_require_use
def property_value_for(%SourceFile{ast: ast, filename: filename}, _params) do
ast
def property_value_for(%SourceFile{filename: filename} = source_file, _params) do
source_file
|> SourceFile.ast
|> ReuseOpHelper.multiple_single_names
|> Enum.map(fn ns -> property_value_for_namespace(ns, filename) end)
end
@@ -18,4 +19,4 @@ defmodule Credo.Check.Consistency.MultiAliasImportRequireUse.Single do
|> Enum.max
PropertyValue.for(property_value(), %{line_no: line_no, reuse_op: reuse_op, filename: filename, namespace: namespace})
end
end
end
@@ -5,8 +5,8 @@ defmodule Credo.Check.Consistency.ParameterPatternMatching.PositionCollector do
def property_value, do: nil
def property_value_for(%SourceFile{ast: ast, filename: filename}, _params) do
Credo.Code.prewalk(ast, &traverse(&1, &2, filename))
def property_value_for(%SourceFile{filename: filename} = source_file, _params) do
Credo.Code.prewalk(source_file, &traverse(&1, &2, filename))
end
defp traverse({:defmodule, _meta, [{:__aliases__, _, _name_arr}, _arguments]} = ast, property_values, filename) do
@@ -6,11 +6,11 @@ defmodule Credo.Check.Consistency.SpaceAroundOperators.WithSpace do
def property_value, do: :with_space
def property_value_for(source_file, _params) do
property_values_for(source_file.source, source_file.filename)
property_values_for(source_file, source_file.filename)
end
defp property_values_for(source, filename) do
source
defp property_values_for(source_file, filename) do
source_file
|> Credo.Code.to_tokens
|> check_tokens([])
|> Enum.uniq
@@ -10,7 +10,7 @@ defmodule Credo.Check.Consistency.SpaceAroundOperators.WithoutSpace do
end
defp property_values_for(source_file) do
source_file.source
source_file
|> Credo.Code.to_tokens
|> check_tokens([])
|> Enum.uniq
@@ -3,7 +3,9 @@ defmodule Credo.Check.Consistency.TabsOrSpaces.Spaces do
def property_value, do: :spaces
def property_value_for(%SourceFile{lines: lines, filename: filename}, _params) do
def property_value_for(%SourceFile{filename: filename} = source_file, _params) do
lines = SourceFile.lines(source_file)
Enum.map(lines, &property_value_for_line(&1, filename))
end
@@ -3,7 +3,9 @@ defmodule Credo.Check.Consistency.TabsOrSpaces.Tabs do
def property_value, do: :tabs
def property_value_for(%SourceFile{lines: lines, filename: filename}, _params) do
def property_value_for(%SourceFile{filename: filename} = source_file, _params) do
lines = SourceFile.lines(source_file)
Enum.map(lines, &property_value_for_line(&1, filename))
end
@@ -53,18 +53,19 @@ defmodule Credo.Check.Design.AliasUsage do
use Credo.Check, base_priority: :normal
@doc false
def run(%SourceFile{ast: ast} = source_file, params \\ []) do
def run(source_file, params \\ []) do
issue_meta = IssueMeta.for(source_file, params)
excluded_namespaces = Params.get(params, :excluded_namespaces, @default_params)
excluded_lastnames = Params.get(params, :excluded_lastnames, @default_params)
Credo.Code.prewalk(ast, &traverse(&1, &2, issue_meta, excluded_namespaces, excluded_lastnames))
Credo.Code.prewalk(source_file, &traverse(&1, &2, issue_meta, excluded_namespaces, excluded_lastnames))
end
defp traverse({:defmodule, _, _} = ast, issues, issue_meta, excluded_namespaces, excluded_lastnames) do
aliases = Credo.Code.Module.aliases(ast)
mod_deps = Credo.Code.Module.modules(ast)
new_issues = Credo.Code.prewalk(ast, &find_issues(&1, &2, issue_meta, excluded_namespaces, excluded_lastnames, aliases, mod_deps))
{ast, issues ++ new_issues}
end
defp traverse(ast, issues, _source_file, _excluded_namespaces, _excluded_lastnames) do
@@ -91,6 +92,7 @@ defmodule Credo.Check.Design.AliasUsage do
{ast, issues}
true ->
trigger = Enum.join(mod_list, ".")
{ast, issues ++ [issue_for(issue_meta, meta[:line], trigger)]}
end
end
@@ -71,7 +71,9 @@ defmodule Credo.Check.Design.DuplicatedCode do
defp duplicate_nodes(source_files, mass_threshold) do
source_files
|> Enum.reduce(%{}, fn(source_file, acc) ->
calculate_hashes(source_file.ast, acc, source_file.filename, mass_threshold)
ast = SourceFile.ast(source_file)
calculate_hashes(ast, acc, source_file.filename, mass_threshold)
end)
|> prune_hashes
|> add_masses
@@ -24,10 +24,11 @@ defmodule Credo.Check.Design.TagFIXME do
use Credo.Check, base_priority: :high
@doc false
def run(%SourceFile{source: source} = source_file, params \\ []) do
def run(source_file, params \\ []) do
issue_meta = IssueMeta.for(source_file, params)
source
source_file
|> SourceFile.source
|> TagHelper.tags(@tag_name)
|> Enum.map(&issue_for(issue_meta, &1))
end
@@ -24,7 +24,8 @@ defmodule Credo.Check.Design.TagTODO do
use Credo.Check
@doc false
def run(%SourceFile{source: source} = source_file, params \\ []) do
def run(source_file, params \\ []) do
source = SourceFile.source(source_file)
issue_meta = IssueMeta.for(source_file, params)
source
@@ -30,7 +30,7 @@ defmodule Credo.Check.Readability.LargeNumbers do
issue_meta = IssueMeta.for(source_file, params)
min_number = Params.get(params, :only_greater_than, @default_params)
source_file.source
source_file
|> Credo.Code.to_tokens
|> collect_number_tokens([], min_number)
|> find_issues([], issue_meta)
@@ -26,16 +26,17 @@ defmodule Credo.Check.Readability.MaxLineLength do
use Credo.Check, base_priority: :low
@doc false
def run(%SourceFile{ast: ast, source: source} = source_file, params \\ []) do
def run(source_file, params \\ []) do
issue_meta = IssueMeta.for(source_file, params)
max_length = Params.get(params, :max_length, @default_params)
ignore_definitions = Params.get(params, :ignore_definitions, @default_params)
ignore_specs = Params.get(params, :ignore_specs, @default_params)
ignore_strings = Params.get(params, :ignore_strings, @default_params)
definitions = Credo.Code.prewalk(ast, &find_definitions/2)
specs = Credo.Code.prewalk(ast, &find_specs/2)
definitions = Credo.Code.prewalk(source_file, &find_definitions/2)
specs = Credo.Code.prewalk(source_file, &find_specs/2)
source = SourceFile.source(source_file)
source =
if ignore_strings do
Credo.Code.Strings.replace_with_spaces(source, "")
@@ -53,14 +53,14 @@ defmodule Credo.Check.Readability.ModuleDoc do
use Credo.Check
@doc false
def run(%SourceFile{ast: ast, filename: filename} = source_file, params \\ []) do
def run(%SourceFile{filename: filename} = source_file, params \\ []) do
if Path.extname(filename) == ".exs" do
[]
else
issue_meta = IssueMeta.for(source_file, params)
ignore_names = Params.get(params, :ignore_names, @default_params)
{_continue, issues} = Credo.Code.prewalk(ast, &traverse(&1, &2, issue_meta, ignore_names), {true, []})
{_continue, issues} = Credo.Code.prewalk(source_file, &traverse(&1, &2, issue_meta, ignore_names), {true, []})
issues
end
@@ -28,7 +28,7 @@ defmodule Credo.Check.Readability.ParenthesesInCondition do
def run(source_file, params \\ []) do
issue_meta = IssueMeta.for(source_file, params)
source_file.source
source_file
|> Credo.Code.to_tokens
|> collect_parenthetical_tokens([], nil)
|> find_issues([], issue_meta)
@@ -25,7 +25,7 @@ defmodule Credo.Check.Readability.ParenthesesOnZeroArityDefs do
use Credo.Check, base_priority: :low
@doc false
def run(%SourceFile{} = source_file, params \\ []) do
def run(source_file, params \\ []) do
issue_meta = IssueMeta.for(source_file, params)
Credo.Code.prewalk(source_file, &traverse(&1, &2, issue_meta))
@@ -33,7 +33,7 @@ defmodule Credo.Check.Readability.PredicateFunctionNames do
use Credo.Check, base_priority: :high
@doc false
def run(%SourceFile{} = source_file, params \\ []) do
def run(source_file, params \\ []) do
issue_meta = IssueMeta.for(source_file, params)
Credo.Code.prewalk(source_file, &traverse(&1, &2, issue_meta))
@@ -32,7 +32,7 @@ defmodule Credo.Check.Readability.PreferImplicitTry do
use Credo.Check, base_priority: :low
@doc false
def run(%SourceFile{} = source_file, params \\ []) do
def run(source_file, params \\ []) do
issue_meta = IssueMeta.for(source_file, params)
Credo.Code.prewalk(source_file, &traverse(&1, &2, issue_meta))
@@ -20,12 +20,13 @@ defmodule Credo.Check.Readability.RedundantBlankLines do
use Credo.Check, base_priority: :low
@doc false
def run(%SourceFile{lines: lines} = source_file, params \\ []) do
def run(source_file, params \\ []) do
issue_meta = IssueMeta.for(source_file, params)
max_blank_lines = Params.get(params, :max_blank_lines, @default_params)
lines
source_file
|> SourceFile.lines
|> blank_lines
|> consecutive_lines(max_blank_lines)
|> Enum.map(fn line -> issue_for(issue_meta, line, max_blank_lines) end)
@@ -18,7 +18,7 @@ defmodule Credo.Check.Readability.Semicolons do
def run(source_file, params \\ []) do
issue_meta = IssueMeta.for(source_file, params)
source_file.source
source_file
|> Credo.Code.to_tokens
|> collect_issues([], issue_meta)
end
@@ -27,11 +27,11 @@ defmodule Credo.Check.Readability.SinglePipe do
use Credo.Check, base_priority: :high
@doc false
def run(%SourceFile{ast: ast} = source_file, params \\ []) do
def run(source_file, params \\ []) do
issue_meta = IssueMeta.for(source_file, params)
{_continue, issues} =
Credo.Code.prewalk(ast, &traverse(&1, &2, issue_meta), {true, []})
Credo.Code.prewalk(source_file, &traverse(&1, &2, issue_meta), {true, []})
issues
end
Oops, something went wrong.

0 comments on commit c717c66

Please sign in to comment.