diff options
author | Jeff Chapman II <jchapman@lock3software.com> | 2022-11-03 15:47:47 -0400 |
---|---|---|
committer | Jason Merrill <jason@redhat.com> | 2022-11-04 13:07:14 -0400 |
commit | 0386c40eebf1800dc7728ba85f3dbbb9ec4eeb5d (patch) | |
tree | 4e50664ab59a990dff40825e20f4ad72961a9bfa /gcc | |
parent | 679be32e66428f0ba81d1c1b55f7bd47f01cb295 (diff) | |
download | gcc-0386c40eebf1800dc7728ba85f3dbbb9ec4eeb5d.zip gcc-0386c40eebf1800dc7728ba85f3dbbb9ec4eeb5d.tar.gz gcc-0386c40eebf1800dc7728ba85f3dbbb9ec4eeb5d.tar.bz2 |
input: add get_source_text_between
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 <jason@redhat.com>
gcc/ChangeLog:
* input.cc (get_source_text_between): New fn.
* input.h (get_source_text_between): Declare.
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/input.cc | 92 | ||||
-rw-r--r-- | gcc/input.h | 1 |
2 files changed, 93 insertions, 0 deletions
diff --git a/gcc/input.cc b/gcc/input.cc index a28abfa..c185bd7 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. */ diff --git a/gcc/input.h b/gcc/input.h index 11c571d..f187699 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); |