GCOV: introduce --json-format.
authorMartin Liska <mliska@suse.cz>
Mon, 29 Oct 2018 12:00:54 +0000 (13:00 +0100)
committerMartin Liska <marxin@gcc.gnu.org>
Mon, 29 Oct 2018 12:00:54 +0000 (12:00 +0000)
2018-10-29  Martin Liska  <mliska@suse.cz>

* Makefile.in: Make dependency to json.o.
* doc/gcov.texi: Document new JSON format, remove
old intermediate format documentation.
* gcov.c (struct function_info): Come up with m_name and
m_demangled_name.
(function_info::function_info): Initialize it.
(function_info::~function_info): Release it.
(main): Rename flag_intermediate_format to flag_json_format.
(print_usage): Describe --json-format.
(process_args): Set flag_json_format.
(output_intermediate_line): Remove.
(output_intermediate_json_line): Likewise.
(get_gcov_intermediate_filename): Return new extension
".gcov.json.gz".
(output_intermediate_file): Implement JSON emission.
(output_json_intermediate_file): Implement JSON emission.
(generate_results): Use ::get_name for function name.
Handle JSON output file.
(read_graph_file): Use ::get_name instead of cplus_demangle.
(read_count_file): Likewise.
(solve_flow_graph): Likewise.
(add_line_counts): Likewise.
(accumulate_line_counts): Use new flag_json_format.
(output_function_details): Use ::get_name instead of cplus_demangle.
(output_lines): Likewise.
* json.cc (test_writing_literals): Add new tests.
* json.h (class literal): Add new boolean constructor.
2018-10-29  Martin Liska  <mliska@suse.cz>

* g++.dg/gcov/gcov-8.C: Do not check intermediate format.
* lib/gcov.exp: Remove legacy verify-intermediate.

From-SVN: r265587

gcc/ChangeLog
gcc/Makefile.in
gcc/doc/gcov.texi
gcc/gcov.c
gcc/json.cc
gcc/json.h
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/gcov/gcov-8.C
gcc/testsuite/lib/gcov.exp

index 0dd2c511fe26b1264fcc4103ba539e7d965665c7..165ae049dba28858585a2353f69aa9f93914cfe0 100644 (file)
@@ -1,3 +1,33 @@
+2018-10-29  Martin Liska  <mliska@suse.cz>
+
+       * Makefile.in: Make dependency to json.o.
+       * doc/gcov.texi: Document new JSON format, remove
+       old intermediate format documentation.
+       * gcov.c (struct function_info): Come up with m_name and
+       m_demangled_name.
+       (function_info::function_info): Initialize it.
+       (function_info::~function_info): Release it.
+       (main): Rename flag_intermediate_format to flag_json_format.
+       (print_usage): Describe --json-format.
+       (process_args): Set flag_json_format.
+       (output_intermediate_line): Remove.
+       (output_intermediate_json_line): Likewise.
+       (get_gcov_intermediate_filename): Return new extension
+       ".gcov.json.gz".
+       (output_intermediate_file): Implement JSON emission.
+       (output_json_intermediate_file): Implement JSON emission.
+       (generate_results): Use ::get_name for function name.
+       Handle JSON output file.
+       (read_graph_file): Use ::get_name instead of cplus_demangle.
+       (read_count_file): Likewise.
+       (solve_flow_graph): Likewise.
+       (add_line_counts): Likewise.
+       (accumulate_line_counts): Use new flag_json_format.
+       (output_function_details): Use ::get_name instead of cplus_demangle.
+       (output_lines): Likewise.
+       * json.cc (test_writing_literals): Add new tests.
+       * json.h (class literal): Add new boolean constructor.
+
 2018-10-29  Segher Boessenkool  <segher@kernel.crashing.org>
 
        PR rtl-optimization/87701
index a164332140831e9b5a2845eb63e95983453768e7..719a516c356d21a285aa4f65fb6ca7608e19481a 100644 (file)
@@ -2899,10 +2899,13 @@ s-iov: build/gcov-iov$(build_exeext) $(BASEVER) $(DEVPHASE)
        $(SHELL) $(srcdir)/../move-if-change tmp-gcov-iov.h gcov-iov.h
        $(STAMP) s-iov
 
-GCOV_OBJS = gcov.o
+# gcov.o needs $(ZLIBINC) added to the include flags.
+CFLAGS-gcov.o += $(ZLIBINC)
+
+GCOV_OBJS = gcov.o json.o
 gcov$(exeext): $(GCOV_OBJS) $(LIBDEPS)
        +$(LINKER) $(ALL_LINKERFLAGS) $(LDFLAGS) $(GCOV_OBJS) \
-               hash-table.o ggc-none.o $(LIBS) -o $@
+               hash-table.o ggc-none.o $(LIBS) $(ZLIB) -o $@
 GCOV_DUMP_OBJS = gcov-dump.o
 gcov-dump$(exeext): $(GCOV_DUMP_OBJS) $(LIBDEPS)
        +$(LINKER) $(ALL_LINKERFLAGS) $(LDFLAGS) $(GCOV_DUMP_OBJS) \
index 3b1b38aebfa2bf93ba22832a2593b16e24c34c97..8046fd78e358371a4f1d4b8fd67cf450b2f1554e 100644 (file)
@@ -124,7 +124,7 @@ gcov [@option{-v}|@option{--version}] [@option{-h}|@option{--help}]
      [@option{-c}|@option{--branch-counts}]
      [@option{-d}|@option{--display-progress}]
      [@option{-f}|@option{--function-summaries}]
-     [@option{-i}|@option{--intermediate-format}]
+     [@option{-i}|@option{--json-format}]
      [@option{-j}|@option{--human-readable}]
      [@option{-k}|@option{--use-colors}]
      [@option{-l}|@option{--long-file-names}]
@@ -181,79 +181,142 @@ Display help about using @command{gcov} (on the standard output), and
 exit without doing any further processing.
 
 @item -i
-@itemx --intermediate-format
-Output gcov file in an easy-to-parse intermediate text format that can
-be used by @command{lcov} or other tools. The output is a single
-@file{.gcov} file per @file{.gcda} file. No source code is required.
+@itemx --json-format
+Output gcov file in an easy-to-parse JSON intermediate format
+which does not require source code for generation.  The JSON
+file is compressed with gzip compression algorithm
+and the files have @file{.gcov.json.gz} extension.
 
-The format of the intermediate @file{.gcov} file is plain text with
-one entry per line
+Structure of the JSON is following:
 
 @smallexample
-version:@var{gcc_version}
-cwd:@var{working_directory}
-file:@var{source_file_name}
-function:@var{start_line_number},@var{end_line_number},@var{execution_count},@var{function_name}
-lcount:@var{line number},@var{execution_count},@var{has_unexecuted_block}
-branch:@var{line_number},@var{branch_coverage_type}
-
-Where the @var{branch_coverage_type} is
-   notexec (Branch not executed)
-   taken (Branch executed and taken)
-   nottaken (Branch executed, but not taken)
+@{
+  "current_working_directory": @var{current_working_directory},
+  "format_version": @var{format_version},
+  "gcc_version": @var{gcc_version}
+  "files": [@var{file}]
+@}
 @end smallexample
 
-There can be multiple @var{file} entries in an intermediate gcov
-file. All entries following a @var{file} pertain to that source file
-until the next @var{file} entry.  If there are multiple functions that
-start on a single line, then corresponding lcount is repeated multiple
-times.
+Fields of the root element have following semantics:
 
-Here is a sample when @option{-i} is used in conjunction with @option{-b} option:
+@itemize @bullet
+@item
+@var{current_working_directory}: working directory where
+a compilation unit was compiled
+
+@item
+@var{format_version}: semantic version of the format
+
+@item
+@var{gcc_version}: version of the GCC compiler
+@end itemize
+
+Each @var{file} has the following form:
+
+@smallexample
+@{
+  "file": @var{file_name},
+  "functions": [@var{function}],
+  "lines": [@var{line}]
+@}
+@end smallexample
+
+Fields of the @var{file} element have following semantics:
+
+@itemize @bullet
+@item
+@var{file_name}: name of the source file
+@end itemize
+
+Each @var{function} has the following form:
+
+@smallexample
+@{
+  "blocks": @var{blocks},
+  "blocks_executed": @var{blocks_executed},
+  "demangled_name": "@var{demangled_name},
+  "end_line": @var{end_line},
+  "execution_count": @var{execution_count},
+  "name": @var{name},
+  "start_line": @var{start_line}
+@}
+@end smallexample
+
+Fields of the @var{function} element have following semantics:
+
+@itemize @bullet
+@item
+@var{blocks}: number of blocks that are in the function
+
+@item
+@var{blocks_executed}: number of executed blocks of the function
+
+@item
+@var{demangled_name}: demangled name of the function
+
+@item
+@var{end_line}: line in the source file where the function ends
+
+@item
+@var{execution_count}: number of executions of the function
+
+@item
+@var{name}: name of the function
+
+@item
+@var{start_line}: line in the source file where the function begins
+@end itemize
+
+Each @var{line} has the following form:
+
+@smallexample
+@{
+  "branches": [@var{branch}],
+  "count": @var{count},
+  "line_number": @var{line_number},
+  "unexecuted_block": @var{unexecuted_block}
+@}
+@end smallexample
+
+Branches are present only with @var{-b} option.
+Fields of the @var{line} element have following semantics:
+
+@itemize @bullet
+@item
+@var{count}: number of executions of the line
+
+@item
+@var{line_number}: line number
+
+@item
+@var{unexecuted_block}: flag whether the line contains an unexecuted block
+(not all statements on the line are executed)
+@end itemize
+
+Each @var{branch} has the following form:
 
 @smallexample
-version: 8.1.0 20180103
-cwd:/home/gcc/testcase
-file:tmp.cpp
-function:7,7,0,_ZN3FooIcEC2Ev
-function:7,7,1,_ZN3FooIiEC2Ev
-function:8,8,0,_ZN3FooIcE3incEv
-function:8,8,2,_ZN3FooIiE3incEv
-function:18,37,1,main
-lcount:7,0,1
-lcount:7,1,0
-lcount:8,0,1
-lcount:8,2,0
-lcount:18,1,0
-lcount:21,1,0
-branch:21,taken
-branch:21,nottaken
-lcount:23,1,0
-branch:23,taken
-branch:23,nottaken
-lcount:24,1,0
-branch:24,taken
-branch:24,nottaken
-lcount:25,1,0
-lcount:27,11,0
-branch:27,taken
-branch:27,taken
-lcount:28,10,0
-lcount:30,1,1
-branch:30,nottaken
-branch:30,taken
-lcount:32,1,0
-branch:32,nottaken
-branch:32,taken
-lcount:33,0,1
-branch:33,notexec
-branch:33,notexec
-lcount:35,1,0
-branch:35,taken
-branch:35,nottaken
-lcount:36,1,0
+@{
+  "count": @var{count},
+  "fallthrough": @var{fallthrough},
+  "throw": @var{throw}
+@}
 @end smallexample
 
+Fields of the @var{branch} element have following semantics:
+
+@itemize @bullet
+@item
+@var{count}: number of executions of the branch
+
+@item
+@var{fallthrough}: true when the branch is a fall through branch
+
+@item
+@var{throw}: true when the branch is an exceptional branch
+@end itemize
+
 @item -j
 @itemx --human-readable
 Write counts in human readable format (like 24.6k).
@@ -842,7 +905,7 @@ some summary information.
 
 It is not recommended to access the coverage files directly.
 Consumers should use the intermediate format that is provided
-by @command{gcov} tool via @option{--intermediate-format} option.
+by @command{gcov} tool via @option{--json-format} option.
 
 @node Cross-profiling
 @section Data File Relocation to Support Cross-Profiling
index e255e4e3922defa3fb1a0476067b8dacde2d872a..26d352ce7f123ab98da8d3e40914eefad666c1e9 100644 (file)
@@ -44,7 +44,10 @@ along with Gcov; see the file COPYING3.  If not see
 #include "version.h"
 #include "demangle.h"
 #include "color-macros.h"
+#include "pretty-print.h"
+#include "json.h"
 
+#include <zlib.h>
 #include <getopt.h>
 
 #include "md5.h"
@@ -221,6 +224,10 @@ line_info::has_block (block_info *needle)
   return std::find (blocks.begin (), blocks.end (), needle) != blocks.end ();
 }
 
+/* Output demangled function names.  */
+
+static int flag_demangled_names = 0;
+
 /* Describes a single function. Contains an array of basic blocks.  */
 
 struct function_info
@@ -241,8 +248,8 @@ struct function_info
   }
 
   /* Name of function.  */
-  char *name;
-  char *demangled_name;
+  char *m_name;
+  char *m_demangled_name;
   unsigned ident;
   unsigned lineno_checksum;
   unsigned cfg_checksum;
@@ -284,6 +291,32 @@ struct function_info
 
   /* Next function.  */
   struct function_info *next;
+
+  /*  Get demangled name of a function.  The demangled name
+      is converted when it is used for the first time.  */
+  char *get_demangled_name ()
+  {
+    if (m_demangled_name == NULL)
+      {
+       m_demangled_name = cplus_demangle (m_name, DMGL_PARAMS);
+       if (!m_demangled_name)
+         m_demangled_name = m_name;
+      }
+
+    return m_demangled_name;
+  }
+
+  /* Get name of the function based on flag_demangled_names.  */
+  char *get_name ()
+  {
+    return flag_demangled_names ? get_demangled_name () : m_name;
+  }
+
+  /* Return number of basic blocks (without entry and exit block).  */
+  unsigned get_block_count ()
+  {
+    return blocks.size () - 2;
+  }
 };
 
 /* Function info comparer that will sort functions according to starting
@@ -477,13 +510,9 @@ static int flag_use_stdout = 0;
 
 static int flag_display_progress = 0;
 
-/* Output *.gcov file in intermediate format used by 'lcov'.  */
+/* Output *.gcov file in JSON intermediate format used by consumers.  */
 
-static int flag_intermediate_format = 0;
-
-/* Output demangled function names.  */
-
-static int flag_demangled_names = 0;
+static int flag_json_format = 0;
 
 /* For included files, make the gcov output file name include the name
    of the input source file.  For example, if x.h is included in a.c,
@@ -576,7 +605,7 @@ static char *mangle_name (const char *, char *);
 static void release_structures (void);
 extern int main (int, char **);
 
-function_info::function_info (): name (NULL), demangled_name (NULL),
+function_info::function_info (): m_name (NULL), m_demangled_name (NULL),
   ident (0), lineno_checksum (0), cfg_checksum (0), has_catch (0),
   artificial (0), is_group (0),
   blocks (), blocks_executed (0), counts (),
@@ -596,9 +625,9 @@ function_info::~function_info ()
          free (arc);
        }
     }
-  if (flag_demangled_names && demangled_name != name)
-    free (demangled_name);
-  free (name);
+  if (m_demangled_name != m_name)
+    free (m_demangled_name);
+  free (m_name);
 }
 
 bool function_info::group_line_p (unsigned n, unsigned src_idx)
@@ -807,7 +836,7 @@ main (int argc, char **argv)
                argc - first_arg);
       process_file (argv[argno]);
 
-      if (flag_intermediate_format || argno == argc - 1)
+      if (flag_json_format || argno == argc - 1)
        {
          process_all_functions ();
          generate_results (argv[argno]);
@@ -836,7 +865,7 @@ print_usage (int error_p)
   fnotice (file, "  -d, --display-progress          Display progress information\n");
   fnotice (file, "  -f, --function-summaries        Output summaries for each function\n");
   fnotice (file, "  -h, --help                      Print this help, then exit\n");
-  fnotice (file, "  -i, --intermediate-format       Output .gcov file in intermediate text format\n");
+  fnotice (file, "  -i, --json-format              Output JSON intermediate format into .gcov.json.gz file\n");
   fnotice (file, "  -j, --human-readable            Output human readable numbers\n");
   fnotice (file, "  -k, --use-colors                Emit colored output\n");
   fnotice (file, "  -l, --long-file-names           Use long output file names for included\n\
@@ -881,7 +910,7 @@ static const struct option options[] =
   { "all-blocks",           no_argument,       NULL, 'a' },
   { "branch-probabilities", no_argument,       NULL, 'b' },
   { "branch-counts",        no_argument,       NULL, 'c' },
-  { "intermediate-format",  no_argument,       NULL, 'i' },
+  { "json-format",         no_argument,       NULL, 'i' },
   { "human-readable",      no_argument,       NULL, 'j' },
   { "no-output",            no_argument,       NULL, 'n' },
   { "long-file-names",      no_argument,       NULL, 'l' },
@@ -963,12 +992,12 @@ process_args (int argc, char **argv)
          flag_unconditional = 1;
          break;
        case 'i':
-          flag_intermediate_format = 1;
-          flag_gcov_file = 1;
-          break;
-        case 'd':
-          flag_display_progress = 1;
-          break;
+         flag_json_format = 1;
+         flag_gcov_file = 1;
+         break;
+       case 'd':
+         flag_display_progress = 1;
+         break;
        case 'x':
          flag_hash_filenames = 1;
          break;
@@ -990,17 +1019,23 @@ process_args (int argc, char **argv)
   return optind;
 }
 
-/* Output intermediate LINE sitting on LINE_NUM to output file F.  */
+/* Output intermediate LINE sitting on LINE_NUM to JSON OBJECT.  */
 
 static void
-output_intermediate_line (FILE *f, line_info *line, unsigned line_num)
+output_intermediate_json_line (json::array *object,
+                              line_info *line, unsigned line_num)
 {
   if (!line->exists)
     return;
 
-  fprintf (f, "lcount:%u,%s,%d\n", line_num,
-          format_gcov (line->count, 0, -1),
-          line->has_unexecuted_block);
+  json::object *lineo = new json::object ();
+  lineo->set ("line_number", new json::number (line_num));
+  lineo->set ("count", new json::number (line->count));
+  lineo->set ("unexecuted_block",
+             new json::literal (line->has_unexecuted_block));
+
+  json::array *branches = new json::array ();
+  lineo->set ("branches", branches);
 
   vector<arc_info *>::const_iterator it;
   if (flag_branches)
@@ -1009,21 +1044,16 @@ output_intermediate_line (FILE *f, line_info *line, unsigned line_num)
       {
        if (!(*it)->is_unconditional && !(*it)->is_call_non_return)
          {
-           const char *branch_type;
-           /* branch:<line_num>,<branch_coverage_infoype>
-              branch_coverage_infoype
-              : notexec (Branch not executed)
-              : taken (Branch executed and taken)
-              : nottaken (Branch executed, but not taken)
-              */
-           if ((*it)->src->count)
-                branch_type
-                       = ((*it)->count > 0) ? "taken" : "nottaken";
-           else
-             branch_type = "notexec";
-           fprintf (f, "branch:%d,%s\n", line_num, branch_type);
+           json::object *branch = new json::object ();
+           branch->set ("count", new json::number ((*it)->count));
+           branch->set ("throw", new json::literal ((*it)->is_throw));
+           branch->set ("fallthrough",
+                        new json::literal ((*it)->fall_through));
+           branches->append (branch);
          }
       }
+
+  object->append (lineo);
 }
 
 /* Get the name of the gcov file.  The return value must be free'd.
@@ -1038,7 +1068,7 @@ output_intermediate_line (FILE *f, line_info *line, unsigned line_num)
 static char *
 get_gcov_intermediate_filename (const char *file_name)
 {
-  const char *gcov = ".gcov";
+  const char *gcov = ".gcov.json.gz";
   char *result;
   const char *cptr;
 
@@ -1051,34 +1081,44 @@ get_gcov_intermediate_filename (const char *file_name)
   return result;
 }
 
-/* Output the result in intermediate format used by 'lcov'.
-
-The intermediate format contains a single file named 'foo.cc.gcov',
-with no source code included.
-
-The default gcov outputs multiple files: 'foo.cc.gcov',
-'iostream.gcov', 'ios_base.h.gcov', etc. with source code
-included. Instead the intermediate format here outputs only a single
-file 'foo.cc.gcov' similar to the above example. */
+/* Output the result in JSON intermediate format.
+   Source info SRC is dumped into JSON_FILES which is JSON array.  */
 
 static void
-output_intermediate_file (FILE *gcov_file, source_info *src)
+output_json_intermediate_file (json::array *json_files, source_info *src)
 {
-  fprintf (gcov_file, "version:%s\n", version_string);
-  fprintf (gcov_file, "file:%s\n", src->name);    /* source file name */
-  fprintf (gcov_file, "cwd:%s\n", bbg_cwd);
+  json::object *root = new json::object ();
+  json_files->append (root);
+
+  root->set ("file", new json::string (src->name));
+
+  json::array *functions = new json::array ();
+  root->set ("functions", functions);
 
   std::sort (src->functions.begin (), src->functions.end (),
             function_line_start_cmp ());
   for (vector<function_info *>::iterator it = src->functions.begin ();
        it != src->functions.end (); it++)
     {
-      /* function:<name>,<line_number>,<execution_count> */
-      fprintf (gcov_file, "function:%d,%d,%s,%s\n", (*it)->start_line,
-              (*it)->end_line, format_gcov ((*it)->blocks[0].count, 0, -1),
-              flag_demangled_names ? (*it)->demangled_name : (*it)->name);
+      json::object *function = new json::object ();
+      function->set ("name", new json::string ((*it)->m_name));
+      function->set ("demangled_name",
+                    new json::string ((*it)->get_demangled_name ()));
+      function->set ("start_line", new json::number ((*it)->start_line));
+      function->set ("end_line", new json::number ((*it)->end_line));
+      function->set ("blocks",
+                    new json::number ((*it)->get_block_count ()));
+      function->set ("blocks_executed",
+                    new json::number ((*it)->blocks_executed));
+      function->set ("execution_count",
+                    new json::number ((*it)->blocks[0].count));
+
+      functions->append (function);
     }
 
+  json::array *lineso = new json::array ();
+  root->set ("lines", lineso);
+
   for (unsigned line_num = 1; line_num <= src->lines.size (); line_num++)
     {
       vector<function_info *> fns = src->get_functions_at_location (line_num);
@@ -1091,13 +1131,13 @@ output_intermediate_file (FILE *gcov_file, source_info *src)
          for (unsigned i = 0; i < lines.size (); i++)
            {
              line_info *line = &lines[i];
-             output_intermediate_line (gcov_file, line, line_num + i);
+             output_intermediate_json_line (lineso, line, line_num + i);
            }
        }
 
       /* Follow with lines associated with the source file.  */
       if (line_num < src->lines.size ())
-       output_intermediate_line (gcov_file, &src->lines[line_num], line_num);
+       output_intermediate_json_line (lineso, &src->lines[line_num], line_num);
     }
 }
 
@@ -1301,8 +1341,7 @@ output_gcov_file (const char *file_name, source_info *src)
 static void
 generate_results (const char *file_name)
 {
-  FILE *gcov_intermediate_file = NULL;
-  char *gcov_intermediate_filename = NULL;
+  char *gcov_intermediate_filename;
 
   for (vector<function_info *>::iterator it = functions.begin ();
        it != functions.end (); it++)
@@ -1311,7 +1350,7 @@ generate_results (const char *file_name)
       coverage_info coverage;
 
       memset (&coverage, 0, sizeof (coverage));
-      coverage.name = flag_demangled_names ? fn->demangled_name : fn->name;
+      coverage.name = fn->get_name ();
       add_line_counts (flag_function_summary ? &coverage : NULL, fn);
       if (flag_function_summary)
        {
@@ -1333,18 +1372,15 @@ generate_results (const char *file_name)
        file_name = canonicalize_name (file_name);
     }
 
-  if (flag_gcov_file && flag_intermediate_format && !flag_use_stdout)
-    {
-      /* Open the intermediate file.  */
-      gcov_intermediate_filename = get_gcov_intermediate_filename (file_name);
-      gcov_intermediate_file = fopen (gcov_intermediate_filename, "w");
-      if (!gcov_intermediate_file)
-       {
-         fnotice (stderr, "Cannot open intermediate output file %s\n",
-                  gcov_intermediate_filename);
-         return;
-       }
-    }
+  gcov_intermediate_filename = get_gcov_intermediate_filename (file_name);
+
+  json::object *root = new json::object ();
+  root->set ("format_version", new json::string ("1"));
+  root->set ("gcc_version", new json::string (version_string));
+  root->set ("current_working_directory", new json::string (bbg_cwd));
+
+  json::array *json_files = new json::array ();
+  root->set ("files", json_files);
 
   for (vector<source_info>::iterator it = sources.begin ();
        it != sources.end (); it++)
@@ -1372,11 +1408,8 @@ generate_results (const char *file_name)
       total_executed += src->coverage.lines_executed;
       if (flag_gcov_file)
        {
-         if (flag_intermediate_format)
-           /* Output the intermediate format without requiring source
-              files.  This outputs a section to a *single* file.  */
-           output_intermediate_file ((flag_use_stdout
-                                      ? stdout : gcov_intermediate_file), src);
+         if (flag_json_format)
+           output_json_intermediate_file (json_files, src);
          else
            {
              if (flag_use_stdout)
@@ -1393,11 +1426,35 @@ generate_results (const char *file_name)
        }
     }
 
-  if (flag_gcov_file && flag_intermediate_format && !flag_use_stdout)
+  if (flag_gcov_file && flag_json_format)
     {
-      /* Now we've finished writing the intermediate file.  */
-      fclose (gcov_intermediate_file);
-      XDELETEVEC (gcov_intermediate_filename);
+      if (flag_use_stdout)
+       {
+         root->dump (stdout);
+         printf ("\n");
+       }
+      else
+       {
+         pretty_printer pp;
+         root->print (&pp);
+         pp_formatted_text (&pp);
+
+         gzFile output = gzopen (gcov_intermediate_filename, "w");
+         if (output == NULL)
+           {
+             fnotice (stderr, "Cannot open JSON output file %s\n",
+                      gcov_intermediate_filename);
+             return;
+           }
+
+         if (gzputs (output, pp_formatted_text (&pp)) == EOF
+             || gzclose (output))
+           {
+             fnotice (stderr, "Error writing JSON output file %s\n",
+                      gcov_intermediate_filename);
+             return;
+           }
+       }
     }
 
   if (!file_name)
@@ -1634,13 +1691,7 @@ read_graph_file (void)
 
          fn = new function_info ();
          functions.push_back (fn);
-         fn->name = function_name;
-         if (flag_demangled_names)
-           {
-             fn->demangled_name = cplus_demangle (fn->name, DMGL_PARAMS);
-             if (!fn->demangled_name)
-               fn->demangled_name = fn->name;
-           }
+         fn->m_name = function_name;
          fn->ident = ident;
          fn->lineno_checksum = lineno_checksum;
          fn->cfg_checksum = cfg_checksum;
@@ -1656,7 +1707,7 @@ read_graph_file (void)
        {
          if (!fn->blocks.empty ())
            fnotice (stderr, "%s:already seen blocks for '%s'\n",
-                    bbg_file_name, fn->name);
+                    bbg_file_name, fn->get_name ());
          else
            fn->blocks.resize (gcov_read_unsigned ());
        }
@@ -1862,7 +1913,7 @@ read_count_file (void)
            {
            mismatch:;
              fnotice (stderr, "%s:profile mismatch for '%s'\n",
-                      da_file_name, fn->name);
+                      da_file_name, fn->get_name ());
              goto cleanup;
            }
        }
@@ -1927,12 +1978,12 @@ solve_flow_graph (function_info *fn)
 
   if (fn->blocks.size () < 2)
     fnotice (stderr, "%s:'%s' lacks entry and/or exit blocks\n",
-            bbg_file_name, fn->name);
+            bbg_file_name, fn->get_name ());
   else
     {
       if (fn->blocks[ENTRY_BLOCK].num_pred)
        fnotice (stderr, "%s:'%s' has arcs to entry block\n",
-                bbg_file_name, fn->name);
+                bbg_file_name, fn->get_name ());
       else
        /* We can't deduce the entry block counts from the lack of
           predecessors.  */
@@ -1940,7 +1991,7 @@ solve_flow_graph (function_info *fn)
 
       if (fn->blocks[EXIT_BLOCK].num_succ)
        fnotice (stderr, "%s:'%s' has arcs from exit block\n",
-                bbg_file_name, fn->name);
+                bbg_file_name, fn->get_name ());
       else
        /* Likewise, we can't deduce exit block counts from the lack
           of its successors.  */
@@ -2149,7 +2200,7 @@ solve_flow_graph (function_info *fn)
     if (!fn->blocks[i].count_valid)
       {
        fnotice (stderr, "%s:graph is unsolvable for '%s'\n",
-                bbg_file_name, fn->name);
+                bbg_file_name, fn->get_name ());
        break;
       }
 }
@@ -2553,7 +2604,8 @@ add_line_counts (coverage_info *coverage, function_info *fn)
     }
 
   if (!has_any_line)
-    fnotice (stderr, "%s:no lines for '%s'\n", bbg_file_name, fn->name);
+    fnotice (stderr, "%s:no lines for '%s'\n", bbg_file_name,
+            fn->get_name ());
 }
 
 /* Accumulate info for LINE that belongs to SRC source file.  If ADD_COVERAGE
@@ -2633,7 +2685,7 @@ accumulate_line_counts (source_info *src)
 
   /* If not using intermediate mode, sum lines of group functions and
      add them to lines that live in a source file.  */
-  if (!flag_intermediate_format)
+  if (!flag_json_format)
     for (vector<function_info *>::iterator it = src->functions.begin ();
         it != src->functions.end (); it++)
       {
@@ -2895,7 +2947,7 @@ output_line_details (FILE *f, const line_info *line, unsigned line_num)
 /* Output detail statistics about function FN to file F.  */
 
 static void
-output_function_details (FILE *f, const function_info *fn)
+output_function_details (FILE *f, function_info *fn)
 {
   if (!flag_branches)
     return;
@@ -2908,15 +2960,13 @@ output_function_details (FILE *f, const function_info *fn)
     if (arc->fake)
       return_count -= arc->count;
 
-  fprintf (f, "function %s",
-          flag_demangled_names ? fn->demangled_name : fn->name);
+  fprintf (f, "function %s", fn->get_name ());
   fprintf (f, " called %s",
           format_gcov (called_count, 0, -1));
   fprintf (f, " returned %s",
           format_gcov (return_count, called_count, 0));
   fprintf (f, " blocks executed %s",
-          format_gcov (fn->blocks_executed, fn->blocks.size () - 2,
-                       0));
+          format_gcov (fn->blocks_executed, fn->get_block_count (), 0));
   fprintf (f, "\n");
 }
 
@@ -3028,9 +3078,7 @@ output_lines (FILE *gcov_file, const source_info *src)
 
              fprintf (gcov_file, FN_SEPARATOR);
 
-             string fn_name
-               = flag_demangled_names ? fn->demangled_name : fn->name;
-
+             string fn_name = fn->get_name ();
              if (flag_use_colors)
                {
                  fn_name.insert (0, SGR_SEQ (COLOR_FG_CYAN));
index 3ead98073f6a31d7fdd285e2dc0ed8f94d7829a9..a0c439560e974fa85016e067244b9f3b20591b28 100644 (file)
@@ -296,6 +296,9 @@ test_writing_literals ()
   assert_print_eq (literal (JSON_TRUE), "true");
   assert_print_eq (literal (JSON_FALSE), "false");
   assert_print_eq (literal (JSON_NULL), "null");
+
+  assert_print_eq (literal (true), "true");
+  assert_print_eq (literal (false), "false");
 }
 
 /* Run all of the selftests within this file.  */
index 154d9e1b57517a75323fb2dc58981935c87ee1e5..e99141e71e15cace81757d367bc0830db4afaec2 100644 (file)
@@ -154,6 +154,9 @@ class literal : public value
  public:
   literal (enum kind kind) : m_kind (kind) {}
 
+  /* Construct literal for a boolean value.  */
+  literal (bool value): m_kind (value ? JSON_TRUE : JSON_FALSE) {}
+
   enum kind get_kind () const FINAL OVERRIDE { return m_kind; }
   void print (pretty_printer *pp) const FINAL OVERRIDE;
 
index 40ea5a7b436a5fa4861cea359582da1689cfefa1..5584b886f1dcd52e46809e61e95fad3fdc325198 100644 (file)
@@ -1,3 +1,8 @@
+2018-10-29  Martin Liska  <mliska@suse.cz>
+
+       * g++.dg/gcov/gcov-8.C: Do not check intermediate format.
+       * lib/gcov.exp: Remove legacy verify-intermediate.
+
 2018-10-28  Kugan Vivekanandarajah  <kuganv@linaro.org>
 
        * gcc.dg/gimplefe-30.c: New test.
index 7acab4672ff50d0a52d58bfe8ef5454ecf8abe8a..1c97c35d8c1e3d2aad97d124d3be8865b56d0338 100644 (file)
@@ -1,5 +1,3 @@
-/* Verify that intermediate coverage format can be generated for simple code. */
-
 /* { dg-options "-fprofile-arcs -ftest-coverage" } */
 /* { dg-do run { target native } } */
 
@@ -32,4 +30,4 @@ int main()
   foo();
 }
 
-/* { dg-final { run-gcov intermediate { -i -b gcov-8.C } } } */
+/* { dg-final { run-gcov { -b gcov-8.C } } } */
index f35ca59fbe308c4d94c5722e9f762f7990d65e81..a7b8c0a1ef45d4dafc0b5e491727754a14df0171 100644 (file)
@@ -83,61 +83,6 @@ proc verify-lines { testname testcase file } {
 }
 
 
-#
-# verify-intermediate -- check that intermediate file has certain lines
-#
-# TESTNAME is the name of the test, including unique flags.
-# TESTCASE is the name of the test.
-# FILE is the name of the gcov output file.
-#
-# Checks are very loose, they are based on certain tags being present
-# in the output. They do not check for exact expected execution
-# counts. For that the regular gcov format should be checked.
-#
-proc verify-intermediate { testname testcase file } {
-    set failed 0
-    set srcfile 0
-    set function 0
-    set lcount 0
-    set branch 0
-    set fd [open $file r]
-    while { [gets $fd line] >= 0 } {
-       if [regexp "^file:" $line] {
-           incr srcfile
-       }
-       if [regexp "^function:(\[0-9\]+),(\[0-9\]+),.*" $line] {
-           incr function
-       }
-       if [regexp "^lcount:(\[0-9\]+),(\[0-9\]+),(\[01\])" $line] {
-           incr lcount
-       }
-       if [regexp "^branch:(\[0-9\]+),(taken|nottaken|notexec)" $line] {
-           incr branch
-       }
-    }
-
-    # We should see at least one tag of each type
-    if {$srcfile == 0} {
-       fail "$testname expected 'file:' tag not found"
-       incr failed
-    }
-    if {$function == 0} {
-       fail "$testname expected 'function:' tag not found"
-       incr failed
-    }
-    if {$lcount == 0} {
-       fail "$testname expected 'lcount:' tag not found"
-       incr failed
-    }
-    if {$branch == 0} {
-       fail "$testname expected 'branch:' tag not found"
-       incr failed
-    }
-    close $fd
-    return $failed
-}
-
-
 #
 # verify-branches -- check that branch percentages are as expected
 #