There was an error in the way that we calculate the reference scope sequences that are used as the basis for assertions about changed ranges in randomized tests. The error caused some characters' scopes to not be checked. This corrects the reference implementation and fixes a previously uncaught bug in the implementation of `tree_path_get_changed_ranges`. Previously, when iterating over the old and new trees, we would only perform comparisons of visible nodes. This resulted in a failure to do any comparison for portions of the text in which there were trailing invisible child nodes (e.g. trailing `_line_break` nodes inside `statement` nodes in the JavaScript grammar). Now, we additionally perform comparisons at invisible leaf nodes, based on their lowest visible ancestor.
106 lines
3.7 KiB
C++
106 lines
3.7 KiB
C++
#include "./scope_sequence.h"
|
|
|
|
#include "bandit/bandit.h"
|
|
#include <sstream>
|
|
#include "helpers/stream_methods.h"
|
|
#include "helpers/point_helpers.h"
|
|
|
|
using std::string;
|
|
using std::cout;
|
|
|
|
static void append_text_to_scope_sequence(ScopeSequence *sequence,
|
|
ScopeStack *current_scopes,
|
|
const std::string &text,
|
|
size_t length) {
|
|
for (size_t i = 0; i < length; i++) {
|
|
string character(1, text[sequence->size()]);
|
|
sequence->push_back(*current_scopes);
|
|
sequence->back().push_back("'" + character + "'");
|
|
}
|
|
}
|
|
|
|
static void append_to_scope_sequence(ScopeSequence *sequence,
|
|
ScopeStack *current_scopes,
|
|
TSNode node, TSDocument *document,
|
|
const std::string &text) {
|
|
append_text_to_scope_sequence(
|
|
sequence, current_scopes, text, ts_node_start_byte(node) - sequence->size()
|
|
);
|
|
|
|
current_scopes->push_back(ts_node_type(node, document));
|
|
|
|
for (size_t i = 0, n = ts_node_child_count(node); i < n; i++) {
|
|
TSNode child = ts_node_child(node, i);
|
|
append_to_scope_sequence(sequence, current_scopes, child, document, text);
|
|
}
|
|
|
|
append_text_to_scope_sequence(
|
|
sequence, current_scopes, text, ts_node_end_byte(node) - sequence->size()
|
|
);
|
|
|
|
current_scopes->pop_back();
|
|
}
|
|
|
|
ScopeSequence build_scope_sequence(TSDocument *document, const std::string &text) {
|
|
ScopeSequence sequence;
|
|
ScopeStack current_scopes;
|
|
TSNode node = ts_document_root_node(document);
|
|
append_to_scope_sequence(&sequence, ¤t_scopes, node, document, text);
|
|
return sequence;
|
|
}
|
|
|
|
bool operator<=(const TSPoint &left, const TSPoint &right) {
|
|
if (left.row < right.row)
|
|
return true;
|
|
else if (left.row == right.row)
|
|
return left.column <= right.column;
|
|
else
|
|
return false;
|
|
}
|
|
|
|
void verify_changed_ranges(const ScopeSequence &old_sequence, const ScopeSequence &new_sequence,
|
|
const string &text, TSRange *ranges, size_t range_count) {
|
|
TSPoint current_position = {0, 0};
|
|
for (size_t i = 0; i < old_sequence.size(); i++) {
|
|
if (text[i] == '\n') {
|
|
current_position.row++;
|
|
current_position.column = 0;
|
|
continue;
|
|
}
|
|
|
|
const ScopeStack &old_scopes = old_sequence[i];
|
|
const ScopeStack &new_scopes = new_sequence[i];
|
|
if (old_scopes != new_scopes) {
|
|
bool found_containing_range = false;
|
|
for (size_t j = 0; j < range_count; j++) {
|
|
TSRange range = ranges[j];
|
|
if (range.start <= current_position && current_position <= range.end) {
|
|
found_containing_range = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!found_containing_range) {
|
|
std::stringstream message_stream;
|
|
message_stream << "Found changed scope outside of any invalidated range;\n";
|
|
message_stream << "Position: " << current_position << "\n";
|
|
message_stream << "Byte index: " << i << "\n";
|
|
size_t line_start_index = i - current_position.column;
|
|
size_t line_end_index = text.find_first_of('\n', i);
|
|
message_stream << "Line: " << text.substr(line_start_index, line_end_index - line_start_index) << "\n";
|
|
for (size_t j = 0; j < current_position.column + string("Line: ").size(); j++)
|
|
message_stream << " ";
|
|
message_stream << "^\n";
|
|
message_stream << "Old scopes: " << old_scopes << "\n";
|
|
message_stream << "New scopes: " << new_scopes << "\n";
|
|
message_stream << "Invalidated ranges:\n";
|
|
for (size_t j = 0; j < range_count; j++) {
|
|
message_stream << " " << ranges[j] << "\n";
|
|
}
|
|
Assert::Failure(message_stream.str());
|
|
}
|
|
}
|
|
|
|
current_position.column++;
|
|
}
|
|
}
|