Merge pull request #73 from ferd/various-fixes

Various fixes
diff --git a/.travis.yml b/.travis.yml
index 715a9e0..47900b0 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,6 +1,7 @@
 sudo: false
 language: erlang
 otp_release:
+  - 22.0
   - 21.0
   - 20.0
   - 19.3
diff --git a/README.md b/README.md
index 5463862..5a11f73 100644
--- a/README.md
+++ b/README.md
@@ -27,6 +27,9 @@
 
 *2.x*
 
+- 2.5.0
+  - Optional formatting of records in traces (thanks to @bartekgorny)
+  - Basic support for OTP-22 in `recon_alloc` (base handling of `foreign_blocks` type)
 - 2.4.0
   - Optional formatting of records in traces (thanks to @bartekgorny)
 - 2.3.6
diff --git a/mix.exs b/mix.exs
index 836cb60..0580395 100644
--- a/mix.exs
+++ b/mix.exs
@@ -5,7 +5,7 @@
     [
       app: :recon,
       description: "Diagnostic tools for production use",
-      version: "2.4.0",
+      version: "2.5.0",
       language: :erlang,
       deps: []
     ]
diff --git a/src/recon.app.src b/src/recon.app.src
index c7cea40..38a2e91 100644
--- a/src/recon.app.src
+++ b/src/recon.app.src
@@ -1,6 +1,6 @@
 {application, recon,
  [{description, "Diagnostic tools for production use"},
-  {vsn, "2.4.0"},
+  {vsn, "2.5.0"},
   {modules, [recon, recon_alloc, recon_lib, recon_trace, recon_rec]},
   {registered, []},
   {applications, [kernel, stdlib]},
diff --git a/src/recon_alloc.erl b/src/recon_alloc.erl
index 7c2d029..a89354d 100644
--- a/src/recon_alloc.erl
+++ b/src/recon_alloc.erl
@@ -420,6 +420,9 @@
                    %% value is very rarely important so leave it
                    %% like this for now.
                    {K, lists:max([V1,V2])};
+              ({{K,V1}, {K,V2}}) when K =:= foreign_blocks ->
+                   %% foreign blocks are just merged as a bigger list.
+                   {K, V1++V2};
               ({{K,V1}, {K,V2}}) ->
                    {K, V1 + V2};
               ({{K,C1,L1,M1}, {K,C2,L2,M2}}) ->
diff --git a/src/recon_map.erl b/src/recon_map.erl
index 29bfb80..f80e587 100644
--- a/src/recon_map.erl
+++ b/src/recon_map.erl
@@ -13,12 +13,8 @@
 -author("bartlomiej.gorny@erlang-solutions.com").
 %% API
 
--export([limit/3]).
--export([list/0]).
+-export([limit/3, list/0, is_active/0, clear/0, remove/1, rename/2]).
 -export([process_map/1]).
--export([is_active/0]).
--export([clear/0]).
--export([remove/1, rename/2]).
 
 -type map_label() :: atom().
 -type pattern() :: map() | function().
@@ -52,26 +48,38 @@
 limit(Label, Pattern, Limit) when is_atom(Label), is_function(Pattern) ->
     store_pattern(Label, Pattern, Limit).
 
+%% @doc prints out all "known" map definitions and their limit settings.
+%% Printout tells a map's name, the matching fields required, and the limit options.
+%% @end
 list() ->
     ensure_table_exists(),
     io:format("~nmap definitions and limits:~n"),
-    list(lists:sort(ets:tab2list(patterns_table_name()))).
+    list(ets:tab2list(patterns_table_name())).
 
+%% @doc remove a given map entry
+-spec remove(map_label()) -> true.
 remove(Label) ->
     ensure_table_exists(),
     ets:delete(patterns_table_name(), Label).
 
+%% @doc rename a given map entry, which allows to to change priorities for
+%% matching. The first argument is the current name, and the second
+%% argument is the new name.
+-spec rename(map_label(), map_label()) -> renamed | missing.
 rename(Name, NewName) ->
     ensure_table_exists(),
     case ets:lookup(patterns_table_name(), Name) of
         [{Name, Pattern, Limit}] ->
-            ets:delete(patterns_table_name(), Name),
             ets:insert(patterns_table_name(), {NewName, Pattern, Limit}),
+            ets:delete(patterns_table_name(), Name),
             renamed;
         [] ->
             missing
     end.
 
+%% @doc prints out all "known" map filter definitions and their settings.
+%% Printout tells the map's label, the matching patterns, and the limit options
+%% @end
 list([]) ->
     io:format("~n"),
     ok;
@@ -79,7 +87,7 @@
     io:format("~p: ~p -> ~p~n", [Label, Pattern, Limit]),
     list(Rest).
 
-%% @doc given a map, scans saved patterns for one that matches; if found, returns a label
+%% @private given a map, scans saved patterns for one that matches; if found, returns a label
 %% and a map with limits applied; otherwise returns 'none' and original map.
 %% Pattern can be:
 %% <ul>
diff --git a/src/recon_rec.erl b/src/recon_rec.erl
index 23c4098..3689df1 100644
--- a/src/recon_rec.erl
+++ b/src/recon_rec.erl
@@ -15,8 +15,8 @@
 %% API
 
 -export([is_active/0]).
--export([import/1, format_tuple/1, clear/1, clear/0, list/0, get_list/0, limit/3]).
--export([ensure_table_exists/0]).
+-export([import/1, clear/1, clear/0, list/0, get_list/0, limit/3]).
+-export([format_tuple/1]).
 
 -ifdef(TEST).
 -export([lookup_record/2]).
@@ -63,7 +63,7 @@
     ok.
 
 %% @doc prints out all "known" (imported) record definitions and their limit settings.
-%% Print out tells module a record originates from, its name and a list of field names,
+%% Printout tells module a record originates from, its name and a list of field names,
 %% plus the record's arity (may be handy if handling big records) and a list of field it
 %% limits its output to, if set.
 %% @end
@@ -151,6 +151,7 @@
     ensure_table_exists(),
     ets:lookup(records_table_name(), {RecName, FieldCount}).
 
+%% @private
 ensure_table_exists() ->
     case ets:info(records_table_name()) of
         undefined ->
@@ -234,6 +235,7 @@
     end.
 
 format_kv(Key, Val) ->
+    %% Some messy mutually recursive calls we can't avoid
     [recon_trace:format_trace_output(true, Key), "=", recon_trace:format_trace_output(true, Val)].
 
 apply_limits(List, none) -> List;
diff --git a/src/recon_trace.erl b/src/recon_trace.erl
index 27e30e4..cfad519 100644
--- a/src/recon_trace.erl
+++ b/src/recon_trace.erl
@@ -620,19 +620,15 @@
     format_trace_output(Recs, recon_map:is_active(), Args).
 
 format_trace_output(true, _, Args) when is_tuple(Args) ->
-    case sets:is_set(Args) of
-        true ->
-            ["set:", format_trace_output(true, sets:to_list(Args))];
-        false ->
-            recon_rec:format_tuple(Args)
-    end;
-format_trace_output(true, Maps, Args) when is_list(Args) ->
+    recon_rec:format_tuple(Args);
+format_trace_output(false, true, Args) when is_tuple(Args) ->
+    format_tuple(false, true, Args);
+format_trace_output(Recs, Maps, Args) when is_list(Args), Recs orelse Maps ->
     case io_lib:printable_list(Args) of
         true ->
             io_lib:format("~p", [Args]);
         false ->
-            L = lists:map(fun(A) -> format_trace_output(true, Maps, A) end, Args),
-            [$[, join(", ", L), $]]
+            format_maybe_improper_list(Recs, Maps, Args)
     end;
 format_trace_output(Recs, true, Args) when is_map(Args) ->
     {Label, Map} = case recon_map:process_map(Args) of
@@ -655,6 +651,33 @@
 format_kv(Recs, Maps, Key, Val) ->
     [format_trace_output(Recs, Maps, Key), "=>", format_trace_output(Recs, Maps, Val)].
 
+
+format_tuple(Recs, Maps, Tup) ->
+    [${ | format_tuple_(Recs, Maps, tuple_to_list(Tup))].
+
+format_tuple_(_Recs, _Maps, []) ->
+    "}";
+format_tuple_(Recs, Maps, [H|T]) ->
+    [format_trace_output(Recs, Maps, H), $,,
+     format_tuple_(Recs, Maps, T)].
+
+
+format_maybe_improper_list(Recs, Maps, List) ->
+    [$[ | format_maybe_improper_list_(Recs, Maps, List)].
+
+format_maybe_improper_list_(_, _, []) ->
+    "]";
+format_maybe_improper_list_(Recs, Maps, [H|[]]) ->
+    [format_trace_output(Recs, Maps, H), $]];
+format_maybe_improper_list_(Recs, Maps, [H|T]) when is_list(T) ->
+    [format_trace_output(Recs, Maps, H), $,,
+     format_maybe_improper_list_(Recs, Maps, T)];
+format_maybe_improper_list_(Recs, Maps, [H|T]) when not is_list(T) ->
+    %% Handling improper lists
+    [format_trace_output(Recs, Maps, H), $|,
+     format_trace_output(Recs, Maps, T), $]].
+
+
 %%%%%%%%%%%%%%%
 %%% HELPERS %%%
 %%%%%%%%%%%%%%%
@@ -695,6 +718,7 @@
             exit(shell_funs_only)
     end.
 
+
 -ifdef(OTP_RELEASE).
 -spec join(term(), [term()]) -> [term()].
 join(Sep, List) ->
diff --git a/test/recon_SUITE.erl b/test/recon_SUITE.erl
index 6cf63fb..dbb4d86 100644
--- a/test/recon_SUITE.erl
+++ b/test/recon_SUITE.erl
@@ -66,7 +66,7 @@
 
 info4(Config) ->
     Pid = ?config(pid, Config),
-    Keys = [meta, signals, location, memory_used, work,
+    Keys = [meta, signals, location, memory_used,
             links, monitors, messages,
             [links, monitors, messages]],
     {A,B,C} = pid_to_triple(Pid),