1112 lines
36 KiB
C++
1112 lines
36 KiB
C++
#include <iomanip>
|
|
#include <algorithm>
|
|
#include "./debug_printer.hpp"
|
|
|
|
namespace lsp::language::symbol::debug
|
|
{
|
|
// ==================== PrintOptions ====================
|
|
|
|
PrintOptions PrintOptions::Default()
|
|
{
|
|
return PrintOptions{};
|
|
}
|
|
|
|
PrintOptions PrintOptions::Compact()
|
|
{
|
|
PrintOptions opts;
|
|
opts.compact_mode = true;
|
|
opts.show_details = false;
|
|
opts.show_children = false;
|
|
opts.indent_size = 1;
|
|
return opts;
|
|
}
|
|
|
|
PrintOptions PrintOptions::Verbose()
|
|
{
|
|
PrintOptions opts;
|
|
opts.show_details = true;
|
|
opts.show_children = true;
|
|
opts.show_references = true;
|
|
return opts;
|
|
}
|
|
|
|
PrintOptions PrintOptions::NoColor()
|
|
{
|
|
PrintOptions opts;
|
|
opts.use_color = false;
|
|
return opts;
|
|
}
|
|
|
|
// ==================== Statistics ====================
|
|
|
|
void Statistics::Compute(const SymbolTable& table)
|
|
{
|
|
auto all_defs = table.GetAllDefinitions();
|
|
total_symbols = all_defs.size();
|
|
|
|
symbol_counts.clear();
|
|
|
|
for (const auto* def : all_defs)
|
|
{
|
|
symbol_counts[def->kind]++;
|
|
|
|
auto refs = table.GetReferences(def->id);
|
|
if (refs && !refs->empty())
|
|
{
|
|
symbols_with_refs++;
|
|
total_references += refs->size();
|
|
|
|
if (refs->size() > max_references)
|
|
{
|
|
max_references = refs->size();
|
|
most_referenced = def->id;
|
|
}
|
|
}
|
|
}
|
|
|
|
// 统计作用域
|
|
const auto& all_scopes = table.GetScopeManager().GetAllScopes();
|
|
total_scopes = all_scopes.size();
|
|
|
|
for (const auto& [id, info] : all_scopes)
|
|
{
|
|
scope_counts[info.kind]++;
|
|
}
|
|
}
|
|
|
|
void Statistics::Print(std::ostream& os, bool use_color) const
|
|
{
|
|
auto color = [use_color](const char* code) {
|
|
return use_color ? code : "";
|
|
};
|
|
|
|
os << "\n";
|
|
os << color(Color::Bold) << "╔════════════════════════════════════════════════════════════╗\n";
|
|
os << "║ STATISTICS ║\n";
|
|
os << "╚════════════════════════════════════════════════════════════╝"
|
|
<< color(Color::Reset) << "\n\n";
|
|
|
|
// 总体统计
|
|
os << color(Color::Bold) << "Overview:" << color(Color::Reset) << "\n";
|
|
os << " Total Symbols: " << color(Color::Cyan) << total_symbols << color(Color::Reset) << "\n";
|
|
os << " Total Scopes: " << color(Color::Cyan) << total_scopes << color(Color::Reset) << "\n";
|
|
os << " Total References: " << color(Color::Cyan) << total_references << color(Color::Reset) << "\n";
|
|
os << " Symbols w/ Refs: " << color(Color::Green) << symbols_with_refs << color(Color::Reset) << "\n";
|
|
|
|
if (most_referenced != kInvalidSymbolId)
|
|
{
|
|
os << " Most Referenced: " << color(Color::Yellow) << "ID=" << most_referenced
|
|
<< " (" << max_references << " refs)" << color(Color::Reset) << "\n";
|
|
}
|
|
|
|
os << "\n";
|
|
|
|
// 符号类型分布
|
|
os << color(Color::Bold) << "Symbol Distribution:" << color(Color::Reset) << "\n";
|
|
|
|
struct KindInfo
|
|
{
|
|
SymbolKind kind;
|
|
const char* name;
|
|
const char* icon;
|
|
};
|
|
|
|
KindInfo kinds[] = {
|
|
{ SymbolKind::Module, "Modules", "📦" },
|
|
{ SymbolKind::Namespace, "Namespace", "🗃️" },
|
|
{ SymbolKind::Class, "Classes", "🏛️" },
|
|
{ SymbolKind::Interface, "Interfaces", "🔌" },
|
|
{ SymbolKind::Struct, "Structs", "📐" },
|
|
{ SymbolKind::Enum, "Enums", "🔢" },
|
|
{ SymbolKind::Function, "Functions", "🎄" },
|
|
{ SymbolKind::Method, "Methods", "🪀" },
|
|
{ SymbolKind::Constructor, "Constructors", "🔨" },
|
|
{ SymbolKind::Property, "Properties", "📋" },
|
|
{ SymbolKind::Field, "Fields", "📌" },
|
|
{ SymbolKind::Variable, "Variables", "📊" },
|
|
{ SymbolKind::Constant, "Constants", "🔒" }
|
|
};
|
|
|
|
for (const auto& kind_info : kinds)
|
|
{
|
|
auto it = symbol_counts.find(kind_info.kind);
|
|
if (it != symbol_counts.end() && it->second > 0)
|
|
{
|
|
os << " " << kind_info.icon << " "
|
|
<< std::setw(15) << std::left << kind_info.name
|
|
<< ": " << color(Color::BrightBlue) << std::setw(5) << std::right
|
|
<< it->second << color(Color::Reset) << "\n";
|
|
}
|
|
}
|
|
|
|
os << "\n";
|
|
|
|
// 作用域分布
|
|
if (!scope_counts.empty())
|
|
{
|
|
os << color(Color::Bold) << "Scope Distribution:" << color(Color::Reset) << "\n";
|
|
|
|
struct ScopeKindInfo
|
|
{
|
|
ScopeKind kind;
|
|
const char* name;
|
|
};
|
|
|
|
ScopeKindInfo scope_kinds[] = {
|
|
{ ScopeKind::Global, "Global" },
|
|
{ ScopeKind::Unit, "Unit" },
|
|
{ ScopeKind::Class, "Class" },
|
|
{ ScopeKind::Function, "Function" },
|
|
{ ScopeKind::Block, "Block" }
|
|
};
|
|
|
|
for (const auto& scope_info : scope_kinds)
|
|
{
|
|
auto it = scope_counts.find(scope_info.kind);
|
|
if (it != scope_counts.end() && it->second > 0)
|
|
{
|
|
os << " " << std::setw(15) << std::left << scope_info.name
|
|
<< ": " << color(Color::BrightMagenta) << std::setw(5) << std::right
|
|
<< it->second << color(Color::Reset) << "\n";
|
|
}
|
|
}
|
|
|
|
os << "\n";
|
|
}
|
|
}
|
|
|
|
// ==================== DebugPrinter ====================
|
|
|
|
DebugPrinter::DebugPrinter(const SymbolTable& table, const PrintOptions& options) : table_(table), options_(options)
|
|
{
|
|
stats_.Compute(table);
|
|
}
|
|
|
|
// ===== 顶层打印 =====
|
|
|
|
void DebugPrinter::PrintAll(std::ostream& os)
|
|
{
|
|
PrintHeader("SYMBOL TABLE DUMP", os);
|
|
|
|
PrintSubHeader("1. Overview", os);
|
|
PrintOverview(os);
|
|
|
|
PrintSubHeader("2. Symbol Definitions", os);
|
|
PrintSymbolList(os);
|
|
|
|
PrintSubHeader("3. Scope Hierarchy", os);
|
|
PrintScopeHierarchy(os);
|
|
|
|
PrintSubHeader("4. References", os);
|
|
PrintAllReferences(os);
|
|
|
|
PrintSubHeader("5. Inheritance", os);
|
|
PrintAllInheritance(os);
|
|
|
|
PrintSubHeader("6. Call Graph", os);
|
|
PrintAllCalls(os);
|
|
|
|
PrintSubHeader("7. Statistics", os);
|
|
PrintStatistics(os);
|
|
}
|
|
|
|
void DebugPrinter::PrintOverview(std::ostream& os)
|
|
{
|
|
auto all_defs = table_.GetAllDefinitions();
|
|
|
|
os << "\n";
|
|
os << Color(Color::Bold) << "Symbol Table Overview" << Color(Color::Reset) << "\n";
|
|
os << " Total Symbols: " << Color(Color::Cyan) << all_defs.size() << Color(Color::Reset) << "\n";
|
|
os << " Total Scopes: " << Color(Color::Cyan) << stats_.total_scopes << Color(Color::Reset) << "\n";
|
|
os << "\n";
|
|
|
|
// 按类型分组显示
|
|
std::unordered_map<SymbolKind, std::vector<const SymbolDefinition*>> by_kind;
|
|
for (const auto* def : all_defs)
|
|
{
|
|
by_kind[def->kind].push_back(def);
|
|
}
|
|
|
|
// 定义固定的类型顺序
|
|
std::vector<SymbolKind> kind_order = {
|
|
SymbolKind::Module,
|
|
SymbolKind::Class,
|
|
SymbolKind::Interface,
|
|
SymbolKind::Struct,
|
|
SymbolKind::Enum,
|
|
SymbolKind::Function,
|
|
SymbolKind::Method,
|
|
SymbolKind::Constructor,
|
|
SymbolKind::Property,
|
|
SymbolKind::Field,
|
|
SymbolKind::Variable,
|
|
SymbolKind::Constant
|
|
};
|
|
|
|
// 按固定顺序遍历类型
|
|
for (const auto& kind : kind_order)
|
|
{
|
|
auto it = by_kind.find(kind);
|
|
if (it == by_kind.end() || it->second.empty())
|
|
continue;
|
|
|
|
auto& symbols = it->second;
|
|
|
|
// 按位置排序同类型的符号
|
|
std::sort(symbols.begin(), symbols.end(), [](const SymbolDefinition* a, const SymbolDefinition* b) {
|
|
if (a->location.start_line != b->location.start_line)
|
|
return a->location.start_line < b->location.start_line;
|
|
if (a->location.start_column != b->location.start_column)
|
|
return a->location.start_column < b->location.start_column;
|
|
return true;
|
|
});
|
|
|
|
os << " " << SymbolIcon(kind) << " "
|
|
<< Color(Color::Bold) << FormatSymbolKind(kind)
|
|
<< Color(Color::Reset) << " (" << symbols.size() << ")\n";
|
|
|
|
if (!options_.compact_mode)
|
|
{
|
|
for (const auto* sym : symbols)
|
|
{
|
|
os << " " << Color(Color::Dim) << "• " << Color(Color::Reset)
|
|
<< ColorizeSymbolName(sym->name, kind);
|
|
|
|
if (options_.show_location)
|
|
{
|
|
os << " " << Color(Color::Dim)
|
|
<< FormatLocation(sym->location) << Color(Color::Reset);
|
|
}
|
|
|
|
os << "\n";
|
|
}
|
|
}
|
|
}
|
|
|
|
os << "\n";
|
|
}
|
|
|
|
void DebugPrinter::PrintStatistics(std::ostream& os)
|
|
{
|
|
stats_.Print(os, options_.use_color);
|
|
}
|
|
|
|
// ===== 符号打印 =====
|
|
|
|
void DebugPrinter::PrintSymbol(SymbolId id, std::ostream& os, int depth)
|
|
{
|
|
const auto* def = table_.GetDefinition(id);
|
|
if (!def)
|
|
return;
|
|
|
|
os << Indent(depth);
|
|
os << SymbolIcon(def->kind) << " ";
|
|
os << ColorizeSymbolName(def->name, def->kind);
|
|
|
|
if (options_.show_location)
|
|
{
|
|
os << " " << Color(Color::Dim) << FormatLocation(def->location) << Color(Color::Reset);
|
|
}
|
|
|
|
os << "\n";
|
|
|
|
if (options_.show_details && !options_.compact_mode)
|
|
{
|
|
os << Indent(depth + 1) << Color(Color::Dim) << "Kind: " << Color(Color::Reset)
|
|
<< FormatSymbolKind(def->kind) << "\n";
|
|
|
|
if (def->type_hint)
|
|
{
|
|
os << Indent(depth + 1) << Color(Color::Dim) << "Type: " << Color(Color::Reset)
|
|
<< *def->type_hint << "\n";
|
|
}
|
|
|
|
if (!def->detail.empty())
|
|
{
|
|
os << Indent(depth + 1) << Color(Color::Dim) << "Detail: " << Color(Color::Reset)
|
|
<< def->detail << "\n";
|
|
}
|
|
|
|
if (def->access_modifier)
|
|
{
|
|
const char* access_str = "public";
|
|
switch (*def->access_modifier)
|
|
{
|
|
case ast::AccessModifier::kPublic:
|
|
access_str = "public";
|
|
break;
|
|
case ast::AccessModifier::kProtected:
|
|
access_str = "protected";
|
|
break;
|
|
case ast::AccessModifier::kPrivate:
|
|
access_str = "private";
|
|
break;
|
|
}
|
|
os << Indent(depth + 1) << Color(Color::Dim) << "Access: " << Color(Color::Reset)
|
|
<< access_str << "\n";
|
|
}
|
|
}
|
|
}
|
|
|
|
void DebugPrinter::PrintSymbolTree(SymbolId id, std::ostream& os, int depth)
|
|
{
|
|
if (options_.max_depth >= 0 && depth > options_.max_depth)
|
|
return;
|
|
|
|
PrintSymbol(id, os, depth);
|
|
|
|
if (options_.show_children)
|
|
{
|
|
auto children = table_.GetChildren(id);
|
|
|
|
// 按位置排序子符号
|
|
std::vector<SymbolId> sorted_children(children.begin(), children.end());
|
|
std::sort(sorted_children.begin(), sorted_children.end(), [this](SymbolId a, SymbolId b) {
|
|
const auto* def_a = table_.GetDefinition(a);
|
|
const auto* def_b = table_.GetDefinition(b);
|
|
if (!def_a || !def_b)
|
|
return false;
|
|
|
|
if (def_a->location.start_line != def_b->location.start_line)
|
|
return def_a->location.start_line < def_b->location.start_line;
|
|
if (def_a->location.start_column != def_b->location.start_column)
|
|
return def_a->location.start_column < def_b->location.start_column;
|
|
return true;
|
|
});
|
|
|
|
for (SymbolId child_id : sorted_children)
|
|
{
|
|
PrintSymbolTree(child_id, os, depth + 1);
|
|
}
|
|
}
|
|
}
|
|
|
|
void DebugPrinter::PrintSymbolList(std::ostream& os)
|
|
{
|
|
auto all_defs = table_.GetAllDefinitions();
|
|
|
|
if (all_defs.empty())
|
|
{
|
|
os << Color(Color::Dim) << " (no symbols)\n"
|
|
<< Color(Color::Reset);
|
|
return;
|
|
}
|
|
|
|
// 按层级排序(顶层优先)
|
|
std::vector<const SymbolDefinition*> top_level;
|
|
for (const auto* def : all_defs)
|
|
{
|
|
if (!def->parent_id)
|
|
top_level.push_back(def);
|
|
}
|
|
|
|
// 按位置排序顶层符号
|
|
std::sort(top_level.begin(), top_level.end(), [](const SymbolDefinition* a, const SymbolDefinition* b) {
|
|
if (a->location.start_line != b->location.start_line)
|
|
return a->location.start_line < b->location.start_line;
|
|
if (a->location.start_column != b->location.start_column)
|
|
return a->location.start_column < b->location.start_column;
|
|
return true;
|
|
});
|
|
|
|
for (const auto* def : top_level)
|
|
{
|
|
PrintSymbolTree(def->id, os, 0);
|
|
}
|
|
}
|
|
|
|
void DebugPrinter::PrintSymbolsByKind(SymbolKind kind, std::ostream& os)
|
|
{
|
|
auto all_defs = table_.GetAllDefinitions();
|
|
|
|
os << "\n"
|
|
<< Color(Color::Bold) << FormatSymbolKind(kind) << "s:" << Color(Color::Reset) << "\n\n";
|
|
|
|
// 收集并排序符号
|
|
std::vector<const SymbolDefinition*> symbols;
|
|
for (const auto* def : all_defs)
|
|
{
|
|
if (def->kind == kind)
|
|
{
|
|
symbols.push_back(def);
|
|
}
|
|
}
|
|
|
|
if (symbols.empty())
|
|
{
|
|
os << Color(Color::Dim) << " (none)\n"
|
|
<< Color(Color::Reset);
|
|
}
|
|
else
|
|
{
|
|
// 按位置排序
|
|
std::sort(symbols.begin(), symbols.end(), [](const SymbolDefinition* a, const SymbolDefinition* b) {
|
|
if (a->location.start_line != b->location.start_line)
|
|
return a->location.start_line < b->location.start_line;
|
|
if (a->location.start_column != b->location.start_column)
|
|
return a->location.start_column < b->location.start_column;
|
|
return true;
|
|
});
|
|
|
|
for (const auto* def : symbols)
|
|
{
|
|
PrintSymbol(def->id, os, 0);
|
|
}
|
|
}
|
|
|
|
os << "\n";
|
|
}
|
|
|
|
// ===== 作用域打印 =====
|
|
|
|
void DebugPrinter::PrintScope(ScopeId id, std::ostream& os, int depth)
|
|
{
|
|
const auto* info = table_.GetScopeManager().GetScopeInfo(id);
|
|
if (!info)
|
|
return;
|
|
|
|
os << Indent(depth);
|
|
os << "🔷 " << Color(Color::Bold) << FormatScopeKind(info->kind) << Color(Color::Reset);
|
|
os << " (id=" << id << ")";
|
|
|
|
if (options_.show_location)
|
|
{
|
|
os << " " << Color(Color::Dim) << FormatLocation(info->range) << Color(Color::Reset);
|
|
}
|
|
|
|
os << "\n";
|
|
|
|
if (!options_.compact_mode && !info->symbols.empty())
|
|
{
|
|
os << Indent(depth + 1) << Color(Color::Dim) << "Symbols: " << info->symbols.size() << Color(Color::Reset) << "\n";
|
|
|
|
// 收集符号并按位置排序
|
|
std::vector<std::pair<std::string, SymbolId>> sorted_symbols(
|
|
info->symbols.begin(), info->symbols.end());
|
|
|
|
std::sort(sorted_symbols.begin(), sorted_symbols.end(), [this](const auto& a, const auto& b) {
|
|
// 按符号定义的位置排序
|
|
const auto* def_a = table_.GetDefinition(a.second);
|
|
const auto* def_b = table_.GetDefinition(b.second);
|
|
if (!def_a || !def_b)
|
|
return false;
|
|
|
|
if (def_a->location.start_line != def_b->location.start_line)
|
|
return def_a->location.start_line < def_b->location.start_line;
|
|
if (def_a->location.start_column != def_b->location.start_column)
|
|
return def_a->location.start_column < def_b->location.start_column;
|
|
return true;
|
|
});
|
|
|
|
for (const auto& [name, sym_id] : sorted_symbols)
|
|
{
|
|
os << Indent(depth + 2) << "• " << name << "\n";
|
|
}
|
|
}
|
|
}
|
|
|
|
void DebugPrinter::PrintScopeTree(ScopeId id, std::ostream& os, int depth)
|
|
{
|
|
if (options_.max_depth >= 0 && depth > options_.max_depth)
|
|
return;
|
|
|
|
PrintScope(id, os, depth);
|
|
|
|
// 查找并收集子作用域
|
|
const auto& all_scopes = table_.GetScopeManager().GetAllScopes();
|
|
|
|
std::vector<std::pair<ScopeId, const ScopeInfo*>> children;
|
|
for (const auto& [child_id, info] : all_scopes)
|
|
{
|
|
if (info.parent_scope_id && *info.parent_scope_id == id)
|
|
{
|
|
children.push_back({ child_id, &info });
|
|
}
|
|
}
|
|
|
|
// 按位置排序子作用域
|
|
std::sort(children.begin(), children.end(), [](const auto& a, const auto& b) {
|
|
if (a.second->range.start_line != b.second->range.start_line)
|
|
return a.second->range.start_line < b.second->range.start_line;
|
|
if (a.second->range.start_column != b.second->range.start_column)
|
|
return a.second->range.start_column < b.second->range.start_column;
|
|
return true;
|
|
});
|
|
|
|
// 递归打印子作用域
|
|
for (const auto& [child_id, info] : children)
|
|
{
|
|
PrintScopeTree(child_id, os, depth + 1);
|
|
}
|
|
}
|
|
|
|
void DebugPrinter::PrintScopeHierarchy(std::ostream& os)
|
|
{
|
|
ScopeId global_scope = table_.GetGlobalScope();
|
|
if (global_scope == kInvalidScopeId)
|
|
{
|
|
os << Color(Color::Dim) << " (no scopes)\n"
|
|
<< Color(Color::Reset);
|
|
return;
|
|
}
|
|
|
|
PrintScopeTree(global_scope, os, 0);
|
|
}
|
|
|
|
// ===== 关系打印 =====
|
|
|
|
void DebugPrinter::PrintReferences(SymbolId id, std::ostream& os)
|
|
{
|
|
const auto* def = table_.GetDefinition(id);
|
|
if (!def)
|
|
return;
|
|
|
|
os << "\n"
|
|
<< Color(Color::Bold) << "References for: " << def->name << Color(Color::Reset) << "\n";
|
|
|
|
auto refs = table_.GetReferences(id);
|
|
if (!refs || refs->empty())
|
|
{
|
|
os << Color(Color::Dim) << " (no references)\n"
|
|
<< Color(Color::Reset);
|
|
return;
|
|
}
|
|
|
|
os << " Total: " << refs->size() << "\n\n";
|
|
|
|
for (const auto& ref : *refs)
|
|
{
|
|
os << " ";
|
|
|
|
if (ref.is_definition)
|
|
os << Color(Color::Green) << "[DEF]" << Color(Color::Reset) << " ";
|
|
else if (ref.is_write)
|
|
os << Color(Color::Yellow) << "[WRITE]" << Color(Color::Reset) << " ";
|
|
else
|
|
os << Color(Color::Cyan) << "[READ]" << Color(Color::Reset) << " ";
|
|
|
|
os << FormatLocation(ref.location) << "\n";
|
|
}
|
|
|
|
os << "\n";
|
|
}
|
|
|
|
void DebugPrinter::PrintInheritance(SymbolId class_id, std::ostream& os)
|
|
{
|
|
const auto* def = table_.GetDefinition(class_id);
|
|
if (!def || def->kind != SymbolKind::Class)
|
|
return;
|
|
|
|
os << "\n"
|
|
<< Color(Color::Bold) << "Inheritance for: " << def->name << Color(Color::Reset) << "\n\n";
|
|
|
|
// 基类
|
|
auto bases = table_.GetBaseClasses(class_id);
|
|
if (bases && !bases->empty())
|
|
{
|
|
os << " " << Color(Color::Green) << "Base Classes:" << Color(Color::Reset) << "\n";
|
|
for (SymbolId base_id : *bases)
|
|
{
|
|
const auto* base_def = table_.GetDefinition(base_id);
|
|
if (base_def)
|
|
{
|
|
os << " ↑ " << base_def->name << "\n";
|
|
}
|
|
}
|
|
}
|
|
|
|
// 派生类
|
|
auto derived = table_.GetDerivedClasses(class_id);
|
|
if (derived && !derived->empty())
|
|
{
|
|
os << " " << Color(Color::Yellow) << "Derived Classes:" << Color(Color::Reset) << "\n";
|
|
for (SymbolId derived_id : *derived)
|
|
{
|
|
const auto* derived_def = table_.GetDefinition(derived_id);
|
|
if (derived_def)
|
|
{
|
|
os << " ↓ " << derived_def->name << "\n";
|
|
}
|
|
}
|
|
}
|
|
|
|
os << "\n";
|
|
}
|
|
|
|
void DebugPrinter::PrintCallGraph(SymbolId function_id, std::ostream& os)
|
|
{
|
|
const auto* def = table_.GetDefinition(function_id);
|
|
if (!def)
|
|
return;
|
|
|
|
os << "\n"
|
|
<< Color(Color::Bold) << "Call Graph for: " << def->name << Color(Color::Reset) << "\n\n";
|
|
|
|
// 调用者
|
|
auto callers = table_.GetCallers(function_id);
|
|
if (callers && !callers->empty())
|
|
{
|
|
os << " " << Color(Color::Green) << "Called by:" << Color(Color::Reset) << "\n";
|
|
for (const auto& rel : *callers)
|
|
{
|
|
const auto* caller_def = table_.GetDefinition(rel.caller);
|
|
if (caller_def)
|
|
{
|
|
os << " ← " << caller_def->name
|
|
<< " " << Color(Color::Dim) << FormatLocation(rel.call_location) << Color(Color::Reset) << "\n";
|
|
}
|
|
}
|
|
}
|
|
|
|
// 被调用的
|
|
auto callees = table_.GetCallees(function_id);
|
|
if (callees && !callees->empty())
|
|
{
|
|
os << " " << Color(Color::Yellow) << "Calls:" << Color(Color::Reset) << "\n";
|
|
for (const auto& rel : *callees)
|
|
{
|
|
const auto* callee_def = table_.GetDefinition(rel.callee);
|
|
if (callee_def)
|
|
{
|
|
os << " → " << callee_def->name
|
|
<< " " << Color(Color::Dim) << FormatLocation(rel.call_location) << Color(Color::Reset) << "\n";
|
|
}
|
|
}
|
|
}
|
|
|
|
os << "\n";
|
|
}
|
|
|
|
void DebugPrinter::PrintAllReferences(std::ostream& os)
|
|
{
|
|
auto all_defs = table_.GetAllDefinitions();
|
|
|
|
// 按位置排序
|
|
std::vector<const SymbolDefinition*> sorted_defs(all_defs.begin(), all_defs.end());
|
|
std::sort(sorted_defs.begin(), sorted_defs.end(), [](const SymbolDefinition* a, const SymbolDefinition* b) {
|
|
if (a->location.start_line != b->location.start_line)
|
|
return a->location.start_line < b->location.start_line;
|
|
if (a->location.start_column != b->location.start_column)
|
|
return a->location.start_column < b->location.start_column;
|
|
return true;
|
|
});
|
|
|
|
for (const auto* def : sorted_defs)
|
|
{
|
|
auto refs = table_.GetReferences(def->id);
|
|
if (refs && refs->size() > 1) // >1 因为定义本身算一个引用
|
|
{
|
|
PrintReferences(def->id, os);
|
|
}
|
|
}
|
|
}
|
|
|
|
void DebugPrinter::PrintAllInheritance(std::ostream& os)
|
|
{
|
|
auto all_defs = table_.GetAllDefinitions();
|
|
|
|
// 按位置排序
|
|
std::vector<const SymbolDefinition*> sorted_defs(all_defs.begin(), all_defs.end());
|
|
std::sort(sorted_defs.begin(), sorted_defs.end(), [](const SymbolDefinition* a, const SymbolDefinition* b) {
|
|
if (a->location.start_line != b->location.start_line)
|
|
return a->location.start_line < b->location.start_line;
|
|
if (a->location.start_column != b->location.start_column)
|
|
return a->location.start_column < b->location.start_column;
|
|
return true;
|
|
});
|
|
|
|
bool found = false;
|
|
for (const auto* def : sorted_defs)
|
|
{
|
|
if (def->kind == SymbolKind::Class)
|
|
{
|
|
auto bases = table_.GetBaseClasses(def->id);
|
|
auto derived = table_.GetDerivedClasses(def->id);
|
|
|
|
if ((bases && !bases->empty()) || (derived && !derived->empty()))
|
|
{
|
|
PrintInheritance(def->id, os);
|
|
found = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!found)
|
|
{
|
|
os << Color(Color::Dim) << " (no inheritance relationships)\n"
|
|
<< Color(Color::Reset);
|
|
}
|
|
}
|
|
|
|
void DebugPrinter::PrintAllCalls(std::ostream& os)
|
|
{
|
|
auto all_defs = table_.GetAllDefinitions();
|
|
|
|
// 按位置排序
|
|
std::vector<const SymbolDefinition*> sorted_defs(all_defs.begin(), all_defs.end());
|
|
std::sort(sorted_defs.begin(), sorted_defs.end(), [](const SymbolDefinition* a, const SymbolDefinition* b) {
|
|
if (a->location.start_line != b->location.start_line)
|
|
return a->location.start_line < b->location.start_line;
|
|
if (a->location.start_column != b->location.start_column)
|
|
return a->location.start_column < b->location.start_column;
|
|
return true;
|
|
});
|
|
|
|
bool found = false;
|
|
for (const auto* def : sorted_defs)
|
|
{
|
|
if (def->kind == SymbolKind::Function || def->kind == SymbolKind::Method)
|
|
{
|
|
auto callers = table_.GetCallers(def->id);
|
|
auto callees = table_.GetCallees(def->id);
|
|
|
|
if ((callers && !callers->empty()) || (callees && !callees->empty()))
|
|
{
|
|
PrintCallGraph(def->id, os);
|
|
found = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!found)
|
|
{
|
|
os << Color(Color::Dim) << " (no call relationships)\n"
|
|
<< Color(Color::Reset);
|
|
}
|
|
}
|
|
|
|
// ===== 搜索和查询 =====
|
|
|
|
void DebugPrinter::FindAndPrint(const std::string& name, std::ostream& os)
|
|
{
|
|
auto symbols = table_.FindSymbolsByName(name);
|
|
|
|
os << "\n"
|
|
<< Color(Color::Bold) << "Search results for: '" << name << "'" << Color(Color::Reset) << "\n";
|
|
os << "Found " << symbols.size() << " symbol(s)\n\n";
|
|
|
|
if (symbols.empty())
|
|
{
|
|
os << Color(Color::Dim) << " (no matches)\n"
|
|
<< Color(Color::Reset);
|
|
return;
|
|
}
|
|
|
|
// 按位置排序结果
|
|
std::vector<SymbolId> sorted_symbols(symbols.begin(), symbols.end());
|
|
std::sort(sorted_symbols.begin(), sorted_symbols.end(), [this](SymbolId a, SymbolId b) {
|
|
const auto* def_a = table_.GetDefinition(a);
|
|
const auto* def_b = table_.GetDefinition(b);
|
|
if (!def_a || !def_b)
|
|
return false;
|
|
|
|
if (def_a->location.start_line != def_b->location.start_line)
|
|
return def_a->location.start_line < def_b->location.start_line;
|
|
if (def_a->location.start_column != def_b->location.start_column)
|
|
return def_a->location.start_column < def_b->location.start_column;
|
|
return true;
|
|
});
|
|
|
|
for (SymbolId id : sorted_symbols)
|
|
{
|
|
const auto* def = table_.GetDefinition(id);
|
|
if (!def)
|
|
continue;
|
|
|
|
PrintSymbol(id, os, 0);
|
|
|
|
if (options_.show_references)
|
|
{
|
|
PrintReferences(id, os);
|
|
}
|
|
|
|
os << "\n";
|
|
}
|
|
}
|
|
|
|
void DebugPrinter::FindAtLocation(const ast::Location& loc, std::ostream& os)
|
|
{
|
|
os << "\n"
|
|
<< Color(Color::Bold) << "Symbols at location: "
|
|
<< FormatLocation(loc) << Color(Color::Reset) << "\n\n";
|
|
|
|
// 查找符号
|
|
auto symbol_id = table_.FindSymbolAt(loc);
|
|
if (symbol_id)
|
|
{
|
|
os << "Symbol: ";
|
|
PrintSymbol(*symbol_id, os, 0);
|
|
}
|
|
else
|
|
{
|
|
os << "Symbol: " << Color(Color::Dim) << "(none)\n"
|
|
<< Color(Color::Reset);
|
|
}
|
|
|
|
// 查找作用域
|
|
auto scope_id = table_.FindScopeAt(loc);
|
|
if (scope_id)
|
|
{
|
|
os << "Scope: ";
|
|
PrintScope(*scope_id, os, 0);
|
|
}
|
|
else
|
|
{
|
|
os << "Scope: " << Color(Color::Dim) << "(none)\n"
|
|
<< Color(Color::Reset);
|
|
}
|
|
|
|
// 查找引用
|
|
auto ref_id = table_.FindReferenceAt(loc);
|
|
if (ref_id)
|
|
{
|
|
os << "Reference to: ";
|
|
PrintSymbol(*ref_id, os, 0);
|
|
}
|
|
|
|
os << "\n";
|
|
}
|
|
|
|
// ===== 辅助方法 =====
|
|
|
|
std::string DebugPrinter::Indent(int depth) const
|
|
{
|
|
return std::string(depth * options_.indent_size, ' ');
|
|
}
|
|
|
|
std::string DebugPrinter::ColorizeSymbolKind(SymbolKind kind) const
|
|
{
|
|
if (!options_.use_color)
|
|
return "";
|
|
|
|
switch (kind)
|
|
{
|
|
case SymbolKind::Module:
|
|
return Color::BrightMagenta;
|
|
case SymbolKind::Class:
|
|
return Color::BrightYellow;
|
|
case SymbolKind::Function:
|
|
return Color::BrightBlue;
|
|
case SymbolKind::Method:
|
|
return Color::BrightCyan;
|
|
case SymbolKind::Constructor:
|
|
return Color::BrightGreen;
|
|
case SymbolKind::Interface:
|
|
return Color::BrightMagenta;
|
|
case SymbolKind::Struct:
|
|
return Color::BrightYellow;
|
|
case SymbolKind::Enum:
|
|
return Color::BrightCyan;
|
|
case SymbolKind::Property:
|
|
return Color::Magenta;
|
|
case SymbolKind::Field:
|
|
return Color::Yellow;
|
|
case SymbolKind::Variable:
|
|
return Color::White;
|
|
case SymbolKind::Constant:
|
|
return Color::BrightRed;
|
|
default:
|
|
return Color::Reset;
|
|
}
|
|
}
|
|
|
|
std::string DebugPrinter::ColorizeSymbolName(const std::string& name, SymbolKind kind) const
|
|
{
|
|
if (!options_.use_color)
|
|
return name;
|
|
return std::string(ColorizeSymbolKind(kind)) + name + Color::Reset;
|
|
}
|
|
|
|
std::string DebugPrinter::FormatLocation(const ast::Location& loc) const
|
|
{
|
|
std::ostringstream oss;
|
|
oss << "[" << loc.start_line << ":" << loc.start_column
|
|
<< "-" << loc.end_line << ":" << loc.end_column << "]";
|
|
return oss.str();
|
|
}
|
|
|
|
std::string DebugPrinter::FormatSymbolKind(SymbolKind kind) const
|
|
{
|
|
switch (kind)
|
|
{
|
|
case SymbolKind::Module:
|
|
return "Module";
|
|
case SymbolKind::Namespace:
|
|
return "Namespace";
|
|
case SymbolKind::Class:
|
|
return "Class";
|
|
case SymbolKind::Interface:
|
|
return "Interface";
|
|
case SymbolKind::Struct:
|
|
return "Struct";
|
|
case SymbolKind::Enum:
|
|
return "Enum";
|
|
case SymbolKind::Function:
|
|
return "Function";
|
|
case SymbolKind::Method:
|
|
return "Method";
|
|
case SymbolKind::Constructor:
|
|
return "Constructor";
|
|
case SymbolKind::Property:
|
|
return "Property";
|
|
case SymbolKind::Field:
|
|
return "Field";
|
|
case SymbolKind::Variable:
|
|
return "Variable";
|
|
case SymbolKind::Constant:
|
|
return "Constant";
|
|
default:
|
|
return "Unknown";
|
|
}
|
|
}
|
|
|
|
std::string DebugPrinter::FormatScopeKind(ScopeKind kind) const
|
|
{
|
|
switch (kind)
|
|
{
|
|
case ScopeKind::Global:
|
|
return "Global";
|
|
case ScopeKind::Unit:
|
|
return "Unit";
|
|
case ScopeKind::Class:
|
|
return "Class";
|
|
case ScopeKind::Function:
|
|
return "Function";
|
|
case ScopeKind::Block:
|
|
return "Block";
|
|
default:
|
|
return "Unknown";
|
|
}
|
|
}
|
|
|
|
std::string DebugPrinter::SymbolIcon(SymbolKind kind) const
|
|
{
|
|
if (!options_.use_color)
|
|
return "";
|
|
|
|
switch (kind)
|
|
{
|
|
case SymbolKind::Module:
|
|
return "📦";
|
|
case SymbolKind::Namespace:
|
|
return "🗃️";
|
|
case SymbolKind::Class:
|
|
return "🏛️";
|
|
case SymbolKind::Interface:
|
|
return "🔌";
|
|
case SymbolKind::Struct:
|
|
return "📐";
|
|
case SymbolKind::Enum:
|
|
return "🔢";
|
|
case SymbolKind::Function:
|
|
return "🎄";
|
|
case SymbolKind::Method:
|
|
return "🪀";
|
|
case SymbolKind::Constructor:
|
|
return "🔨";
|
|
case SymbolKind::Property:
|
|
return "📋";
|
|
case SymbolKind::Field:
|
|
return "📌";
|
|
case SymbolKind::Variable:
|
|
return "📊";
|
|
case SymbolKind::Constant:
|
|
return "🔒";
|
|
default:
|
|
return "•";
|
|
}
|
|
}
|
|
|
|
void DebugPrinter::PrintSeparator(std::ostream& os, char ch, int width) const
|
|
{
|
|
os << std::string(width, ch) << "\n";
|
|
}
|
|
|
|
void DebugPrinter::PrintHeader(const std::string& title, std::ostream& os) const
|
|
{
|
|
os << "\n";
|
|
os << Color(Color::Bold) << "╔" << std::string(78, '=') << "╗\n";
|
|
os << "║ " << std::setw(74) << std::left << title << " ║\n";
|
|
os << "╚" << std::string(78, '=') << "╝" << Color(Color::Reset) << "\n\n";
|
|
}
|
|
|
|
void DebugPrinter::PrintSubHeader(const std::string& title, std::ostream& os) const
|
|
{
|
|
os << "\n";
|
|
os << Color(Color::Bold) << Color(Color::BrightCyan)
|
|
<< "┌─ " << title << " " << std::string(73 - title.length(), '-') << "\n"
|
|
<< Color(Color::Reset);
|
|
}
|
|
|
|
std::string DebugPrinter::Color(const char* color_code) const
|
|
{
|
|
return options_.use_color ? color_code : "";
|
|
}
|
|
|
|
std::string DebugPrinter::Bold(const std::string& text) const
|
|
{
|
|
if (!options_.use_color)
|
|
return text;
|
|
return std::string(Color::Bold) + text + Color::Reset;
|
|
}
|
|
|
|
std::string DebugPrinter::Dim(const std::string& text) const
|
|
{
|
|
if (!options_.use_color)
|
|
return text;
|
|
return std::string(Color::Dim) + text + Color::Reset;
|
|
}
|
|
|
|
// ==================== 快速打印函数 ====================
|
|
|
|
void Print(const SymbolTable& table, std::ostream& os)
|
|
{
|
|
DebugPrinter printer(table);
|
|
printer.PrintAll(os);
|
|
}
|
|
|
|
void PrintOverview(const SymbolTable& table, std::ostream& os)
|
|
{
|
|
DebugPrinter printer(table);
|
|
printer.PrintOverview(os);
|
|
}
|
|
|
|
void PrintStats(const SymbolTable& table, std::ostream& os)
|
|
{
|
|
DebugPrinter printer(table);
|
|
printer.PrintStatistics(os);
|
|
}
|
|
|
|
void PrintSymbolTree(const SymbolTable& table, std::ostream& os)
|
|
{
|
|
DebugPrinter printer(table);
|
|
printer.PrintSymbolList(os);
|
|
}
|
|
|
|
void PrintScopeTree(const SymbolTable& table, std::ostream& os)
|
|
{
|
|
DebugPrinter printer(table);
|
|
printer.PrintScopeHierarchy(os);
|
|
}
|
|
|
|
void Find(const SymbolTable& table, const std::string& name, std::ostream& os)
|
|
{
|
|
DebugPrinter printer(table);
|
|
printer.FindAndPrint(name, os);
|
|
}
|
|
|
|
void PrintCompact(const SymbolTable& table, std::ostream& os)
|
|
{
|
|
DebugPrinter printer(table, PrintOptions::Compact());
|
|
printer.PrintOverview(os);
|
|
printer.PrintStatistics(os);
|
|
}
|
|
|
|
void PrintVerbose(const SymbolTable& table, std::ostream& os)
|
|
{
|
|
DebugPrinter printer(table, PrintOptions::Verbose());
|
|
printer.PrintAll(os);
|
|
}
|
|
|
|
} // namespace lsp::language::symbol::debug
|