On 11/4/22 11:16, David Malcolm wrote:
On Fri, 2022-11-04 at 10:27 -0400, Jason Merrill wrote:
On 11/3/22 19:06, David Malcolm wrote:
On Thu, 2022-11-03 at 15:59 -0400, Jason Merrill via Gcc-patches
wrote:

[...snip...]



Do you have test coverage for this from the DejaGnu side?  If not,
you
could add selftest coverage for this; see input.cc's
test_reading_source_line for something similar.

There is test coverage for the output of the the contract violation
handler, which involves printing the result of this function.

Thanks.   Is this test posted somwehere?  I was looking in:
  https://gcc.gnu.org/pipermail/gcc-patches/2022-November/604974.html
but I'm not seeing it.  Sorry if I'm missing something here.

The tests are in the newer message

  https://gcc.gnu.org/pipermail/gcc-patches/2022-November/605072.html

Ideally we should have coverage for the three cases of:
(a) bails out and returns NULL

This isn't tested because it should never happen.

(b) single-line case

contracts-tmpl-spec3.C etc.

(c) multi-line case

contracts-multiline1.C

index a28abfac5ac..04d0809bfdf 100644
--- a/gcc/input.cc
+++ b/gcc/input.cc
@@ -949,6 +949,97 @@ location_get_source_line (const char *file_path, int line)
    return char_span (buffer, len);
  }

Strings in input.cc are not always NUL-terminated, so...

+/* Return a copy of the source text between two locations. The caller is
+   responsible for freeing the return value.  */

...please note in the comment that if non-NULL, the copy is NUL-
terminated (I checked both exit paths that can return non-NULL, and
they do NUL-terminate their buffers).

OK with that nit fixed.

Thanks, pushing this:
From 35d436c8e9455e99015d0e414a4ede9e59e774c4 Mon Sep 17 00:00:00 2001
From: Jeff Chapman II <jchap...@lock3software.com>
Date: Thu, 3 Nov 2022 15:47:47 -0400
Subject: [PATCH] input: add get_source_text_between
To: gcc-patches@gcc.gnu.org

The c++-contracts branch uses this to retrieve the source form of the
contract predicate, to be returned by contract_violation::comment().

Co-authored-by: Jason Merrill  <ja...@redhat.com>

gcc/ChangeLog:

	* input.cc (get_source_text_between): New fn.
	* input.h (get_source_text_between): Declare.
---
 gcc/input.h  |  1 +
 gcc/input.cc | 92 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 93 insertions(+)

diff --git a/gcc/input.h b/gcc/input.h
index 11c571d076f..f18769950b5 100644
--- a/gcc/input.h
+++ b/gcc/input.h
@@ -111,6 +111,7 @@ class char_span
 };
 
 extern char_span location_get_source_line (const char *file_path, int line);
+extern char *get_source_text_between (location_t, location_t);
 
 extern bool location_missing_trailing_newline (const char *file_path);
 
diff --git a/gcc/input.cc b/gcc/input.cc
index a28abfac5ac..c185bd74c1f 100644
--- a/gcc/input.cc
+++ b/gcc/input.cc
@@ -949,6 +949,98 @@ location_get_source_line (const char *file_path, int line)
   return char_span (buffer, len);
 }
 
+/* Return a NUL-terminated copy of the source text between two locations, or
+   NULL if the arguments are invalid.  The caller is responsible for freeing
+   the return value.  */
+
+char *
+get_source_text_between (location_t start, location_t end)
+{
+  expanded_location expstart =
+    expand_location_to_spelling_point (start, LOCATION_ASPECT_START);
+  expanded_location expend =
+    expand_location_to_spelling_point (end, LOCATION_ASPECT_FINISH);
+
+  /* If the locations are in different files or the end comes before the
+     start, give up and return nothing.  */
+  if (!expstart.file || !expend.file)
+    return NULL;
+  if (strcmp (expstart.file, expend.file) != 0)
+    return NULL;
+  if (expstart.line > expend.line)
+    return NULL;
+  if (expstart.line == expend.line
+      && expstart.column > expend.column)
+    return NULL;
+  /* These aren't real column numbers, give up.  */
+  if (expstart.column == 0 || expend.column == 0)
+    return NULL;
+
+  /* For a single line we need to trim both edges.  */
+  if (expstart.line == expend.line)
+    {
+      char_span line = location_get_source_line (expstart.file, expstart.line);
+      if (line.length () < 1)
+	return NULL;
+      int s = expstart.column - 1;
+      int len = expend.column - s;
+      if (line.length () < (size_t)expend.column)
+	return NULL;
+      return line.subspan (s, len).xstrdup ();
+    }
+
+  struct obstack buf_obstack;
+  obstack_init (&buf_obstack);
+
+  /* Loop through all lines in the range and append each to buf; may trim
+     parts of the start and end lines off depending on column values.  */
+  for (int lnum = expstart.line; lnum <= expend.line; ++lnum)
+    {
+      char_span line = location_get_source_line (expstart.file, lnum);
+      if (line.length () < 1 && (lnum != expstart.line && lnum != expend.line))
+	continue;
+
+      /* For the first line in the range, only start at expstart.column */
+      if (lnum == expstart.line)
+	{
+	  unsigned off = expstart.column - 1;
+	  if (line.length () < off)
+	    return NULL;
+	  line = line.subspan (off, line.length() - off);
+	}
+      /* For the last line, don't go past expend.column */
+      else if (lnum == expend.line)
+	{
+	  if (line.length () < (size_t)expend.column)
+	    return NULL;
+	  line = line.subspan (0, expend.column);
+	}
+
+      /* Combine spaces at the beginning of later lines.  */
+      if (lnum > expstart.line)
+	{
+	  unsigned off;
+	  for (off = 0; off < line.length(); ++off)
+	    if (line[off] != ' ' && line[off] != '\t')
+	      break;
+	  if (off > 0)
+	    {
+	      obstack_1grow (&buf_obstack, ' ');
+	      line = line.subspan (off, line.length() - off);
+	    }
+	}
+
+      /* This does not include any trailing newlines.  */
+      obstack_grow (&buf_obstack, line.get_buffer (), line.length ());
+    }
+
+  /* NUL-terminate and finish the buf obstack.  */
+  obstack_1grow (&buf_obstack, 0);
+  const char *buf = (const char *) obstack_finish (&buf_obstack);
+
+  return xstrdup (buf);
+}
+
 /* Determine if FILE_PATH missing a trailing newline on its final line.
    Only valid to call once all of the file has been loaded, by
    requesting a line number beyond the end of the file.  */
-- 
2.31.1

Reply via email to