From 1d982367704d1ab504aedae06e02d5edb40c83aa Mon Sep 17 00:00:00 2001 From: Ben Clayton Date: Thu, 18 Feb 2021 21:40:19 +0000 Subject: [PATCH] Source: Restructure Source::File Add Source::FileContent to hold the file source content and per-line data. Have Source hold an optional pointer to a FileContent, and add a file_path field. This allows us to kill the `FreeInternalCompilerErrors()` filth as we're now able to construct Sources that hold a file path without file content. Change-Id: I03556795d7d4161c3d34cef32cb685c45ad04a3d Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/42026 Reviewed-by: Austin Eng Reviewed-by: dan sinclair Commit-Queue: Ben Clayton --- src/clone_context_test.cc | 7 --- src/debug.cc | 43 +----------------- src/debug.h | 6 --- src/debug_test.cc | 7 --- src/diagnostic/formatter.cc | 14 +++--- src/reader/wgsl/lexer.cc | 48 ++++++++++---------- src/reader/wgsl/lexer.h | 11 +++-- src/reader/wgsl/lexer_test.cc | 83 ++++++++++++++++++---------------- src/reader/wgsl/parser_impl.cc | 4 +- src/reader/wgsl/token_test.cc | 3 -- src/source.cc | 7 +-- src/source.h | 66 +++++++++++++++++++++------ src/test_main.cc | 2 - 13 files changed, 142 insertions(+), 159 deletions(-) diff --git a/src/clone_context_test.cc b/src/clone_context_test.cc index fc7b73a0e3..1a97fb827d 100644 --- a/src/clone_context_test.cc +++ b/src/clone_context_test.cc @@ -280,13 +280,6 @@ TEST(CloneContext, CloneWithReplace_WithNotANode) { ctx.Clone(original_root); }, "internal compiler error"); - - // Ensure that this test does not leak memory. - // This will be automatically called by main() in src/test_main.cc, but - // chromium uses it's own test entry point. - // TODO(ben-clayton): Add this call to the end of Chromium's main(), and we - // can remove this call. - FreeInternalCompilerErrors(); } } // namespace diff --git a/src/debug.cc b/src/debug.cc index 01305ec182..2ac9ce7274 100644 --- a/src/debug.cc +++ b/src/debug.cc @@ -27,45 +27,8 @@ namespace { InternalCompilerErrorReporter* ice_reporter = nullptr; -/// Note - this class is _not_ thread safe. If we have multiple internal -/// compiler errors occurring at the same time on different threads, then -/// we're in serious trouble. -class SourceFileToDelete { - static SourceFileToDelete* instance; - - public: - /// Adds file to the list that will be deleted on call to Free() - static void Add(Source::File* file) { - if (!instance) { - instance = new SourceFileToDelete(); - } - instance->files.emplace_back(file); - } - - /// Free deletes all the source files added by calls to Add() and then this - /// SourceFileToDelete object. - static void Free() { - if (instance) { - for (auto* file : instance->files) { - delete file; - } - delete instance; - instance = nullptr; - } - } - - private: - std::vector files; -}; - -SourceFileToDelete* SourceFileToDelete::instance = nullptr; - } // namespace -void FreeInternalCompilerErrors() { - SourceFileToDelete::Free(); -} - void SetInternalCompilerErrorReporter(InternalCompilerErrorReporter* reporter) { ice_reporter = reporter; } @@ -76,11 +39,7 @@ InternalCompilerError::InternalCompilerError(const char* file, : file_(file), line_(line), diagnostics_(diagnostics) {} InternalCompilerError::~InternalCompilerError() { - auto* file = new Source::File(file_, ""); - - SourceFileToDelete::Add(file); - - Source source{Source::Range{Source::Location{line_}}, file}; + Source source{Source::Range{Source::Location{line_}}, file_}; diagnostics_.add_ice(msg_.str(), source); if (ice_reporter) { diff --git a/src/debug.h b/src/debug.h index 56649fdb2f..80c597fd00 100644 --- a/src/debug.h +++ b/src/debug.h @@ -27,12 +27,6 @@ namespace tint { /// Function type used for registering an internal compiler error reporter using InternalCompilerErrorReporter = void(const diag::List&); -/// Frees any memory allocated for reporting internal compiler errors. -/// Must only be called on application termination. -/// If an internal compiler error is raised and this function is not called, -/// then memory will leak. -void FreeInternalCompilerErrors(); - /// Sets the global error reporter to be called in case of internal compiler /// errors. /// @param reporter the error reporter diff --git a/src/debug_test.cc b/src/debug_test.cc index 5b9df293c2..45e8a1f2f9 100644 --- a/src/debug_test.cc +++ b/src/debug_test.cc @@ -26,13 +26,6 @@ TEST(DebugTest, Unreachable) { TINT_UNREACHABLE(diagnostics); }, "internal compiler error"); - - // Ensure that this test does not leak memory. - // This will be automatically called by main() in src/test_main.cc, but - // chromium uses it's own test entry point. - // TODO(ben-clayton): Add this call to the end of Chromium's main(), and we - // can remove this call. - FreeInternalCompilerErrors(); } } // namespace diff --git a/src/diagnostic/formatter.cc b/src/diagnostic/formatter.cc index 4e96d2b9f7..4acecab420 100644 --- a/src/diagnostic/formatter.cc +++ b/src/diagnostic/formatter.cc @@ -160,12 +160,12 @@ void Formatter::format(const Diagnostic& diag, State& state) const { std::vector prefix; prefix.reserve(6); - if (style_.print_file && src.file != nullptr && !src.file->path.empty()) { + if (style_.print_file && !src.file_path.empty()) { if (rng.begin.line > 0) { - prefix.emplace_back(TextAndColor{src.file->path + ":" + to_str(rng.begin), + prefix.emplace_back(TextAndColor{src.file_path + ":" + to_str(rng.begin), Color::kDefault}); } else { - prefix.emplace_back(TextAndColor{src.file->path, Color::kDefault}); + prefix.emplace_back(TextAndColor{src.file_path, Color::kDefault}); } } else if (rng.begin.line > 0) { prefix.emplace_back(TextAndColor{to_str(rng.begin), Color::kDefault}); @@ -208,15 +208,15 @@ void Formatter::format(const Diagnostic& diag, State& state) const { } state << diag.message; - if (style_.print_line && src.file != nullptr && rng.begin.line > 0) { + if (style_.print_line && src.file_content != nullptr && rng.begin.line > 0) { state.newline(); state.set_style({Color::kDefault, false}); for (size_t line = rng.begin.line; line <= rng.end.line; line++) { - if (line < src.file->lines.size() + 1) { - auto len = src.file->lines[line - 1].size(); + if (line < src.file_content->lines.size() + 1) { + auto len = src.file_content->lines[line - 1].size(); - state << src.file->lines[line - 1]; + state << src.file_content->lines[line - 1]; state.newline(); state.set_style({Color::kCyan, false}); diff --git a/src/reader/wgsl/lexer.cc b/src/reader/wgsl/lexer.cc index 181f46c048..2939e66f5f 100644 --- a/src/reader/wgsl/lexer.cc +++ b/src/reader/wgsl/lexer.cc @@ -32,9 +32,10 @@ bool is_whitespace(char c) { } // namespace -Lexer::Lexer(Source::File const* file) - : file_(file), - len_(static_cast(file->content.size())), +Lexer::Lexer(const std::string& file_path, const Source::FileContent* content) + : file_path_(file_path), + content_(content), + len_(static_cast(content->data.size())), location_{1, 1} {} Lexer::~Lexer() = default; @@ -82,7 +83,8 @@ Token Lexer::next() { Source Lexer::begin_source() const { Source src{}; - src.file = file_; + src.file_path = file_path_; + src.file_content = content_; src.range.begin = location_; src.range.end = location_; return src; @@ -115,13 +117,13 @@ bool Lexer::is_hex(char ch) const { bool Lexer::matches(size_t pos, const std::string& substr) { if (pos >= len_) return false; - return file_->content.substr(pos, substr.size()) == substr; + return content_->data.substr(pos, substr.size()) == substr; } void Lexer::skip_whitespace() { for (;;) { auto pos = pos_; - while (!is_eof() && is_whitespace(file_->content[pos_])) { + while (!is_eof() && is_whitespace(content_->data[pos_])) { if (matches(pos_, "\n")) { pos_++; location_.line++; @@ -162,7 +164,7 @@ Token Lexer::try_float() { if (matches(end, "-")) { end++; } - while (end < len_ && is_digit(file_->content[end])) { + while (end < len_ && is_digit(content_->data[end])) { end++; } @@ -171,7 +173,7 @@ Token Lexer::try_float() { } end++; - while (end < len_ && is_digit(file_->content[end])) { + while (end < len_ && is_digit(content_->data[end])) { end++; } @@ -183,7 +185,7 @@ Token Lexer::try_float() { } auto exp_start = end; - while (end < len_ && isdigit(file_->content[end])) { + while (end < len_ && isdigit(content_->data[end])) { end++; } @@ -192,7 +194,7 @@ Token Lexer::try_float() { return {}; } - auto str = file_->content.substr(start, end - start); + auto str = content_->data.substr(start, end - start); if (str == "." || str == "-.") return {}; @@ -201,7 +203,7 @@ Token Lexer::try_float() { end_source(source); - auto res = strtod(file_->content.c_str() + start, nullptr); + auto res = strtod(content_->data.c_str() + start, nullptr); // This handles if the number is a really small in the exponent if (res > 0 && res < static_cast(std::numeric_limits::min())) { return {Token::Type::kError, source, "f32 (" + str + " too small"}; @@ -221,13 +223,13 @@ Token Lexer::build_token_from_int_if_possible(Source source, size_t start, size_t end, int32_t base) { - auto res = strtoll(file_->content.c_str() + start, nullptr, base); + auto res = strtoll(content_->data.c_str() + start, nullptr, base); if (matches(pos_, "u")) { if (static_cast(res) > static_cast(std::numeric_limits::max())) { return { Token::Type::kError, source, - "u32 (" + file_->content.substr(start, end - start) + ") too large"}; + "u32 (" + content_->data.substr(start, end - start) + ") too large"}; } pos_ += 1; location_.column += 1; @@ -238,12 +240,12 @@ Token Lexer::build_token_from_int_if_possible(Source source, if (res < static_cast(std::numeric_limits::min())) { return { Token::Type::kError, source, - "i32 (" + file_->content.substr(start, end - start) + ") too small"}; + "i32 (" + content_->data.substr(start, end - start) + ") too small"}; } if (res > static_cast(std::numeric_limits::max())) { return { Token::Type::kError, source, - "i32 (" + file_->content.substr(start, end - start) + ") too large"}; + "i32 (" + content_->data.substr(start, end - start) + ") too large"}; } end_source(source); return {source, static_cast(res)}; @@ -263,7 +265,7 @@ Token Lexer::try_hex_integer() { } end += 2; - while (!is_eof() && is_hex(file_->content[end])) { + while (!is_eof() && is_hex(content_->data[end])) { end += 1; } @@ -282,18 +284,18 @@ Token Lexer::try_integer() { if (matches(end, "-")) { end++; } - if (end >= len_ || !is_digit(file_->content[end])) { + if (end >= len_ || !is_digit(content_->data[end])) { return {}; } auto first = end; - while (end < len_ && is_digit(file_->content[end])) { + while (end < len_ && is_digit(content_->data[end])) { end++; } // If the first digit is a zero this must only be zero as leading zeros // are not allowed. - if (file_->content[first] == '0' && (end - first != 1)) + if (content_->data[first] == '0' && (end - first != 1)) return {}; pos_ = end; @@ -304,19 +306,19 @@ Token Lexer::try_integer() { Token Lexer::try_ident() { // Must begin with an a-zA-Z_ - if (!is_alpha(file_->content[pos_])) { + if (!is_alpha(content_->data[pos_])) { return {}; } auto source = begin_source(); auto s = pos_; - while (!is_eof() && is_alphanum(file_->content[pos_])) { + while (!is_eof() && is_alphanum(content_->data[pos_])) { pos_++; location_.column++; } - auto str = file_->content.substr(s, pos_ - s); + auto str = content_->data.substr(s, pos_ - s); auto t = check_reserved(source, str); if (!t.IsUninitialized()) { return t; @@ -352,7 +354,7 @@ Token Lexer::try_string() { end_source(source); return {Token::Type::kStringLiteral, source, - file_->content.substr(start, end - start)}; + content_->data.substr(start, end - start)}; } Token Lexer::try_punctuation() { diff --git a/src/reader/wgsl/lexer.h b/src/reader/wgsl/lexer.h index ef1a839b86..1fd550a2d2 100644 --- a/src/reader/wgsl/lexer.h +++ b/src/reader/wgsl/lexer.h @@ -28,8 +28,9 @@ namespace wgsl { class Lexer { public: /// Creates a new Lexer - /// @param file the input file to parse - explicit Lexer(Source::File const* file); + /// @param file_path the path to the file containing the source + /// @param content the source content + Lexer(const std::string& file_path, const Source::FileContent* content); ~Lexer(); /// Returns the next token in the input stream @@ -63,8 +64,10 @@ class Lexer { bool is_alphanum(char ch) const; bool matches(size_t pos, const std::string& substr); - /// The source to parse - Source::File const* file_; + /// The source file path + std::string const file_path_; + /// The source file content + Source::FileContent const* const content_; /// The length of the input uint32_t len_ = 0; /// The current position within the input diff --git a/src/reader/wgsl/lexer_test.cc b/src/reader/wgsl/lexer_test.cc index 7a4a49d83a..fe6d9eb392 100644 --- a/src/reader/wgsl/lexer_test.cc +++ b/src/reader/wgsl/lexer_test.cc @@ -26,15 +26,15 @@ namespace { using LexerTest = testing::Test; TEST_F(LexerTest, Empty) { - Source::File file("test.wgsl", ""); - Lexer l(&file); + Source::FileContent content(""); + Lexer l("test.wgsl", &content); auto t = l.next(); EXPECT_TRUE(t.IsEof()); } TEST_F(LexerTest, Skips_Whitespace) { - Source::File file("test.wgsl", "\t\r\n\t ident\t\n\t \r "); - Lexer l(&file); + Source::FileContent content("\t\r\n\t ident\t\n\t \r "); + Lexer l("test.wgsl", &content); auto t = l.next(); EXPECT_TRUE(t.IsIdentifier()); @@ -49,11 +49,11 @@ TEST_F(LexerTest, Skips_Whitespace) { } TEST_F(LexerTest, Skips_Comments) { - Source::File file("test.wgsl", R"(//starts with comment + Source::FileContent content(R"(//starts with comment ident1 //ends with comment // blank line ident2)"); - Lexer l(&file); + Lexer l("test.wgsl", &content); auto t = l.next(); EXPECT_TRUE(t.IsIdentifier()); @@ -76,8 +76,8 @@ ident1 //ends with comment } TEST_F(LexerTest, StringTest_Parse) { - Source::File file("test.wgsl", R"(id "this is string content" id2)"); - Lexer l(&file); + Source::FileContent content(R"(id "this is string content" id2)"); + Lexer l("test.wgsl", &content); auto t = l.next(); EXPECT_TRUE(t.IsIdentifier()); @@ -105,8 +105,8 @@ TEST_F(LexerTest, StringTest_Parse) { } TEST_F(LexerTest, StringTest_Unterminated) { - Source::File file("test.wgsl", R"(id "this is string content)"); - Lexer l(&file); + Source::FileContent content(R"(id "this is string content)"); + Lexer l("test.wgsl", &content); auto t = l.next(); EXPECT_TRUE(t.IsIdentifier()); @@ -139,8 +139,8 @@ inline std::ostream& operator<<(std::ostream& out, FloatData data) { using FloatTest = testing::TestWithParam; TEST_P(FloatTest, Parse) { auto params = GetParam(); - Source::File file("test.wgsl", params.input); - Lexer l(&file); + Source::FileContent content(params.input); + Lexer l("test.wgsl", &content); auto t = l.next(); EXPECT_TRUE(t.IsFloatLiteral()); @@ -175,8 +175,8 @@ INSTANTIATE_TEST_SUITE_P(LexerTest, using FloatTest_Invalid = testing::TestWithParam; TEST_P(FloatTest_Invalid, Handles) { - Source::File file("test.wgsl", GetParam()); - Lexer l(&file); + Source::FileContent content(GetParam()); + Lexer l("test.wgsl", &content); auto t = l.next(); EXPECT_FALSE(t.IsFloatLiteral()); @@ -193,8 +193,8 @@ INSTANTIATE_TEST_SUITE_P(LexerTest, using IdentifierTest = testing::TestWithParam; TEST_P(IdentifierTest, Parse) { - Source::File file("test.wgsl", GetParam()); - Lexer l(&file); + Source::FileContent content(GetParam()); + Lexer l("test.wgsl", &content); auto t = l.next(); EXPECT_TRUE(t.IsIdentifier()); @@ -210,8 +210,8 @@ INSTANTIATE_TEST_SUITE_P( testing::Values("test01", "_test_", "test_", "_test", "_01", "_test01")); TEST_F(LexerTest, IdentifierTest_DoesNotStartWithNumber) { - Source::File file("test.wgsl", "01test"); - Lexer l(&file); + Source::FileContent content("01test"); + Lexer l("test.wgsl", &content); auto t = l.next(); EXPECT_FALSE(t.IsIdentifier()); @@ -229,8 +229,8 @@ inline std::ostream& operator<<(std::ostream& out, HexSignedIntData data) { using IntegerTest_HexSigned = testing::TestWithParam; TEST_P(IntegerTest_HexSigned, Matches) { auto params = GetParam(); - Source::File file("test.wgsl", params.input); - Lexer l(&file); + Source::FileContent content(params.input); + Lexer l("test.wgsl", &content); auto t = l.next(); EXPECT_TRUE(t.IsSintLiteral()); @@ -252,16 +252,18 @@ INSTANTIATE_TEST_SUITE_P( HexSignedIntData{"0x7FFFFFFF", std::numeric_limits::max()})); TEST_F(LexerTest, IntegerTest_HexSignedTooLarge) { - Source::File file("test.wgsl", "0x80000000"); - Lexer l(&file); + Source::FileContent content("0x80000000"); + Lexer l("test.wgsl", &content); + auto t = l.next(); ASSERT_TRUE(t.IsError()); EXPECT_EQ(t.to_str(), "i32 (0x80000000) too large"); } TEST_F(LexerTest, IntegerTest_HexSignedTooSmall) { - Source::File file("test.wgsl", "-0x8000000F"); - Lexer l(&file); + Source::FileContent content("-0x8000000F"); + Lexer l("test.wgsl", &content); + auto t = l.next(); ASSERT_TRUE(t.IsError()); EXPECT_EQ(t.to_str(), "i32 (-0x8000000F) too small"); @@ -278,8 +280,8 @@ inline std::ostream& operator<<(std::ostream& out, HexUnsignedIntData data) { using IntegerTest_HexUnsigned = testing::TestWithParam; TEST_P(IntegerTest_HexUnsigned, Matches) { auto params = GetParam(); - Source::File file("test.wgsl", params.input); - Lexer l(&file); + Source::FileContent content(params.input); + Lexer l("test.wgsl", &content); auto t = l.next(); EXPECT_TRUE(t.IsUintLiteral()); @@ -304,8 +306,9 @@ INSTANTIATE_TEST_SUITE_P( std::numeric_limits::max()})); TEST_F(LexerTest, IntegerTest_HexUnsignedTooLarge) { - Source::File file("test.wgsl", "0xffffffffffu"); - Lexer l(&file); + Source::FileContent content("0xffffffffffu"); + Lexer l("test.wgsl", &content); + auto t = l.next(); ASSERT_TRUE(t.IsError()); EXPECT_EQ(t.to_str(), "u32 (0xffffffffff) too large"); @@ -322,8 +325,8 @@ inline std::ostream& operator<<(std::ostream& out, UnsignedIntData data) { using IntegerTest_Unsigned = testing::TestWithParam; TEST_P(IntegerTest_Unsigned, Matches) { auto params = GetParam(); - Source::File file("test.wgsl", params.input); - Lexer l(&file); + Source::FileContent content(params.input); + Lexer l("test.wgsl", &content); auto t = l.next(); EXPECT_TRUE(t.IsUintLiteral()); @@ -351,8 +354,8 @@ inline std::ostream& operator<<(std::ostream& out, SignedIntData data) { using IntegerTest_Signed = testing::TestWithParam; TEST_P(IntegerTest_Signed, Matches) { auto params = GetParam(); - Source::File file("test.wgsl", params.input); - Lexer l(&file); + Source::FileContent content(params.input); + Lexer l("test.wgsl", &content); auto t = l.next(); EXPECT_TRUE(t.IsSintLiteral()); @@ -374,8 +377,8 @@ INSTANTIATE_TEST_SUITE_P( using IntegerTest_Invalid = testing::TestWithParam; TEST_P(IntegerTest_Invalid, Parses) { - Source::File file("test.wgsl", GetParam()); - Lexer l(&file); + Source::FileContent content(GetParam()); + Lexer l("test.wgsl", &content); auto t = l.next(); EXPECT_FALSE(t.IsSintLiteral()); @@ -396,8 +399,8 @@ inline std::ostream& operator<<(std::ostream& out, TokenData data) { using PunctuationTest = testing::TestWithParam; TEST_P(PunctuationTest, Parses) { auto params = GetParam(); - Source::File file("test.wgsl", params.input); - Lexer l(&file); + Source::FileContent content(params.input); + Lexer l("test.wgsl", &content); auto t = l.next(); EXPECT_TRUE(t.Is(params.type)); @@ -450,8 +453,8 @@ INSTANTIATE_TEST_SUITE_P( using KeywordTest = testing::TestWithParam; TEST_P(KeywordTest, Parses) { auto params = GetParam(); - Source::File file("test.wgsl", params.input); - Lexer l(&file); + Source::FileContent content(params.input); + Lexer l("test.wgsl", &content); auto t = l.next(); EXPECT_TRUE(t.Is(params.type)) << params.input; @@ -582,8 +585,8 @@ INSTANTIATE_TEST_SUITE_P( using KeywordTest_Reserved = testing::TestWithParam; TEST_P(KeywordTest_Reserved, Parses) { auto* keyword = GetParam(); - Source::File file("test.wgsl", keyword); - Lexer l(&file); + Source::FileContent content(keyword); + Lexer l("test.wgsl", &content); auto t = l.next(); EXPECT_TRUE(t.IsReservedKeyword()); diff --git a/src/reader/wgsl/parser_impl.cc b/src/reader/wgsl/parser_impl.cc index 0000298120..727603ad65 100644 --- a/src/reader/wgsl/parser_impl.cc +++ b/src/reader/wgsl/parser_impl.cc @@ -216,7 +216,7 @@ ParserImpl::FunctionHeader& ParserImpl::FunctionHeader::operator=( const FunctionHeader& rhs) = default; ParserImpl::ParserImpl(Source::File const* file) - : lexer_(std::make_unique(file)) {} + : lexer_(std::make_unique(file->path, &file->content)) {} ParserImpl::~ParserImpl() = default; @@ -294,7 +294,7 @@ void ParserImpl::translation_unit() { } expect_global_decl(); if (diags_.error_count() >= max_errors_) { - add_error(Source{{}, p.source().file}, + add_error(Source{{}, p.source().file_path}, "stopping after " + std::to_string(max_errors_) + " errors"); break; } diff --git a/src/reader/wgsl/token_test.cc b/src/reader/wgsl/token_test.cc index ae56acc4b4..24552f3067 100644 --- a/src/reader/wgsl/token_test.cc +++ b/src/reader/wgsl/token_test.cc @@ -67,9 +67,7 @@ TEST_F(TokenTest, ReturnsMaxU32) { } TEST_F(TokenTest, Source) { - Source::File file("", ""); Source src; - src.file = &file; src.range.begin = Source::Location{3, 9}; src.range.end = Source::Location{4, 3}; @@ -78,7 +76,6 @@ TEST_F(TokenTest, Source) { EXPECT_EQ(t.source().range.begin.column, 9u); EXPECT_EQ(t.source().range.end.line, 4u); EXPECT_EQ(t.source().range.end.column, 3u); - EXPECT_EQ(t.source().file, &file); } } // namespace diff --git a/src/source.cc b/src/source.cc index bd45fd5c34..f4a72365ad 100644 --- a/src/source.cc +++ b/src/source.cc @@ -30,9 +30,10 @@ std::vector split_lines(const std::string& str) { } } // namespace -Source::File::File(const std::string& file_path, - const std::string& file_content) - : path(file_path), content(file_content), lines(split_lines(content)) {} +Source::FileContent::FileContent(const std::string& body) + : data(body), lines(split_lines(body)) {} + +Source::FileContent::~FileContent() = default; Source::File::~File() = default; diff --git a/src/source.h b/src/source.h index a6e78300ec..b77fa022d0 100644 --- a/src/source.h +++ b/src/source.h @@ -18,6 +18,7 @@ #include +#include #include #include @@ -26,21 +27,37 @@ namespace tint { /// Source describes a range of characters within a source file. class Source { public: + /// FileContent describes the content of a source file. + class FileContent { + public: + /// Constructs the FileContent with the given file content. + /// @param data the file contents + explicit FileContent(const std::string& data); + + /// Destructor + ~FileContent(); + + /// un-split file content + const std::string data; + /// #data split by lines + const std::vector lines; + }; + /// File describes a source file, including path and content. class File { public: /// Constructs the File with the given file path and content. - /// @param file_path the path for this file - /// @param file_content the file contents - File(const std::string& file_path, const std::string& file_content); + /// @param p the path for this file + /// @param c the file contents + inline File(const std::string& p, const std::string& c) + : path(p), content(c) {} + ~File(); /// file path (optional) const std::string path; /// file content - const std::string content; - /// #content split by lines - const std::vector lines; + const FileContent content; }; /// Location holds a 1-based line and column index. @@ -74,7 +91,7 @@ class Source { }; /// Constructs the Source with an zero initialized Range and null File. - inline Source() = default; + inline Source() : range() {} /// Constructs the Source with the Range `rng` and a null File /// @param rng the source range @@ -84,17 +101,40 @@ class Source { /// @param loc the start and end location for the source range inline explicit Source(const Location& loc) : range(Range(loc)) {} - /// Constructs the Source with the Range `rng` and File `f` + /// Constructs the Source with the Range `rng` and File `file` /// @param rng the source range - /// @param f the source file - inline Source(const Range& rng, File const* f) : range(rng), file(f) {} + /// @param file the source file + inline Source(const Range& rng, File const* file) + : range(rng), file_path(file->path), file_content(&file->content) {} - /// range is the span of text this source refers to in #file + /// Constructs the Source with the Range `rng`, file path `path` and content + /// `content` + /// @param rng the source range + /// @param path the source file path + /// @param content the source file content + inline Source(const Range& rng, + const std::string& path, + FileContent* content = nullptr) + : range(rng), file_path(path), file_content(content) {} + + /// range is the span of text this source refers to in #file_path Range range; - /// file is the source file this source refers to - File const* file = nullptr; + /// file is the optional file path this source refers to + std::string file_path; + /// file is the optional source content this source refers to + const FileContent* file_content = nullptr; }; +/// Writes the Source::FileContent to the std::ostream. +/// @param out the std::ostream to write to +/// @param content the file content to write +/// @returns out so calls can be chained +inline std::ostream& operator<<(std::ostream& out, + const Source::FileContent& content) { + out << content.data; + return out; +} + } // namespace tint #endif // SRC_SOURCE_H_ diff --git a/src/test_main.cc b/src/test_main.cc index 5fca747383..7a8b394f2f 100644 --- a/src/test_main.cc +++ b/src/test_main.cc @@ -32,7 +32,5 @@ int main(int argc, char** argv) { auto res = RUN_ALL_TESTS(); - tint::FreeInternalCompilerErrors(); - return res; }