aboutsummaryrefslogtreecommitdiff
path: root/gcc/input.cc
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/input.cc')
-rw-r--r--gcc/input.cc1073
1 files changed, 21 insertions, 1052 deletions
diff --git a/gcc/input.cc b/gcc/input.cc
index fabfbfb..b9a5539 100644
--- a/gcc/input.cc
+++ b/gcc/input.cc
@@ -22,6 +22,7 @@ along with GCC; see the file COPYING3. If not see
#include "coretypes.h"
#include "intl.h"
#include "diagnostic.h"
+#include "diagnostics/file-cache.h"
#include "selftest.h"
#include "cpplib.h"
@@ -35,188 +36,6 @@ special_fname_builtin ()
return _("<built-in>");
}
-/* Input charset configuration. */
-static const char *default_charset_callback (const char *)
-{
- return nullptr;
-}
-
-void
-file_cache::initialize_input_context (diagnostic_input_charset_callback ccb,
- bool should_skip_bom)
-{
- m_input_context.ccb = (ccb ? ccb : default_charset_callback);
- m_input_context.should_skip_bom = should_skip_bom;
-}
-
-/* This is a cache used by get_next_line to store the content of a
- file to be searched for file lines. */
-class file_cache_slot
-{
-public:
- file_cache_slot ();
- ~file_cache_slot ();
-
- void dump (FILE *out, int indent) const;
- void DEBUG_FUNCTION dump () const { dump (stderr, 0); }
-
- bool read_line_num (size_t line_num,
- char ** line, ssize_t *line_len);
-
- /* Accessors. */
- const char *get_file_path () const { return m_file_path; }
- unsigned get_use_count () const { return m_use_count; }
- bool missing_trailing_newline_p () const
- {
- return m_missing_trailing_newline;
- }
- char_span get_full_file_content ();
-
- void inc_use_count () { m_use_count++; }
-
- bool create (const file_cache::input_context &in_context,
- const char *file_path, FILE *fp, unsigned highest_use_count);
- void evict ();
- void set_content (const char *buf, size_t sz);
-
- static size_t tune (size_t line_record_size_)
- {
- size_t ret = line_record_size;
- line_record_size = line_record_size_;
- return ret;
- }
-
- private:
- /* These are information used to store a line boundary. */
- class line_info
- {
- public:
- /* The line number. It starts from 1. */
- size_t line_num;
-
- /* The position (byte count) of the beginning of the line,
- relative to the file data pointer. This starts at zero. */
- size_t start_pos;
-
- /* The position (byte count) of the last byte of the line. This
- normally points to the '\n' character, or to one byte after the
- last byte of the file, if the file doesn't contain a '\n'
- character. */
- size_t end_pos;
-
- line_info (size_t l, size_t s, size_t e)
- : line_num (l), start_pos (s), end_pos (e)
- {}
-
- line_info ()
- :line_num (0), start_pos (0), end_pos (0)
- {}
-
- static bool less_than(const line_info &a, const line_info &b)
- {
- return a.line_num < b.line_num;
- }
- };
-
- bool needs_read_p () const;
- bool needs_grow_p () const;
- void maybe_grow ();
- bool read_data ();
- bool maybe_read_data ();
- bool get_next_line (char **line, ssize_t *line_len);
- bool read_next_line (char ** line, ssize_t *line_len);
- bool goto_next_line ();
-
- static const size_t buffer_size = 4 * 1024;
- static size_t line_record_size;
- static size_t recent_cached_lines_shift;
-
- /* The number of time this file has been accessed. This is used
- to designate which file cache to evict from the cache
- array. */
- unsigned m_use_count;
-
- /* The file_path is the key for identifying a particular file in
- the cache. This copy is owned by the slot. */
- char *m_file_path;
-
- FILE *m_fp;
-
- /* True when an read error happened. */
- bool m_error;
-
- /* This points to the content of the file that we've read so
- far. */
- char *m_data;
-
- /* The allocated buffer to be freed may start a little earlier than DATA,
- e.g. if a UTF8 BOM was skipped at the beginning. */
- int m_alloc_offset;
-
- /* The size of the DATA array above.*/
- size_t m_size;
-
- /* The number of bytes read from the underlying file so far. This
- must be less (or equal) than SIZE above. */
- size_t m_nb_read;
-
- /* The index of the beginning of the current line. */
- size_t m_line_start_idx;
-
- /* The number of the previous line read. This starts at 1. Zero
- means we've read no line so far. */
- size_t m_line_num;
-
- /* Could this file be missing a trailing newline on its final line?
- Initially true (to cope with empty files), set to true/false
- as each line is read. */
- bool m_missing_trailing_newline;
-
- /* This is a record of the beginning and end of the lines we've seen
- while reading the file. This is useful to avoid walking the data
- from the beginning when we are asked to read a line that is
- before LINE_START_IDX above. When the lines exceed line_record_size
- this is scaled down dynamically, with the line_info becoming anchors. */
- vec<line_info, va_heap> m_line_record;
-
- /* A cache of the recently seen lines. This is maintained as a ring
- buffer. */
- vec<line_info, va_heap> m_line_recent;
-
- /* First and last valid entry in m_line_recent. */
- size_t m_line_recent_last, m_line_recent_first;
-
- void offset_buffer (int offset)
- {
- gcc_assert (offset < 0 ? m_alloc_offset + offset >= 0
- : (size_t) offset <= m_size);
- gcc_assert (m_data);
- m_alloc_offset += offset;
- m_data += offset;
- m_size -= offset;
- }
-
-};
-
-size_t file_cache_slot::line_record_size = 0;
-size_t file_cache_slot::recent_cached_lines_shift = 8;
-
-/* Tune file_cache. */
-void
-file_cache::tune (size_t num_file_slots, size_t lines)
-{
- if (file_cache_slot::tune (lines) != lines
- || m_num_file_slots != num_file_slots)
- {
- delete[] m_file_slots;
- m_file_slots = new file_cache_slot[num_file_slots];
- }
- m_num_file_slots = num_file_slots;
-}
-
-static const char *
-find_end_of_line (const char *s, size_t len);
-
/* Current position in real source file. */
location_t input_location = UNKNOWN_LOCATION;
@@ -320,738 +139,13 @@ expand_location_1 (const line_maps *set,
return xloc;
}
-/* Lookup the cache used for the content of a given file accessed by
- caret diagnostic. Return the found cached file, or NULL if no
- cached file was found. */
-
-file_cache_slot *
-file_cache::lookup_file (const char *file_path)
-{
- gcc_assert (file_path);
-
- /* This will contain the found cached file. */
- file_cache_slot *r = NULL;
- for (unsigned i = 0; i < m_num_file_slots; ++i)
- {
- file_cache_slot *c = &m_file_slots[i];
- if (c->get_file_path () && !strcmp (c->get_file_path (), file_path))
- {
- c->inc_use_count ();
- r = c;
- }
- }
-
- if (r)
- r->inc_use_count ();
-
- return r;
-}
-
-/* Purge any mention of FILENAME from the cache of files used for
- printing source code. For use in selftests when working
- with tempfiles. */
-
-void
-file_cache::forcibly_evict_file (const char *file_path)
-{
- gcc_assert (file_path);
-
- file_cache_slot *r = lookup_file (file_path);
- if (!r)
- /* Not found. */
- return;
-
- r->evict ();
-}
-
-/* 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. */
-
-bool
-file_cache::missing_trailing_newline_p (const char *file_path)
-{
- gcc_assert (file_path);
-
- file_cache_slot *r = lookup_or_add_file (file_path);
- return r->missing_trailing_newline_p ();
-}
-
-void
-file_cache::add_buffered_content (const char *file_path,
- const char *buffer,
- size_t sz)
-{
- gcc_assert (file_path);
-
- file_cache_slot *r = lookup_file (file_path);
- if (!r)
- {
- unsigned highest_use_count = 0;
- r = evicted_cache_tab_entry (&highest_use_count);
- if (!r->create (m_input_context, file_path, nullptr, highest_use_count))
- return;
- }
-
- r->set_content (buffer, sz);
-}
-
-void
-file_cache_slot::evict ()
-{
- free (m_file_path);
- m_file_path = NULL;
- if (m_fp)
- fclose (m_fp);
- m_error = false;
- m_fp = NULL;
- m_nb_read = 0;
- m_line_start_idx = 0;
- m_line_num = 0;
- m_line_record.truncate (0);
- m_line_recent_first = 0;
- m_line_recent_last = 0;
- m_use_count = 0;
- m_missing_trailing_newline = true;
-}
-
-/* Return the file cache that has been less used, recently, or the
- first empty one. If HIGHEST_USE_COUNT is non-null,
- *HIGHEST_USE_COUNT is set to the highest use count of the entries
- in the cache table. */
-
-file_cache_slot*
-file_cache::evicted_cache_tab_entry (unsigned *highest_use_count)
-{
- file_cache_slot *to_evict = &m_file_slots[0];
- unsigned huc = to_evict->get_use_count ();
- for (unsigned i = 1; i < m_num_file_slots; ++i)
- {
- file_cache_slot *c = &m_file_slots[i];
- bool c_is_empty = (c->get_file_path () == NULL);
-
- if (c->get_use_count () < to_evict->get_use_count ()
- || (to_evict->get_file_path () && c_is_empty))
- /* We evict C because it's either an entry with a lower use
- count or one that is empty. */
- to_evict = c;
-
- if (huc < c->get_use_count ())
- huc = c->get_use_count ();
-
- if (c_is_empty)
- /* We've reached the end of the cache; subsequent elements are
- all empty. */
- break;
- }
-
- if (highest_use_count)
- *highest_use_count = huc;
-
- return to_evict;
-}
-
-/* Create the cache used for the content of a given file to be
- accessed by caret diagnostic. This cache is added to an array of
- cache and can be retrieved by lookup_file_in_cache_tab. This
- function returns the created cache. Note that only the last
- m_num_file_slots files are cached.
-
- This can return nullptr if the FILE_PATH can't be opened for
- reading, or if the content can't be converted to the input_charset. */
-
-file_cache_slot*
-file_cache::add_file (const char *file_path)
-{
-
- FILE *fp = fopen (file_path, "r");
- if (fp == NULL)
- return NULL;
-
- unsigned highest_use_count = 0;
- file_cache_slot *r = evicted_cache_tab_entry (&highest_use_count);
- if (!r->create (m_input_context, file_path, fp, highest_use_count))
- return NULL;
- return r;
-}
-
-/* Get a borrowed char_span to the full content of this file
- as decoded according to the input charset, encoded as UTF-8. */
-
-char_span
-file_cache_slot::get_full_file_content ()
-{
- char *line;
- ssize_t line_len;
- while (get_next_line (&line, &line_len))
- {
- }
- return char_span (m_data, m_nb_read);
-}
-
-/* Populate this slot for use on FILE_PATH and FP, dropping any
- existing cached content within it. */
-
-bool
-file_cache_slot::create (const file_cache::input_context &in_context,
- const char *file_path, FILE *fp,
- unsigned highest_use_count)
-{
- m_file_path = file_path ? xstrdup (file_path) : nullptr;
- if (m_fp)
- fclose (m_fp);
- m_error = false;
- m_fp = fp;
- if (m_alloc_offset)
- offset_buffer (-m_alloc_offset);
- m_nb_read = 0;
- m_line_start_idx = 0;
- m_line_num = 0;
- m_line_recent_first = 0;
- m_line_recent_last = 0;
- m_line_record.truncate (0);
- /* Ensure that this cache entry doesn't get evicted next time
- add_file_to_cache_tab is called. */
- m_use_count = ++highest_use_count;
- m_missing_trailing_newline = true;
-
-
- /* Check the input configuration to determine if we need to do any
- transformations, such as charset conversion or BOM skipping. */
- if (const char *input_charset = in_context.ccb (file_path))
- {
- /* Need a full-blown conversion of the input charset. */
- fclose (m_fp);
- m_fp = NULL;
- const cpp_converted_source cs
- = cpp_get_converted_source (file_path, input_charset);
- if (!cs.data)
- return false;
- if (m_data)
- XDELETEVEC (m_data);
- m_data = cs.data;
- m_nb_read = m_size = cs.len;
- m_alloc_offset = cs.data - cs.to_free;
- }
- else if (in_context.should_skip_bom)
- {
- if (read_data ())
- {
- const int offset = cpp_check_utf8_bom (m_data, m_nb_read);
- offset_buffer (offset);
- m_nb_read -= offset;
- }
- }
-
- return true;
-}
-
-void
-file_cache_slot::set_content (const char *buf, size_t sz)
-{
- m_data = (char *)xmalloc (sz);
- memcpy (m_data, buf, sz);
- m_nb_read = m_size = sz;
- m_alloc_offset = 0;
-
- if (m_fp)
- {
- fclose (m_fp);
- m_fp = nullptr;
- }
-}
-
-/* file_cache's ctor. */
-
-file_cache::file_cache ()
-: m_num_file_slots (16), m_file_slots (new file_cache_slot[m_num_file_slots])
-{
- initialize_input_context (nullptr, false);
-}
-
-/* file_cache's dtor. */
-
-file_cache::~file_cache ()
-{
- delete[] m_file_slots;
-}
-
-void
-file_cache::dump (FILE *out, int indent) const
-{
- for (size_t i = 0; i < m_num_file_slots; ++i)
- {
- fprintf (out, "%*sslot[%i]:\n", indent, "", (int)i);
- m_file_slots[i].dump (out, indent + 2);
- }
-}
-
-void
-file_cache::dump () const
-{
- dump (stderr, 0);
-}
-
-/* Lookup the cache used for the content of a given file accessed by
- caret diagnostic. If no cached file was found, create a new cache
- for this file, add it to the array of cached file and return
- it.
-
- This can return nullptr on a cache miss if FILE_PATH can't be opened for
- reading, or if the content can't be converted to the input_charset. */
-
-file_cache_slot*
-file_cache::lookup_or_add_file (const char *file_path)
-{
- file_cache_slot *r = lookup_file (file_path);
- if (r == NULL)
- r = add_file (file_path);
- return r;
-}
-
-/* Default constructor for a cache of file used by caret
- diagnostic. */
-
-file_cache_slot::file_cache_slot ()
-: m_use_count (0), m_file_path (NULL), m_fp (NULL), m_error (false), m_data (0),
- m_alloc_offset (0), m_size (0), m_nb_read (0), m_line_start_idx (0),
- m_line_num (0), m_missing_trailing_newline (true),
- m_line_recent_last (0), m_line_recent_first (0)
-{
- m_line_record.create (0);
- m_line_recent.create (1U << recent_cached_lines_shift);
- for (int i = 0; i < 1 << recent_cached_lines_shift; i++)
- m_line_recent.quick_push (file_cache_slot::line_info (0, 0, 0));
-}
-
-/* Destructor for a cache of file used by caret diagnostic. */
-
-file_cache_slot::~file_cache_slot ()
-{
- free (m_file_path);
- if (m_fp)
- {
- fclose (m_fp);
- m_fp = NULL;
- }
- if (m_data)
- {
- offset_buffer (-m_alloc_offset);
- XDELETEVEC (m_data);
- m_data = 0;
- }
- m_line_record.release ();
- m_line_recent.release ();
-}
-
-void
-file_cache_slot::dump (FILE *out, int indent) const
-{
- if (!m_file_path)
- {
- fprintf (out, "%*s(unused)\n", indent, "");
- return;
- }
- fprintf (out, "%*sfile_path: %s\n", indent, "", m_file_path);
- fprintf (out, "%*sfp: %p\n", indent, "", (void *)m_fp);
- fprintf (out, "%*sneeds_read_p: %i\n", indent, "", (int)needs_read_p ());
- fprintf (out, "%*sneeds_grow_p: %i\n", indent, "", (int)needs_grow_p ());
- fprintf (out, "%*suse_count: %i\n", indent, "", m_use_count);
- fprintf (out, "%*ssize: %zi\n", indent, "", m_size);
- fprintf (out, "%*snb_read: %zi\n", indent, "", m_nb_read);
- fprintf (out, "%*sstart_line_idx: %zi\n", indent, "", m_line_start_idx);
- fprintf (out, "%*sline_num: %zi\n", indent, "", m_line_num);
- fprintf (out, "%*smissing_trailing_newline: %i\n",
- indent, "", (int)m_missing_trailing_newline);
- fprintf (out, "%*sline records (%i):\n",
- indent, "", m_line_record.length ());
- int idx = 0;
- for (auto &line : m_line_record)
- fprintf (out, "%*s[%i]: line %zi: byte offsets: %zi-%zi\n",
- indent + 2, "",
- idx++, line.line_num, line.start_pos, line.end_pos);
-}
-
-/* Returns TRUE iff the cache would need to be filled with data coming
- from the file. That is, either the cache is empty or full or the
- current line is empty. Note that if the cache is full, it would
- need to be extended and filled again. */
-
-bool
-file_cache_slot::needs_read_p () const
-{
- return m_fp && (m_nb_read == 0
- || m_nb_read == m_size
- || (m_line_start_idx >= m_nb_read - 1));
-}
-
-/* Return TRUE iff the cache is full and thus needs to be
- extended. */
-
-bool
-file_cache_slot::needs_grow_p () const
-{
- return m_nb_read == m_size;
-}
-
-/* Grow the cache if it needs to be extended. */
-
-void
-file_cache_slot::maybe_grow ()
-{
- if (!needs_grow_p ())
- return;
-
- if (!m_data)
- {
- gcc_assert (m_size == 0 && m_alloc_offset == 0);
- m_size = buffer_size;
- m_data = XNEWVEC (char, m_size);
- }
- else
- {
- const int offset = m_alloc_offset;
- offset_buffer (-offset);
- m_size *= 2;
- m_data = XRESIZEVEC (char, m_data, m_size);
- offset_buffer (offset);
- }
-}
-
-/* Read more data into the cache. Extends the cache if need be.
- Returns TRUE iff new data could be read. */
-
-bool
-file_cache_slot::read_data ()
-{
- if (feof (m_fp) || ferror (m_fp))
- return false;
-
- maybe_grow ();
-
- char * from = m_data + m_nb_read;
- size_t to_read = m_size - m_nb_read;
- size_t nb_read = fread (from, 1, to_read, m_fp);
-
- if (ferror (m_fp))
- {
- m_error = true;
- return false;
- }
-
- m_nb_read += nb_read;
- return !!nb_read;
-}
-
-/* Read new data iff the cache needs to be filled with more data
- coming from the file FP. Return TRUE iff the cache was filled with
- mode data. */
-
-bool
-file_cache_slot::maybe_read_data ()
-{
- if (!needs_read_p ())
- return false;
- return read_data ();
-}
-
-/* Helper function for file_cache_slot::get_next_line (), to find the end of
- the next line. Returns with the memchr convention, i.e. nullptr if a line
- terminator was not found. We need to determine line endings in the same
- manner that libcpp does: any of \n, \r\n, or \r is a line ending. */
-
-static const char *
-find_end_of_line (const char *s, size_t len)
-{
- for (const auto end = s + len; s != end; ++s)
- {
- if (*s == '\n')
- return s;
- if (*s == '\r')
- {
- const auto next = s + 1;
- if (next == end)
- {
- /* Don't find the line ending if \r is the very last character
- in the buffer; we do not know if it's the end of the file or
- just the end of what has been read so far, and we wouldn't
- want to break in the middle of what's actually a \r\n
- sequence. Instead, we will handle the case of a file ending
- in a \r later. */
- break;
- }
- return (*next == '\n' ? next : s);
- }
- }
- return nullptr;
-}
-
-/* Read a new line from file FP, using C as a cache for the data
- coming from the file. Upon successful completion, *LINE is set to
- the beginning of the line found. *LINE points directly in the
- line cache and is only valid until the next call of get_next_line.
- *LINE_LEN is set to the length of the line. Note that the line
- does not contain any terminal delimiter. This function returns
- true if some data was read or process from the cache, false
- otherwise. Note that subsequent calls to get_next_line might
- make the content of *LINE invalid. */
-
-bool
-file_cache_slot::get_next_line (char **line, ssize_t *line_len)
-{
- /* Fill the cache with data to process. */
- maybe_read_data ();
-
- size_t remaining_size = m_nb_read - m_line_start_idx;
- if (remaining_size == 0)
- /* There is no more data to process. */
- return false;
-
- const char *line_start = m_data + m_line_start_idx;
-
- const char *next_line_start = NULL;
- size_t len = 0;
- const char *line_end = find_end_of_line (line_start, remaining_size);
- if (line_end == NULL)
- {
- /* We haven't found an end-of-line delimiter in the cache.
- Fill the cache with more data from the file and look again. */
- while (maybe_read_data ())
- {
- line_start = m_data + m_line_start_idx;
- remaining_size = m_nb_read - m_line_start_idx;
- line_end = find_end_of_line (line_start, remaining_size);
- if (line_end != NULL)
- {
- next_line_start = line_end + 1;
- break;
- }
- }
- if (line_end == NULL)
- {
- /* We've loaded all the file into the cache and still no
- terminator. Let's say the line ends up at one byte past the
- end of the file. This is to stay consistent with the case
- of when the line ends up with a terminator and line_end points to
- that. That consistency is useful below in the len calculation.
-
- If the file ends in a \r, we didn't identify it as a line
- terminator above, so do that now instead. */
- line_end = m_data + m_nb_read;
- if (m_nb_read && line_end[-1] == '\r')
- {
- --line_end;
- m_missing_trailing_newline = false;
- }
- else
- m_missing_trailing_newline = true;
- }
- else
- m_missing_trailing_newline = false;
- }
- else
- {
- next_line_start = line_end + 1;
- m_missing_trailing_newline = false;
- }
-
- if (m_error)
- return false;
-
- /* At this point, we've found the end of the of line. It either points to
- the line terminator or to one byte after the last byte of the file. */
- gcc_assert (line_end != NULL);
-
- len = line_end - line_start;
-
- if (m_line_start_idx < m_nb_read)
- *line = const_cast<char *> (line_start);
-
- ++m_line_num;
-
- /* Now update our line record so that re-reading lines from the
- before m_line_start_idx is faster. */
- size_t rlen = m_line_record.length ();
- /* Only update when beyond the previously cached region. */
- if (rlen == 0 || m_line_record[rlen - 1].line_num < m_line_num)
- {
- size_t spacing
- = (rlen >= 2
- ? (m_line_record[rlen - 1].line_num
- - m_line_record[rlen - 2].line_num) : 1);
- size_t delta
- = rlen >= 1 ? m_line_num - m_line_record[rlen - 1].line_num : 1;
-
- size_t max_size = line_record_size;
- /* One anchor per hundred input lines. */
- if (max_size == 0)
- max_size = m_line_num / 100;
-
- /* If we're too far beyond drop half of the lines to rebalance. */
- if (rlen == max_size && delta >= spacing * 2)
- {
- size_t j = 0;
- for (size_t i = 1; i < rlen; i += 2)
- m_line_record[j++] = m_line_record[i];
- m_line_record.truncate (j);
- rlen = j;
- spacing *= 2;
- }
-
- if (rlen < max_size && delta >= spacing)
- {
- file_cache_slot::line_info li (m_line_num, m_line_start_idx,
- line_end - m_data);
- m_line_record.safe_push (li);
- }
- }
-
- /* Cache recent tail lines separately for fast access. This assumes
- most accesses do not skip backwards. */
- if (m_line_recent_last == m_line_recent_first
- || m_line_recent[m_line_recent_last].line_num == m_line_num - 1)
- {
- size_t mask = ((size_t) 1 << recent_cached_lines_shift) - 1;
- m_line_recent_last = (m_line_recent_last + 1) & mask;
- if (m_line_recent_last == m_line_recent_first)
- m_line_recent_first = (m_line_recent_first + 1) & mask;
- m_line_recent[m_line_recent_last]
- = file_cache_slot::line_info (m_line_num, m_line_start_idx,
- line_end - m_data);
- }
-
- /* Update m_line_start_idx so that it points to the next line to be
- read. */
- if (next_line_start)
- m_line_start_idx = next_line_start - m_data;
- else
- /* We didn't find any terminal '\n'. Let's consider that the end
- of line is the end of the data in the cache. The next
- invocation of get_next_line will either read more data from the
- underlying file or return false early because we've reached the
- end of the file. */
- m_line_start_idx = m_nb_read;
-
- *line_len = len;
-
- return true;
-}
-
-/* Consume the next bytes coming from the cache (or from its
- underlying file if there are remaining unread bytes in the file)
- until we reach the next end-of-line (or end-of-file). There is no
- copying from the cache involved. Return TRUE upon successful
- completion. */
-
-bool
-file_cache_slot::goto_next_line ()
-{
- char *l;
- ssize_t len;
-
- return get_next_line (&l, &len);
-}
-
-/* Read an arbitrary line number LINE_NUM from the file cached in C.
- If the line was read successfully, *LINE points to the beginning
- of the line in the file cache and *LINE_LEN is the length of the
- line. *LINE is not nul-terminated, but may contain zero bytes.
- *LINE is only valid until the next call of read_line_num.
- This function returns bool if a line was read. */
-
-bool
-file_cache_slot::read_line_num (size_t line_num,
- char ** line, ssize_t *line_len)
-{
- gcc_assert (line_num > 0);
-
- /* Is the line in the recent line cache?
- This assumes the main file processing is only using
- a single contiguous cursor with only temporary excursions. */
- if (m_line_recent_first != m_line_recent_last
- && m_line_recent[m_line_recent_first].line_num <= line_num
- && m_line_recent[m_line_recent_last].line_num >= line_num)
- {
- line_info &last = m_line_recent[m_line_recent_last];
- size_t mask = (1U << recent_cached_lines_shift) - 1;
- size_t idx = (m_line_recent_last - (last.line_num - line_num)) & mask;
- line_info &recent = m_line_recent[idx];
- gcc_assert (recent.line_num == line_num);
- *line = m_data + recent.start_pos;
- *line_len = recent.end_pos - recent.start_pos;
- return true;
- }
-
- if (line_num <= m_line_num)
- {
- line_info l (line_num, 0, 0);
- int i = m_line_record.lower_bound (l, line_info::less_than);
- if (i == 0)
- {
- m_line_start_idx = 0;
- m_line_num = 0;
- }
- else if (m_line_record[i - 1].line_num == line_num)
- {
- /* We have the start/end of the line. */
- *line = m_data + m_line_record[i - 1].start_pos;
- *line_len = m_line_record[i - 1].end_pos - m_line_record[i - 1].start_pos;
- return true;
- }
- else
- {
- gcc_assert (m_line_record[i - 1].line_num < m_line_num);
- m_line_start_idx = m_line_record[i - 1].start_pos;
- m_line_num = m_line_record[i - 1].line_num - 1;
- }
- }
-
- /* Let's walk from line m_line_num up to line_num - 1, without
- copying any line. */
- while (m_line_num < line_num - 1)
- if (!goto_next_line ())
- return false;
-
- /* The line we want is the next one. Let's read it. */
- return get_next_line (line, line_len);
-}
-
-/* Return the physical source line that corresponds to FILE_PATH/LINE.
- The line is not nul-terminated. The returned pointer is only
- valid until the next call of location_get_source_line.
- Note that the line can contain several null characters,
- so the returned value's length has the actual length of the line.
- If the function fails, a NULL char_span is returned. */
-
-char_span
-file_cache::get_source_line (const char *file_path, int line)
-{
- char *buffer = NULL;
- ssize_t len;
-
- if (line == 0)
- return char_span (NULL, 0);
-
- if (file_path == NULL)
- return char_span (NULL, 0);
-
- file_cache_slot *c = lookup_or_add_file (file_path);
- if (c == NULL)
- return char_span (NULL, 0);
-
- bool read = c->read_line_num (line, &buffer, &len);
- if (!read)
- return char_span (NULL, 0);
-
- 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 (file_cache &fc, location_t start, location_t end)
+get_source_text_between (diagnostics::file_cache &fc,
+ location_t start, location_t end)
{
expanded_location expstart
= expand_location_to_spelling_point (start, LOCATION_ASPECT_START);
@@ -1076,7 +170,8 @@ get_source_text_between (file_cache &fc, location_t start, location_t end)
/* For a single line we need to trim both edges. */
if (expstart.line == expend.line)
{
- char_span line = fc.get_source_line (expstart.file, expstart.line);
+ diagnostics::char_span line
+ = fc.get_source_line (expstart.file, expstart.line);
if (line.length () < 1)
return NULL;
int s = expstart.column - 1;
@@ -1093,7 +188,7 @@ get_source_text_between (file_cache &fc, location_t start, location_t end)
parts of the start and end lines off depending on column values. */
for (int lnum = expstart.line; lnum <= expend.line; ++lnum)
{
- char_span line = fc.get_source_line (expstart.file, lnum);
+ diagnostics::char_span line = fc.get_source_line (expstart.file, lnum);
if (line.length () < 1 && (lnum != expstart.line && lnum != expend.line))
continue;
@@ -1138,16 +233,6 @@ get_source_text_between (file_cache &fc, location_t start, location_t end)
return xstrdup (buf);
}
-
-char_span
-file_cache::get_source_file_content (const char *file_path)
-{
- file_cache_slot *c = lookup_or_add_file (file_path);
- if (c == nullptr)
- return char_span (nullptr, 0);
- return c->get_full_file_content ();
-}
-
/* Test if the location originates from the spelling location of a
builtin-tokens. That is, return TRUE if LOC is a (possibly
virtual) location of a built-in token that appears in the expansion
@@ -1280,13 +365,13 @@ make_location (location_t caret, source_range src_range)
source line in order to calculate the display width. If that cannot be done
for any reason, then returns the byte column as a fallback. */
int
-location_compute_display_column (file_cache &fc,
+location_compute_display_column (diagnostics::file_cache &fc,
expanded_location exploc,
const cpp_char_column_policy &policy)
{
if (!(exploc.file && *exploc.file && exploc.line && exploc.column))
return exploc.column;
- char_span line = fc.get_source_line (exploc.file, exploc.line);
+ diagnostics::char_span line = fc.get_source_line (exploc.file, exploc.line);
/* If line is NULL, this function returns exploc.column which is the
desired fallback. */
return cpp_byte_column_to_display_column (line.get_buffer (), line.length (),
@@ -1431,7 +516,7 @@ dump_labelled_location_range (FILE *stream,
void
dump_location_info (FILE *stream)
{
- file_cache fc;
+ diagnostics::file_cache fc;
/* Visualize the reserved locations. */
dump_labelled_location_range (stream, "RESERVED LOCATIONS",
@@ -1506,8 +591,8 @@ dump_location_info (FILE *stream)
{
/* Beginning of a new source line: draw the line. */
- char_span line_text = fc.get_source_line (exploc.file,
- exploc.line);
+ diagnostics::char_span line_text
+ = fc.get_source_line (exploc.file, exploc.line);
if (!line_text)
break;
fprintf (stream,
@@ -1524,10 +609,10 @@ dump_location_info (FILE *stream)
if (max_col > line_text.length ())
max_col = line_text.length () + 1;
- int len_lnum = num_digits (exploc.line);
+ int len_lnum = diagnostics::num_digits (exploc.line);
if (len_lnum < 3)
len_lnum = 3;
- int len_loc = num_digits (loc);
+ int len_loc = diagnostics::num_digits (loc);
if (len_loc < 5)
len_loc = 5;
@@ -1757,7 +842,7 @@ class auto_cpp_string_vec : public auto_vec <cpp_string>
static const char *
get_substring_ranges_for_loc (cpp_reader *pfile,
- file_cache &fc,
+ diagnostics::file_cache &fc,
string_concat_db *concats,
location_t strloc,
enum cpp_ttype type,
@@ -1837,7 +922,7 @@ get_substring_ranges_for_loc (cpp_reader *pfile,
if (start.column > finish.column)
return "range endpoints are reversed";
- char_span line = fc.get_source_line (start.file, start.line);
+ diagnostics::char_span line = fc.get_source_line (start.file, start.line);
if (!line)
return "unable to read source line";
@@ -1852,7 +937,8 @@ get_substring_ranges_for_loc (cpp_reader *pfile,
if (line.length () < (start.column - 1 + literal_length))
return "line is not wide enough";
- char_span literal = line.subspan (start.column - 1, literal_length);
+ diagnostics::char_span literal
+ = line.subspan (start.column - 1, literal_length);
cpp_string from;
from.len = literal_length;
@@ -1925,7 +1011,7 @@ get_substring_ranges_for_loc (cpp_reader *pfile,
const char *
get_location_within_string (cpp_reader *pfile,
- file_cache &fc,
+ diagnostics::file_cache &fc,
string_concat_db *concats,
location_t strloc,
enum cpp_ttype type,
@@ -2008,7 +1094,7 @@ namespace selftest {
static const char *
get_source_range_for_char (cpp_reader *pfile,
- file_cache &fc,
+ diagnostics::file_cache &fc,
string_concat_db *concats,
location_t strloc,
enum cpp_ttype type,
@@ -2036,7 +1122,7 @@ get_source_range_for_char (cpp_reader *pfile,
static const char *
get_num_source_ranges_for_substring (cpp_reader *pfile,
- file_cache &fc,
+ diagnostics::file_cache &fc,
string_concat_db *concats,
location_t strloc,
enum cpp_ttype type,
@@ -2359,119 +1445,6 @@ test_make_location_nonpure_range_endpoints (const line_table_case &case_)
ASSERT_FALSE (IS_ADHOC_LOC (get_finish (not_aaa_eq_bbb)));
}
-/* Verify reading of a specific line LINENUM in TMP, FC. */
-
-static void
-check_line (temp_source_file &tmp, file_cache &fc, int linenum)
-{
- char_span line = fc.get_source_line (tmp.get_filename (), linenum);
- int n;
- const char *b = line.get_buffer ();
- size_t l = line.length ();
- char buf[5];
- ASSERT_LT (l, 5);
- memcpy (buf, b, l);
- buf[l] = '\0';
- ASSERT_TRUE (sscanf (buf, "%d", &n) == 1);
- ASSERT_EQ (n, linenum);
-}
-
-/* Test file cache replacement. */
-
-static void
-test_replacement ()
-{
- const int maxline = 1000;
-
- char *vec = XNEWVEC (char, maxline * 5);
- char *p = vec;
- int i;
- for (i = 1; i <= maxline; i++)
- p += sprintf (p, "%d\n", i);
-
- temp_source_file tmp (SELFTEST_LOCATION, ".txt", vec);
- free (vec);
- file_cache fc;
-
- for (i = 2; i <= maxline; i++)
- {
- check_line (tmp, fc, i);
- check_line (tmp, fc, i - 1);
- if (i >= 10)
- check_line (tmp, fc, i - 9);
- if (i >= 350) /* Exceed the look behind cache. */
- check_line (tmp, fc, i - 300);
- }
- for (i = 5; i <= maxline; i += 100)
- check_line (tmp, fc, i);
- for (i = 1; i <= maxline; i++)
- check_line (tmp, fc, i);
-}
-
-/* Verify reading of input files (e.g. for caret-based diagnostics). */
-
-static void
-test_reading_source_line ()
-{
- /* Create a tempfile and write some text to it. */
- temp_source_file tmp (SELFTEST_LOCATION, ".txt",
- "01234567890123456789\n"
- "This is the test text\n"
- "This is the 3rd line");
- file_cache fc;
-
- /* Read back a specific line from the tempfile. */
- char_span source_line = fc.get_source_line (tmp.get_filename (), 3);
- ASSERT_TRUE (source_line);
- ASSERT_TRUE (source_line.get_buffer () != NULL);
- ASSERT_EQ (20, source_line.length ());
- ASSERT_TRUE (!strncmp ("This is the 3rd line",
- source_line.get_buffer (), source_line.length ()));
-
- source_line = fc.get_source_line (tmp.get_filename (), 2);
- ASSERT_TRUE (source_line);
- ASSERT_TRUE (source_line.get_buffer () != NULL);
- ASSERT_EQ (21, source_line.length ());
- ASSERT_TRUE (!strncmp ("This is the test text",
- source_line.get_buffer (), source_line.length ()));
-
- source_line = fc.get_source_line (tmp.get_filename (), 4);
- ASSERT_FALSE (source_line);
- ASSERT_TRUE (source_line.get_buffer () == NULL);
-}
-
-/* Verify reading from buffers (e.g. for sarif-replay). */
-
-static void
-test_reading_source_buffer ()
-{
- const char *text = ("01234567890123456789\n"
- "This is the test text\n"
- "This is the 3rd line");
- const char *filename = "foo.txt";
- file_cache fc;
- fc.add_buffered_content (filename, text, strlen (text));
-
- /* Read back a specific line from the tempfile. */
- char_span source_line = fc.get_source_line (filename, 3);
- ASSERT_TRUE (source_line);
- ASSERT_TRUE (source_line.get_buffer () != NULL);
- ASSERT_EQ (20, source_line.length ());
- ASSERT_TRUE (!strncmp ("This is the 3rd line",
- source_line.get_buffer (), source_line.length ()));
-
- source_line = fc.get_source_line (filename, 2);
- ASSERT_TRUE (source_line);
- ASSERT_TRUE (source_line.get_buffer () != NULL);
- ASSERT_EQ (21, source_line.length ());
- ASSERT_TRUE (!strncmp ("This is the test text",
- source_line.get_buffer (), source_line.length ()));
-
- source_line = fc.get_source_line (filename, 4);
- ASSERT_FALSE (source_line);
- ASSERT_TRUE (source_line.get_buffer () == NULL);
-}
-
/* Tests of lexing. */
/* Verify that token TOK from PARSER has cpp_token_as_text
@@ -2628,7 +1601,7 @@ public:
line_table_test m_ltt;
cpp_reader_ptr m_parser;
temp_source_file m_tempfile;
- file_cache m_file_cache;
+ diagnostics::file_cache m_file_cache;
string_concat_db m_concats;
bool m_implicitly_expect_EOF;
};
@@ -4356,10 +3329,6 @@ input_cc_tests ()
for_each_line_table_case (test_lexer_string_locations_raw_string_unterminated);
for_each_line_table_case (test_lexer_char_constants);
- test_reading_source_line ();
- test_reading_source_buffer ();
- test_replacement ();
-
test_line_offset_overflow ();
test_cpp_utf8 ();