developing usage tree

This commit is contained in:
Mirek Fidler 2025-03-30 10:39:04 +02:00
parent d2d07bd834
commit ea3443a4c6
9 changed files with 140 additions and 81 deletions

View file

@ -13,7 +13,7 @@ uses(!NOSO) plugin/png;
uses(!NOSO) Draw;
file
Builders.h options(BUILDER_OPTION) PCH,
Builders.h,
CppBuilder.cpp,
MakeFile.cpp,
CCJ.cpp,

View file

@ -115,89 +115,93 @@ void GatherVirtuals(const VectorMap<String, String>& bases, const String& cls,
}
}
void Ide::GetGlobalUsageIds(const String& id, bool& isvirtual, bool& isstatic, bool& istype, Index<String>& ids)
{
isvirtual = false;
isstatic = false; // to limit file static variables to single file
istype = false;
String cls;
for(const auto& f : ~CodeIndex())
for(const AnnotationItem& m : f.value.items) {
if(m.id == id) {
if(m.isvirtual) {
isvirtual = true;
cls = m.nest;
break;
}
if(IsStruct(m.kind)) {
istype = true;
cls = m.nest;
break;
}
if(m.id == id && m.isstatic && f.key == editfile &&
m.nest.GetCount() == m.nspace.GetCount()) // ignore class variables
isstatic = true;
}
}
ids.FindAdd(id);
if(isvirtual) {
Index<String> visited;
String signature = ScopeWorkaround(id.Mid(cls.GetCount()));
Index<String> base_id;
GatherBaseVirtuals(cls, signature, base_id, visited);
VectorMap<String, String> bases;
for(const auto& f : ~CodeIndex()) // check derived classes
for(const AnnotationItem& m : f.value.items)
if(IsStruct(m.kind))
for(String bcls : Split(m.bases, [](int c) { return iscid(c) || c == ':' ? 0 : 1; }))
bases.Add(bcls, m.id);
visited.Clear();
for(const String& cls : base_id)
GatherVirtuals(bases, cls, signature, ids, visited);
}
}
bool Ide::IsLocalAtCursor(const String& id, Point ref_pos)
{
int li = editor.GetCursorLine();
bool local = false;
AnnotationItem cm = editor.FindCurrentAnnotation(); // what function body are we in?
if(IsFunction(cm.kind)) // do local variables
for(const AnnotationItem& lm : editor.locals)
if(lm.id == id && lm.pos.y >= cm.pos.y && lm.pos.y <= li && ref_pos == lm.pos)
return true;
return false;
}
void Ide::Usage(const String& id, const String& name, Point ref_pos)
{
if(IsNull(id))
return;
ResetFileLine();
int li = editor.GetCursorLine();
bool local = false;
AnnotationItem cm = editor.FindCurrentAnnotation(); // what function body are we in?
if(IsFunction(cm.kind)) { // do local variables
for(const AnnotationItem& lm : editor.locals)
if(lm.id == id && lm.pos.y >= cm.pos.y && lm.pos.y <= li) {
if(ref_pos == lm.pos) {
local = true;
break;
}
}
}
NewFFound();
Progress pi("Indexing files");
while(Indexer::IsRunning()) {
if(pi.StepCanceled())
break;
GuiSleep(10);
}
Index<String> unique;
if(local) {
if(IsLocalAtCursor(id, ref_pos)) {
AddReferenceLine(editfile, ref_pos, name, unique);
for(const ReferenceItem& lm : editor.references)
if(lm.id == id && lm.ref_pos == ref_pos)
AddReferenceLine(editfile, lm.pos, name, unique);
}
else {
bool isvirtual = false;
bool isstatic = false; // to limit file static variables to single file
bool istype = false;
String cls;
Progress pi("Indexing files");
while(Indexer::IsRunning()) {
if(pi.StepCanceled())
break;
GuiSleep(10);
}
for(const auto& f : ~CodeIndex())
for(const AnnotationItem& m : f.value.items) {
if(m.id == id) {
if(m.isvirtual) {
isvirtual = true;
cls = m.nest;
break;
}
if(IsStruct(m.kind)) {
istype = true;
cls = m.nest;
break;
}
if(m.id == id && m.isstatic && f.key == editfile &&
m.nest.GetCount() == m.nspace.GetCount()) // ignore class variables
isstatic = true;
}
}
bool isvirtual;
bool isstatic; // to limit file static variables to single file
bool istype;
Index<String> ids;
ids.FindAdd(id);
if(isvirtual) {
Index<String> visited;
String signature = ScopeWorkaround(id.Mid(cls.GetCount()));
Index<String> base_id;
GatherBaseVirtuals(cls, signature, base_id, visited);
VectorMap<String, String> bases;
for(const auto& f : ~CodeIndex()) // check derived classes
for(const AnnotationItem& m : f.value.items)
if(IsStruct(m.kind))
for(String bcls : Split(m.bases, [](int c) { return iscid(c) || c == ':' ? 0 : 1; }))
bases.Add(bcls, m.id);
visited.Clear();
for(const String& cls : base_id)
GatherVirtuals(bases, cls, signature, ids, visited);
}
GetGlobalUsageIds(id, isvirtual, isstatic, istype, ids);
UsageId(name, id, ids, istype, isstatic, unique);
}
@ -211,7 +215,6 @@ void Ide::UsageId(const String& name, const String& id, const Index<String>& ids
int q = id.ReverseFind("::");
String constructor = id + "::" + (q >= 0 ? id.Mid(q + 2) : id) + "(";
String destructor = id + "::~(";
SortByKey(CodeIndex());
int kind = Null;
for(int src = 0; src < 2; src++)
for(const auto& f : ~CodeIndex()) {
@ -261,6 +264,7 @@ void Ide::Usage()
void Ide::IdUsage()
{
SortByKey(CodeIndex());
if(designer)
return;
if(editfile.EndsWith(".lay")) {
@ -307,6 +311,43 @@ void Ide::IdUsage()
Usage(ref_id, name, ref_pos);
}
void Ide::DoUsageTree(String parent_id, String id, String fn, Point mpos, String name, Index<String>& unique, int& lvl, String& current, Index<String>& done)
{
/* AddReferenceLine(fn, mpos, name, unique);
if(parent_id != current) {
current = parent_id;
if(lvl < 40 && !IsNull(parent_id) && done.Find(parent_id) < 0 && done.GetCount() < 100) {
done.Add(parent_id);
lvl++;
for(int pass = 0; pass < 2; pass++)
for(const auto& f : ~CodeIndex()) {
for(const AnnotationItem& m : f.value.items) {
if(m.id == parent_id && m.definition != (bool)pass) {
String current;
DLOG(lvl << " " << parent_id);
Usage(parent_id, m.name, m.pos, [&](String parent_id, String id, String fn, Point mpos, String name) {
DoUsageTree(parent_id, id, fn, mpos, name, unique, lvl, current, done);
});
lvl--;
return;
}
}
}
lvl--;
}
}
*/}
void Ide::UsageTree()
{
/* Index<String> unique, done;
int lvl = 0;
String current;
IdUsage([&](String parent_id, String id, String fn, Point mpos, String name) {
DoUsageTree(parent_id, id, fn, mpos, name, unique, lvl, current, done);
});
*/}
void Ide::FindDesignerItemReferences(const String& id, const String& name)
{
SaveFile();
@ -358,3 +399,4 @@ void Ide::FindDesignerItemReferences(const String& id, const String& name)
}
}
}

View file

@ -105,6 +105,7 @@ void AnnotationItem::Serialize(Stream& s)
void ReferenceItem::Serialize(Stream& s)
{
s % id
% parent_id
% pos
% ref_pos
;
@ -131,6 +132,7 @@ String CachedAnnotationPath(const String& source_file, const String& defines, co
#ifdef _DEBUG
<< "debug" // to have different codebase for development
#endif
<< "1" // version
;
return CacheFile(GetFileTitle(source_file) + "$" + s.FinishString() + ".code_index");
}
@ -155,7 +157,7 @@ void DumpIndex(const char *file, const String& what_file)
out << '\t' << n.pos.y << ": " << n.id << " -> " << n.pretty << ", bases: " << n.bases << "\n";
out << "\t=== References:\n";
for(const auto& n : m.value.refs)
out << '\t' << n.pos << " " << n.id << " -> " << n.ref_pos << "\n";
out << '\t' << n.pos << " " << n.id << " -> " << n.ref_pos << ", parent: " << n.parent_id << "\n";
}
}

View file

@ -302,6 +302,7 @@ bool ClangVisitor::ProcessNode(CXCursor cursor)
String id = ci.Id();
int kind = ci.Kind();
if(id.GetCount()) {
parent_id = id;
LoadSourceLocation();
CppFileInfo& f = info.GetAdd(sl.path);
AnnotationItem& r = locals ? f.locals.Add() : f.items.Add();
@ -356,6 +357,7 @@ bool ClangVisitor::ProcessNode(CXCursor cursor)
ReferenceItem rm;
rm.pos = sl.pos;
rm.id = ref_ci.Id();
rm.parent_id = parent_id;
rm.ref_pos = ref_loc.pos;
#if 0
DLOG("=======");
@ -397,9 +399,11 @@ CXChildVisitResult clang_visitor(CXCursor cursor, CXCursor p, CXClientData clien
#endif
ClangVisitor *v = (ClangVisitor *)clientData;
bool bak_locals = v->locals;
String bak_parent_id = v->parent_id;
if(v->ProcessNode(cursor))
clang_visitChildren(cursor, clang_visitor, clientData);
v->locals = bak_locals;
v->parent_id = bak_parent_id;
#ifdef DUMPTREE
LOGEND();
#endif

View file

@ -144,6 +144,8 @@ struct AnnotationItem : Moveable<AnnotationItem> {
String nest; // Upp::Class
String unest; // UPP::CLASS
String bases; // base classes of struct/class
String parent_id;
Point pos = Null;
int kind = Null;
bool definition = false;
@ -160,6 +162,7 @@ String MakeDefinition(const AnnotationItem& m);
struct ReferenceItem : Moveable<ReferenceItem> {
String id;
String parent_id; // function or struct that contains this item
Point pos;
Point ref_pos;
@ -243,7 +246,8 @@ class ClangVisitor {
CXLocation GetLocation(CXSourceLocation cxlocation);
SourceLocation GetSourceLocation(const CXLocation& p);
bool locals = false;
bool locals = false;
String parent_id;
public:
VectorMap<String, CppFileInfo> info;

View file

@ -1001,7 +1001,12 @@ public:
void UsageId(const String& name, const String& id, const Index<String>& ids, bool istype, bool isstatic, Index<String>& unique);
void Usage();
void IdUsage();
bool IsLocalAtCursor(const String& id, Point ref_pos);
void GetGlobalUsageIds(const String& id, bool& isvirtual, bool& isstatic, bool& istype, Index<String>& ids);
void Usage(const String& id, const String& name, Point ref_pos);
void DoUsageTree(String parent_id, String id, String fn, Point mpos, String name, Index<String>& unique,
int& lvl, String& current, Index<String>& done);
void UsageTree();
bool OpenLink(const String& s, int pos);
String GetRefId(int pos, String& name, Point& ref_pos);
void ContextGoto0(int pos);

View file

@ -106,6 +106,7 @@ KEY(THISBACKS, "Events..", K_ALT_T)
KEY(SWAPS, "Go to definition/declaration", K_ALT_I)
KEY(IDUSAGE, "Usage", K_ALT_U)
KEY(USAGE, "Usage of current function", K_SHIFT|K_ALT_U)
KEY(USAGETREE, "Usage tree", K_ALT_O)
KEY(JUMPS, "Context go to", K_ALT_J)
KEY(TOGGLEINDEX, "File index", K_CTRL_F12)
KEY(SEARCHINDEX, "File index search", K_F12)

View file

@ -860,8 +860,9 @@ void Ide::AssistMenu(Bar& menu)
menu.Add(!designer, AK_JUMPS, [=] { ContextGoto(); });
menu.Add(!designer, AK_SWAPS, THISBACK(SwapS));
menu.Add(!designer, AK_DCOPY, callback(&editor, &AssistEditor::DCopy));
menu.Add(!designer, AK_IDUSAGE, THISBACK(IdUsage));
menu.Add(!designer, AK_IDUSAGE, [=] { IdUsage(); });
menu.Add(!designer, AK_USAGE, [=] { Usage(); });
menu.Add(!designer, AK_USAGETREE, [=] { UsageTree(); });
menu.Add(!designer, AK_GOTOGLOBAL, THISBACK(NavigatorDlg));
menu.Add(!designer, AK_VIRTUALS, callback(&editor, &AssistEditor::Virtuals));
menu.Add(!designer, AK_THISBACKS, callback(&editor, &AssistEditor::Events));