diff --git a/common/ostream.h b/common/ostream.h index be984707af2d7..6ba004898875f 100644 --- a/common/ostream.h +++ b/common/ostream.h @@ -5,13 +5,14 @@ #ifndef CARBON_COMMON_OSTREAM_H_ #define CARBON_COMMON_OSTREAM_H_ +// Libraries should include this header instead of raw_ostream. + #include #include #include -#include "llvm/Support/raw_os_ostream.h" -// Libraries should include this header instead of raw_ostream. #include "llvm/Support/Compiler.h" +#include "llvm/Support/raw_os_ostream.h" #include "llvm/Support/raw_ostream.h" // IWYU pragma: export namespace Carbon { diff --git a/toolchain/check/BUILD b/toolchain/check/BUILD index d6a7b15da04de..1120c8f3511a1 100644 --- a/toolchain/check/BUILD +++ b/toolchain/check/BUILD @@ -20,6 +20,7 @@ cc_library( "convert.cpp", "decl_name_stack.cpp", "deduce.cpp", + "dump_id.cpp", "eval.cpp", "function.cpp", "generic.cpp", @@ -46,6 +47,7 @@ cc_library( "decl_name_stack.h", "deduce.h", "diagnostic_helpers.h", + "dump_id.h", "eval.h", "function.h", "generic.h", @@ -72,6 +74,7 @@ cc_library( "//common:array_stack", "//common:check", "//common:map", + "//common:ostream", "//common:vlog", "//toolchain/base:index_base", "//toolchain/base:kind_switch", diff --git a/toolchain/check/context.h b/toolchain/check/context.h index 42c76b1f15af7..15790696d1ff1 100644 --- a/toolchain/check/context.h +++ b/toolchain/check/context.h @@ -6,11 +6,13 @@ #define CARBON_TOOLCHAIN_CHECK_CONTEXT_H_ #include "common/map.h" +#include "common/ostream.h" #include "llvm/ADT/FoldingSet.h" #include "llvm/ADT/SmallVector.h" #include "toolchain/check/decl_introducer_state.h" #include "toolchain/check/decl_name_stack.h" #include "toolchain/check/diagnostic_helpers.h" +#include "toolchain/check/dump_id.h" #include "toolchain/check/generic_region_stack.h" #include "toolchain/check/global_init.h" #include "toolchain/check/inst_block_stack.h" @@ -483,10 +485,15 @@ class Context { } auto sem_ir() -> SemIR::File& { return *sem_ir_; } + auto sem_ir() const -> const SemIR::File& { return *sem_ir_; } - auto parse_tree() -> const Parse::Tree& { return sem_ir_->parse_tree(); } + auto parse_tree() const -> const Parse::Tree& { + return sem_ir_->parse_tree(); + } - auto tokens() -> const Lex::TokenizedBuffer& { return parse_tree().tokens(); } + auto tokens() const -> const Lex::TokenizedBuffer& { + return parse_tree().tokens(); + } auto node_stack() -> NodeStack& { return node_stack_; } @@ -604,6 +611,19 @@ class Context { return bind_name_cache_; } + // A set of DumpId() overloads that dump an object to stderr, useful for + // calling inside a debugger. + LLVM_DUMP_METHOD auto DumpId(Lex::TokenIndex token) const -> void { + tokens().DumpId(token); + } + LLVM_DUMP_METHOD auto DumpId(Parse::NodeId node_id) const -> void { + parse_tree().DumpId(node_id); + } + LLVM_DUMP_METHOD auto DumpId(SemIR::LocId loc_id) const -> void { + DumpIdImpl(*this, loc_id); + llvm::errs() << '\n'; + } + private: // A FoldingSet node for a type. class TypeNode : public llvm::FastFoldingSetNode { diff --git a/toolchain/check/dump_id.cpp b/toolchain/check/dump_id.cpp new file mode 100644 index 0000000000000..bbad053c018ba --- /dev/null +++ b/toolchain/check/dump_id.cpp @@ -0,0 +1,47 @@ +// Part of the Carbon Language project, under the Apache License v2.0 with LLVM +// Exceptions. See /LICENSE for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include "toolchain/check/dump_id.h" + +#include "common/check.h" +#include "common/ostream.h" +#include "toolchain/check/context.h" +#include "toolchain/lex/dump_id.h" +#include "toolchain/lex/tokenized_buffer.h" +#include "toolchain/parse/dump_id.h" +#include "toolchain/parse/tree.h" +#include "toolchain/sem_ir/file.h" + +namespace Carbon::Check { + +auto DumpIdImpl(const Context& context, SemIR::LocId loc_id) -> void { + if (!loc_id.is_valid()) { + llvm::errs() << "LocId(invalid)"; + return; + } + + if (loc_id.is_node_id()) { + auto token = context.parse_tree().node_token(loc_id.node_id()); + auto line = context.tokens().GetLineNumber(token); + auto col = context.tokens().GetColumnNumber(token); + const char* implicit = loc_id.is_implicit() ? " implicit" : ""; + llvm::errs() << "LocId("; + llvm::errs().write_escaped(context.sem_ir().filename()); + llvm::errs() << ":" << line << ":" << col << implicit << ")"; + } else { + CARBON_CHECK(loc_id.is_import_ir_inst_id()); + + auto import_ir_id = context.sem_ir() + .import_ir_insts() + .Get(loc_id.import_ir_inst_id()) + .ir_id; + const auto* import_file = + context.sem_ir().import_irs().Get(import_ir_id).sem_ir; + llvm::errs() << "LocId(import from \""; + llvm::errs().write_escaped(import_file->filename()); + llvm::errs() << "\")"; + } +} + +} // namespace Carbon::Check diff --git a/toolchain/check/dump_id.h b/toolchain/check/dump_id.h new file mode 100644 index 0000000000000..4f90606b2c3a8 --- /dev/null +++ b/toolchain/check/dump_id.h @@ -0,0 +1,18 @@ +// Part of the Carbon Language project, under the Apache License v2.0 with LLVM +// Exceptions. See /LICENSE for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#ifndef CARBON_TOOLCHAIN_CHECK_DUMP_ID_H_ +#define CARBON_TOOLCHAIN_CHECK_DUMP_ID_H_ + +#include "toolchain/sem_ir/ids.h" + +namespace Carbon::Check { + +class Context; + +auto DumpIdImpl(const Context& context, SemIR::LocId loc_id) -> void; + +} // namespace Carbon::Check + +#endif // CARBON_TOOLCHAIN_CHECK_DUMP_ID_H_ diff --git a/toolchain/lex/BUILD b/toolchain/lex/BUILD index 08e2f0bb0d5f7..7f24f76fd9853 100644 --- a/toolchain/lex/BUILD +++ b/toolchain/lex/BUILD @@ -209,8 +209,14 @@ cc_library( cc_library( name = "tokenized_buffer", - srcs = ["tokenized_buffer.cpp"], - hdrs = ["tokenized_buffer.h"], + srcs = [ + "dump_id.cpp", + "tokenized_buffer.cpp", + ], + hdrs = [ + "dump_id.h", + "tokenized_buffer.h", + ], deps = [ ":character_set", ":helpers", diff --git a/toolchain/lex/dump_id.cpp b/toolchain/lex/dump_id.cpp new file mode 100644 index 0000000000000..2310bbf8dd583 --- /dev/null +++ b/toolchain/lex/dump_id.cpp @@ -0,0 +1,29 @@ +// Part of the Carbon Language project, under the Apache License v2.0 with LLVM +// Exceptions. See /LICENSE for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include "toolchain/lex/dump_id.h" + +#include "common/ostream.h" +#include "toolchain/lex/tokenized_buffer.h" + +namespace Carbon::Lex { + +auto DumpIdImpl(const TokenizedBuffer& buffer, TokenIndex token) -> void { + if (!token.is_valid()) { + llvm::errs() << "TokenIndex(invalid)"; + return; + } + + auto kind = buffer.GetKind(token); + auto line = buffer.GetLineNumber(token); + auto col = buffer.GetColumnNumber(token); + + llvm::errs() << "TokenIndex(kind: "; + kind.Print(llvm::errs()); + llvm::errs() << ", loc: "; + llvm::errs().write_escaped(buffer.source().filename()); + llvm::errs() << ":" << line << ":" << col << ")"; +} + +} // namespace Carbon::Lex diff --git a/toolchain/lex/dump_id.h b/toolchain/lex/dump_id.h new file mode 100644 index 0000000000000..2b9d9600134ec --- /dev/null +++ b/toolchain/lex/dump_id.h @@ -0,0 +1,18 @@ +// Part of the Carbon Language project, under the Apache License v2.0 with LLVM +// Exceptions. See /LICENSE for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#ifndef CARBON_TOOLCHAIN_LEX_DUMP_ID_H_ +#define CARBON_TOOLCHAIN_LEX_DUMP_ID_H_ + +#include "toolchain/lex/token_index.h" + +namespace Carbon::Lex { + +class TokenizedBuffer; + +auto DumpIdImpl(const TokenizedBuffer& buffer, TokenIndex token) -> void; + +} // namespace Carbon::Lex + +#endif // CARBON_TOOLCHAIN_LEX_DUMP_ID_H_ diff --git a/toolchain/lex/tokenized_buffer.cpp b/toolchain/lex/tokenized_buffer.cpp index 6aec49a05cec7..acd7e9e987770 100644 --- a/toolchain/lex/tokenized_buffer.cpp +++ b/toolchain/lex/tokenized_buffer.cpp @@ -25,7 +25,7 @@ auto TokenizedBuffer::GetLine(TokenIndex token) const -> LineIndex { } auto TokenizedBuffer::GetLineNumber(TokenIndex token) const -> int { - return GetLineNumber(GetLine(token)); + return GetLine(token).index + 1; } auto TokenizedBuffer::GetColumnNumber(TokenIndex token) const -> int { @@ -162,10 +162,6 @@ auto TokenizedBuffer::IsRecoveryToken(TokenIndex token) const -> bool { return recovery_tokens_[token.index]; } -auto TokenizedBuffer::GetLineNumber(LineIndex line) const -> int { - return line.index + 1; -} - auto TokenizedBuffer::GetNextLine(LineIndex line) const -> LineIndex { LineIndex next(line.index + 1); CARBON_DCHECK(static_cast(next.index) < line_infos_.size()); @@ -262,7 +258,7 @@ auto TokenizedBuffer::PrintToken(llvm::raw_ostream& output_stream, llvm::right_justify( llvm::formatv("'{0}'", token_info.kind().name()).str(), widths.kind + 2), - llvm::format_decimal(GetLineNumber(GetLine(token)), widths.line), + llvm::format_decimal(GetLineNumber(token), widths.line), llvm::format_decimal(GetColumnNumber(token), widths.column), llvm::format_decimal(GetIndentColumnNumber(line_index), widths.indent), token_text); diff --git a/toolchain/lex/tokenized_buffer.h b/toolchain/lex/tokenized_buffer.h index 1822a7c25823c..0b7d082848941 100644 --- a/toolchain/lex/tokenized_buffer.h +++ b/toolchain/lex/tokenized_buffer.h @@ -18,6 +18,7 @@ #include "toolchain/base/mem_usage.h" #include "toolchain/base/shared_value_stores.h" #include "toolchain/diagnostics/diagnostic_emitter.h" +#include "toolchain/lex/dump_id.h" #include "toolchain/lex/token_index.h" #include "toolchain/lex/token_kind.h" #include "toolchain/source/source_buffer.h" @@ -156,9 +157,6 @@ class TokenizedBuffer : public Printable { // For example, a closing paren inserted to match an unmatched paren. auto IsRecoveryToken(TokenIndex token) const -> bool; - // Returns the 1-based line number. - auto GetLineNumber(LineIndex line) const -> int; - // Returns the 1-based indentation column number. auto GetIndentColumnNumber(LineIndex line) const -> int; @@ -219,6 +217,13 @@ class TokenizedBuffer : public Printable { auto source() const -> const SourceBuffer& { return *source_; } + // A set of DumpId() overloads that dump an object to stderr, useful for + // calling inside a debugger. + LLVM_DUMP_METHOD auto DumpId(Lex::TokenIndex token) const -> void { + DumpIdImpl(*this, token); + llvm::errs() << '\n'; + } + private: friend class Lexer; friend class TokenDiagnosticConverter; diff --git a/toolchain/parse/BUILD b/toolchain/parse/BUILD index 310ff296eeca1..baf43a7703791 100644 --- a/toolchain/parse/BUILD +++ b/toolchain/parse/BUILD @@ -113,11 +113,13 @@ cc_library( cc_library( name = "tree", srcs = [ + "dump_id.cpp", "extract.cpp", "tree.cpp", "tree_and_subtrees.cpp", ], hdrs = [ + "dump_id.h", "tree.h", "tree_and_subtrees.h", ], diff --git a/toolchain/parse/context.cpp b/toolchain/parse/context.cpp index dbcd5c6b14338..fd0b6384cb2a3 100644 --- a/toolchain/parse/context.cpp +++ b/toolchain/parse/context.cpp @@ -481,7 +481,7 @@ auto Context::PrintForStackDump(llvm::raw_ostream& output) const -> void { auto Context::PrintTokenForStackDump(llvm::raw_ostream& output, Lex::TokenIndex token) const -> void { - output << " @ " << tokens_->GetLineNumber(tokens_->GetLine(token)) << ":" + output << " @ " << tokens_->GetLineNumber(token) << ":" << tokens_->GetColumnNumber(token) << ": token " << token << " : " << tokens_->GetKind(token) << "\n"; } diff --git a/toolchain/parse/dump_id.cpp b/toolchain/parse/dump_id.cpp new file mode 100644 index 0000000000000..e705c0b6ae76a --- /dev/null +++ b/toolchain/parse/dump_id.cpp @@ -0,0 +1,29 @@ +// Part of the Carbon Language project, under the Apache License v2.0 with LLVM +// Exceptions. See /LICENSE for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include "toolchain/parse/dump_id.h" + +#include "common/ostream.h" +#include "toolchain/lex/dump_id.h" +#include "toolchain/parse/tree.h" + +namespace Carbon::Parse { + +auto DumpIdImpl(const Tree& tree, NodeId node_id) -> void { + if (!node_id.is_valid()) { + llvm::errs() << "NodeId(invalid)"; + return; + } + + auto kind = tree.node_kind(node_id); + auto token = tree.node_token(node_id); + + llvm::errs() << "NodeId(kind: "; + kind.Print(llvm::errs()); + llvm::errs() << ", token: "; + Lex::DumpIdImpl(tree.tokens(), token); + llvm::errs() << ")"; +} + +} // namespace Carbon::Parse diff --git a/toolchain/parse/dump_id.h b/toolchain/parse/dump_id.h new file mode 100644 index 0000000000000..cd9b0ecff34b4 --- /dev/null +++ b/toolchain/parse/dump_id.h @@ -0,0 +1,18 @@ +// Part of the Carbon Language project, under the Apache License v2.0 with LLVM +// Exceptions. See /LICENSE for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#ifndef CARBON_TOOLCHAIN_PARSE_DUMP_ID_H_ +#define CARBON_TOOLCHAIN_PARSE_DUMP_ID_H_ + +#include "toolchain/parse/node_ids.h" + +namespace Carbon::Parse { + +class Tree; + +auto DumpIdImpl(const Tree& tree, NodeId node_id) -> void; + +} // namespace Carbon::Parse + +#endif // CARBON_TOOLCHAIN_PARSE_DUMP_ID_H_ diff --git a/toolchain/parse/tree.h b/toolchain/parse/tree.h index 7cbdb25e3afa9..9a261c7538713 100644 --- a/toolchain/parse/tree.h +++ b/toolchain/parse/tree.h @@ -15,6 +15,7 @@ #include "llvm/ADT/iterator_range.h" #include "toolchain/base/value_store.h" #include "toolchain/lex/tokenized_buffer.h" +#include "toolchain/parse/dump_id.h" #include "toolchain/parse/node_ids.h" #include "toolchain/parse/node_kind.h" #include "toolchain/parse/typed_nodes.h" @@ -192,6 +193,16 @@ class Tree : public Printable { auto tokens() const -> const Lex::TokenizedBuffer& { return *tokens_; } + // A set of DumpId() overloads that dump an object to stderr, useful for + // calling inside a debugger. + LLVM_DUMP_METHOD auto DumpId(Lex::TokenIndex token) const -> void { + tokens().DumpId(token); + } + LLVM_DUMP_METHOD auto DumpId(Parse::NodeId node_id) const -> void { + DumpIdImpl(*this, node_id); + llvm::errs() << '\n'; + } + private: friend class Context; friend class TypedNodesTestPeer;