refactoring part 1

This commit is contained in:
Mirek Fidler 2022-07-11 10:47:00 +02:00
parent a7cbd047e8
commit 8a5af27cf7
7 changed files with 344 additions and 561 deletions

View file

@ -0,0 +1,3 @@
#include "clang.h"
void foo() {}

View file

@ -1,10 +1,32 @@
#include "clang.h"
// TODO: Remove
#define LLOG(x)
CXChildVisitResult current_file_visitor2( CXCursor cursor, CXCursor p, CXClientData clientData )
{
#if 0
auto Dump = [&] {
#if 1
SourceLocation location(cxlocation);
LOG("=====================");
// DDUMP(location);
// DDUMP((int)cursorKind);
DDUMP(GetCursorKindName(cursorKind));
DDUMP(name);
DDUMP(type);
DDUMP(pid);
DDUMP(CleanupId(pid));
DDUMP(scope);
DDUMP(nspace);
DDUMP(clang_isCursorDefinition(cursor));
#endif
};
static Index<unsigned> visited;
unsigned h = clang_hashCursor(cursor);
if(visited.Find(h) >= 0)

View file

@ -14,196 +14,6 @@ Event<const Vector<AutoCompleteItem>&> autocomplete_done;
bool do_annotations;
Event<const Vector<AnnotationItem>&> annotations_done;
CXChildVisitResult current_file_visitor( CXCursor cursor, CXCursor p, CXClientData clientData)
{
CXSourceLocation cxlocation = clang_getCursorLocation(cursor);
bool valid = clang_Location_isFromMainFile(cxlocation);
// TODO: change this for MT
static CXPrintingPolicy pp_id = clang_getCursorPrintingPolicy(cursor);
ONCELOCK {
for(int i = 0; i <= CXPrintingPolicy_LastProperty; i++)
clang_PrintingPolicy_setProperty(pp_id, (CXPrintingPolicyProperty)i, 0);
for(CXPrintingPolicyProperty p : {
CXPrintingPolicy_SuppressSpecifiers,
CXPrintingPolicy_SuppressTagKeyword,
CXPrintingPolicy_SuppressUnwrittenScope,
CXPrintingPolicy_SuppressInitializers,
CXPrintingPolicy_SuppressStrongLifetime,
CXPrintingPolicy_SuppressLifetimeQualifiers,
CXPrintingPolicy_SuppressTemplateArgsInCXXConstructors,
CXPrintingPolicy_TerseOutput,
CXPrintingPolicy_SuppressImplicitBase,
CXPrintingPolicy_FullyQualifiedName })
clang_PrintingPolicy_setProperty(pp_id, p, 1);
};
if(valid) {
String m;
CXCursor parent = clang_getCursorSemanticParent(cursor);
CXCursorKind cursorKind = clang_getCursorKind(cursor);
CXCursorKind parentKind = clang_getCursorKind(parent);
String name = GetCursorSpelling(cursor);
String type = GetTypeSpelling(cursor);
String id = FetchString(clang_getCursorPrettyPrinted(cursor, pp_id));
CXCursor p = parent;
String scope;
String nspace;
for(;;) {
CXCursorKind k = clang_getCursorKind(p);
if(findarg(k, CXCursor_Namespace, CXCursor_ClassTemplate, CXCursor_StructDecl, CXCursor_UnionDecl, CXCursor_ClassDecl) < 0)
break;
String q = GetCursorSpelling(p);
scope = scope.GetCount() ? q + "::" + scope : q;
if(k == CXCursor_Namespace)
nspace = nspace.GetCount() ? q + "::" + nspace : q;
p = clang_getCursorSemanticParent(p);
}
int q = scope.Find('('); // 'Struct::(unnamed enum at C:\u\upp.src\upptst\Annotations\main.cpp:47:2)'
if(q >= 0)
scope.Trim(q);
if(scope.GetCount() && *scope.Last() != ':')
scope << "::";
auto Dump = [&] {
#if 1
SourceLocation location(cxlocation);
LOG("=====================");
// DDUMP(location);
// DDUMP((int)cursorKind);
DDUMP(GetCursorKindName(cursorKind));
DDUMP(name);
DDUMP(type);
DDUMP(id);
DDUMP(CleanupId(id));
DDUMP(scope);
DDUMP(nspace);
DDUMP(clang_isCursorDefinition(cursor));
static CXPrintingPolicy pp = clang_getCursorPrintingPolicy(cursor);
ONCELOCK {
for(int i = 0; i <= CXPrintingPolicy_LastProperty; i++)
clang_PrintingPolicy_setProperty(pp, (CXPrintingPolicyProperty)i, 0);
for(CXPrintingPolicyProperty p : {
CXPrintingPolicy_SuppressSpecifiers,
CXPrintingPolicy_SuppressTagKeyword,
// CXPrintingPolicy_IncludeTagDefinition,
// CXPrintingPolicy_SuppressScope,
CXPrintingPolicy_SuppressUnwrittenScope,
CXPrintingPolicy_SuppressInitializers,
// CXPrintingPolicy_ConstantArraySizeAsWritten,
// CXPrintingPolicy_AnonymousTagLocations,
CXPrintingPolicy_SuppressStrongLifetime,
CXPrintingPolicy_SuppressLifetimeQualifiers,
CXPrintingPolicy_SuppressTemplateArgsInCXXConstructors,
// CXPrintingPolicy_Bool,
// CXPrintingPolicy_Restrict,
// CXPrintingPolicy_Alignof,
// CXPrintingPolicy_UnderscoreAlignof,
// CXPrintingPolicy_UseVoidForZeroParams,
CXPrintingPolicy_TerseOutput,
// CXPrintingPolicy_PolishForDeclaration,
// CXPrintingPolicy_Half,
// CXPrintingPolicy_MSWChar,
// CXPrintingPolicy_IncludeNewlines,
// CXPrintingPolicy_MSVCFormatting,
// CXPrintingPolicy_ConstantsAsWritten,
CXPrintingPolicy_SuppressImplicitBase,
CXPrintingPolicy_FullyQualifiedName })
clang_PrintingPolicy_setProperty(pp, p, 1);
};
{
// DTIMING("PrettyPrinting");
// DDUMP(FetchString(clang_getCursorPrettyPrinted(cursor, pp)));
}
// DDUMP(FetchString(clang_Cursor_getMangling(cursor)));
// DDUMP(CxxDemangle(FetchString(clang_Cursor_getMangling(cursor))));
// DDUMP(GetCursorKindName(parentKind));
// DDUMP(GetCursorSpelling(parent));
// DDUMP(GetTypeSpelling(parent));
#endif
};
Dump();
bool external = false;
if(findarg(parentKind, CXCursor_FunctionTemplate, CXCursor_FunctionDecl, CXCursor_CXXMethod,
CXCursor_Constructor, CXCursor_Destructor) >= 0)
valid = false; // local variable
else
switch(cursorKind) {
case CXCursor_StructDecl:
case CXCursor_UnionDecl:
case CXCursor_ClassDecl:
case CXCursor_FunctionTemplate:
case CXCursor_FunctionDecl:
case CXCursor_Constructor:
case CXCursor_Destructor:
case CXCursor_CXXMethod:
m = id;
break;
case CXCursor_VarDecl:
external = clang_Cursor_hasVarDeclExternalStorage(cursor);
case CXCursor_FieldDecl:
case CXCursor_ClassTemplate:
m << scope << name;
break;
case CXCursor_ConversionFunction:
m << scope << "operator " << type;
break;
case CXCursor_MacroDefinition:
m = name;
break;
case CXCursor_EnumConstantDecl:
m << scope << name;
break;
case CXCursor_EnumDecl:
// case CXCursor_ParmDecl:
case CXCursor_TypedefDecl:
case CXCursor_Namespace:
case CXCursor_UnexposedDecl:
// case CXCursor_NamespaceAlias:
break;
default:
valid = false;
break;
}
if(valid) {
// Dump();
if(m.GetCount()) {
CXFile file;
unsigned line_;
unsigned column_;
unsigned offset_;
clang_getExpansionLocation(cxlocation, &file, &line_, &column_, &offset_);
AnnotationItem& r = static_cast<Vector<AnnotationItem> *>(clientData)->Add();
r.kind = cursorKind;
r.name = name;
r.line = line_;
r.id = CleanupId(m);
r.definition = clang_isCursorDefinition(cursor);
r.external = external;
r.nspace = nspace;
static CXPrintingPolicy pp;
ONCELOCK {
pp = clang_getCursorPrintingPolicy(cursor);
for(int i = 0; i <= CXPrintingPolicy_LastProperty; i++)
clang_PrintingPolicy_setProperty(pp, (CXPrintingPolicyProperty)i, 0);
clang_PrintingPolicy_setProperty(pp, CXPrintingPolicy_TerseOutput, 1);
clang_PrintingPolicy_setProperty(pp, CXPrintingPolicy_SuppressScope, 1);
}
r.pretty = CleanupPretty(FetchString(clang_getCursorPrettyPrinted(cursor, pp)));
}
}
}
clang_visitChildren(cursor, current_file_visitor, clientData);
return CXChildVisit_Continue;
}
void ReadAutocomplete(const CXCompletionString& string, String& name, String& signature)
{
const int chunkCount = clang_getNumCompletionChunks(string);
@ -227,30 +37,38 @@ void ReadAutocomplete(const CXCompletionString& string, String& name, String& si
}
}
struct CurrentFileVisitor : ClangVisitor {
Vector<AnnotationItem> item;
virtual void Item() {
AnnotationItem& r = item.Add();
r.kind = GetKind();
r.name = GetName();
r.line = GetLine();
r.id = GetId();
r.definition = IsDefinition();
r.external = IsExtern();
r.nspace = GetNamespace();
}
};
void CurrentFileThread()
{
MemoryIgnoreLeaksBlock __;
CurrentFileContext parsed_file;
CXTranslationUnit tu = nullptr;
int64 serial;
auto DisposeTU = [&] {
if(tu) clang_disposeTranslationUnit(tu);
tu = nullptr;
};
Clang clang;
auto DoAnnotations = [&] {
if(!tu || !annotations_done) return;
Vector<AnnotationItem> item;
{ TIMESTOP("DoAnnotations");
clang_visitChildren(clang_getTranslationUnitCursor(tu), current_file_visitor, &item);
}
if(!clang.tu || !annotations_done) return;
CurrentFileVisitor v;
v.Do(clang.tu);
Ctrl::Call([&] {
if(parsed_file.filename == current_file.filename &&
parsed_file.real_filename == current_file.real_filename &&
parsed_file.includes == current_file.includes)
annotations_done(item);
annotations_done(v.item);
do_annotations = false;
});
};
@ -266,76 +84,71 @@ void CurrentFileThread()
annotations_do = do_annotations;
macros = autocomplete_macros;
}
String fn = f.filename;
if(!IsSourceFile(fn))
fn.Cat(".cpp");
if(f.filename != parsed_file.filename || f.includes != parsed_file.includes ||
f.real_filename != parsed_file.real_filename || !tu) {
parsed_file = f;
DisposeTU();
String cmdline;
cmdline << fn << " -DflagDEBUG -DflagDEBUG_FULL -DflagBLITZ -DflagWIN32 -DflagMAIN -DflagGUI -xc++ -std=c++17 ";
for(String s : Split(f.includes, ';'))
cmdline << " -I" << s;
tu = Clang(cmdline, { { ~fn, f.content } },
CXTranslationUnit_DetailedPreprocessingRecord|
CXTranslationUnit_PrecompiledPreamble|
CXTranslationUnit_CreatePreambleOnFirstParse|
CXTranslationUnit_KeepGoing|
CXTranslationUnit_RetainExcludedConditionalBlocks);
DoAnnotations();
annotations_do = false;
// DumpDiagnostics(tu);
}
if(Thread::IsShutdownThreads()) break;
CXUnsavedFile ufile = { ~fn, ~f.content, (unsigned)f.content.GetCount() };
if(autocomplete_do && tu) {
CXCodeCompleteResults *results;
{
TIMESTOP("clang_codeCompleteAt");
results = clang_codeCompleteAt(tu, fn, autocomplete_pos.y, autocomplete_pos.x, &ufile, 1,
macros ? CXCodeComplete_IncludeMacros : 0);
}
// DumpDiagnostics(tu);
if(results) {
Vector<AutoCompleteItem> item;
for(int i = 0; i < results->NumResults; i++) {
const CXCompletionString& string = results->Results[i].CompletionString;
int kind = results->Results[i].CursorKind;
if(kind == CXCursor_MacroDefinition && !macros) // we probably want this only on Ctrl+Space
continue;
if(kind == CXCursor_NotImplemented)
continue;
String name;
String signature;
ReadAutocomplete(string, name, signature);
AutoCompleteItem& m = item.Add();
m.name = name;
m.parent = FetchString(clang_getCompletionParent(string, NULL));
m.signature = CleanupPretty(signature);
m.kind = kind;
m.priority = clang_getCompletionPriority(string);
}
clang_disposeCodeCompleteResults(results);
Ctrl::Call([&] {
if(serial == autocomplete_serial)
autocomplete_done(item);
});
}
GuiLock __;
do_autocomplete = false;
}
if(Thread::IsShutdownThreads()) break;
if(annotations_do && tu) {
TIMESTOP("ReParse");
if(clang_reparseTranslationUnit(tu, 1, &ufile, 0))
DisposeTU();
else
if(f.filename.GetCount()) {
String fn = f.filename;
if(!IsSourceFile(fn))
fn.Cat(".cpp");
if(f.filename != parsed_file.filename || f.includes != parsed_file.includes ||
f.real_filename != parsed_file.real_filename || !clang.tu) {
parsed_file = f;
clang.Dispose();
clang.Parse(fn, f.content, f.includes, String(),
CXTranslationUnit_DetailedPreprocessingRecord|
CXTranslationUnit_PrecompiledPreamble|
CXTranslationUnit_CreatePreambleOnFirstParse|
CXTranslationUnit_KeepGoing|
CXTranslationUnit_RetainExcludedConditionalBlocks);
DoAnnotations();
annotations_do = false;
// DumpDiagnostics(tu);
}
if(Thread::IsShutdownThreads()) break;
CXUnsavedFile ufile = { ~fn, ~f.content, (unsigned)f.content.GetCount() };
if(autocomplete_do && clang.tu) {
CXCodeCompleteResults *results;
{
TIMESTOP("clang_codeCompleteAt");
results = clang_codeCompleteAt(clang.tu, fn, autocomplete_pos.y, autocomplete_pos.x, &ufile, 1,
macros ? CXCodeComplete_IncludeMacros : 0);
}
// DumpDiagnostics(tu);
if(results) {
Vector<AutoCompleteItem> item;
for(int i = 0; i < results->NumResults; i++) {
const CXCompletionString& string = results->Results[i].CompletionString;
int kind = results->Results[i].CursorKind;
if(kind == CXCursor_MacroDefinition && !macros) // we probably want this only on Ctrl+Space
continue;
if(kind == CXCursor_NotImplemented)
continue;
String name;
String signature;
ReadAutocomplete(string, name, signature);
AutoCompleteItem& m = item.Add();
m.name = name;
m.parent = FetchString(clang_getCompletionParent(string, NULL));
m.signature = CleanupPretty(signature);
m.kind = kind;
m.priority = clang_getCompletionPriority(string);
}
clang_disposeCodeCompleteResults(results);
Ctrl::Call([&] {
if(serial == autocomplete_serial)
autocomplete_done(item);
});
}
GuiLock __;
do_autocomplete = false;
}
if(Thread::IsShutdownThreads()) break;
if(annotations_do && clang.tu) {
TIMESTOP("ReParse");
if(clang.ReParse(fn, f.content))
DoAnnotations();
}
}
current_file_event.Wait(500);
}
DisposeTU();
}
void StartCurrentFileParserThread()

View file

@ -0,0 +1,144 @@
#include "clang.h"
void ClangVisitor::ProcessNode(CXCursor c)
{
cursor = c;
CXSourceLocation cxlocation = clang_getCursorLocation(cursor);
bool annotation = clang_Location_isFromMainFile(cxlocation);
if(annotation) {
String m;
CXCursor parent = clang_getCursorSemanticParent(cursor);
CXCursorKind cursorKind = clang_getCursorKind(cursor);
CXCursorKind parentKind = clang_getCursorKind(parent);
name = GetCursorSpelling(cursor);
type = GetTypeSpelling(cursor);
String pid = FetchString(clang_getCursorPrettyPrinted(cursor, pp_id));
CXCursor p = parent;
scope.Clear();
nspace.Clear();
for(;;) {
CXCursorKind k = clang_getCursorKind(p);
if(findarg(k, CXCursor_Namespace, CXCursor_ClassTemplate, CXCursor_StructDecl, CXCursor_UnionDecl, CXCursor_ClassDecl) < 0)
break;
String q = GetCursorSpelling(p);
scope = scope.GetCount() ? q + "::" + scope : q;
if(k == CXCursor_Namespace)
nspace = nspace.GetCount() ? q + "::" + nspace : q;
p = clang_getCursorSemanticParent(p);
}
int q = scope.Find('('); // 'Struct::(unnamed enum at C:\u\upp.src\upptst\Annotations\main.cpp:47:2)'
if(q >= 0)
scope.Trim(q);
if(scope.GetCount() && *scope.Last() != ':')
scope << "::";
external = false;
if(findarg(parentKind, CXCursor_FunctionTemplate, CXCursor_FunctionDecl, CXCursor_CXXMethod,
CXCursor_Constructor, CXCursor_Destructor) >= 0)
annotation = false; // local variable
else
switch(cursorKind) {
case CXCursor_StructDecl:
case CXCursor_UnionDecl:
case CXCursor_ClassDecl:
case CXCursor_FunctionTemplate:
case CXCursor_FunctionDecl:
case CXCursor_Constructor:
case CXCursor_Destructor:
case CXCursor_CXXMethod:
m = id;
break;
case CXCursor_VarDecl:
external = clang_Cursor_hasVarDeclExternalStorage(cursor);
case CXCursor_FieldDecl:
case CXCursor_ClassTemplate:
m << scope << name;
break;
case CXCursor_ConversionFunction:
m << scope << "operator " << type;
break;
case CXCursor_MacroDefinition:
m = name;
break;
case CXCursor_EnumConstantDecl:
m << scope << name;
break;
case CXCursor_EnumDecl:
// case CXCursor_ParmDecl:
case CXCursor_TypedefDecl:
case CXCursor_Namespace:
case CXCursor_UnexposedDecl:
// case CXCursor_NamespaceAlias:
// break;
default:
annotation = false;
break;
}
if(annotation) {
// Dump();
if(m.GetCount()) {
CXFile file;
unsigned line_;
unsigned column_;
unsigned offset_;
clang_getExpansionLocation(cxlocation, &file, &line_, &column_, &offset_);
line = line_;
column = column_;
kind = cursorKind;
pretty = CleanupPretty(FetchString(clang_getCursorPrettyPrinted(cursor, pp_pretty)));
id = CleanupId(m);
Item();
}
}
}
}
CXChildVisitResult clang_visitor(CXCursor cursor, CXCursor p, CXClientData clientData) {
ClangVisitor *v = (ClangVisitor *)clientData;
v->ProcessNode(cursor);
clang_visitChildren(cursor, clang_visitor, clientData);
return CXChildVisit_Continue;
}
void ClangVisitor::Do(CXTranslationUnit tu)
{
if(!tu) return;
CXCursor cursor = clang_getTranslationUnitCursor(tu);
pp_id = clang_getCursorPrintingPolicy(cursor);
pp_pretty = clang_getCursorPrintingPolicy(cursor);
for(int i = 0; i <= CXPrintingPolicy_LastProperty; i++) {
clang_PrintingPolicy_setProperty(pp_id, (CXPrintingPolicyProperty)i, 0);
clang_PrintingPolicy_setProperty(pp_pretty, (CXPrintingPolicyProperty)i, 0);
}
for(CXPrintingPolicyProperty p : {
CXPrintingPolicy_SuppressSpecifiers,
CXPrintingPolicy_SuppressTagKeyword,
CXPrintingPolicy_SuppressUnwrittenScope,
CXPrintingPolicy_SuppressInitializers,
CXPrintingPolicy_SuppressStrongLifetime,
CXPrintingPolicy_SuppressLifetimeQualifiers,
CXPrintingPolicy_SuppressTemplateArgsInCXXConstructors,
CXPrintingPolicy_TerseOutput,
CXPrintingPolicy_SuppressImplicitBase,
CXPrintingPolicy_FullyQualifiedName })
clang_PrintingPolicy_setProperty(pp_id, p, 1);
clang_PrintingPolicy_setProperty(pp_pretty, CXPrintingPolicy_TerseOutput, 1);
clang_PrintingPolicy_setProperty(pp_pretty, CXPrintingPolicy_SuppressScope, 1);
initialized = true;
clang_visitChildren(cursor, clang_visitor, this);
}
ClangVisitor::~ClangVisitor()
{
if(initialized) {
clang_PrintingPolicy_dispose(pp_id);
clang_PrintingPolicy_dispose(pp_pretty);
}
}

View file

@ -42,316 +42,64 @@ SourceLocation::SourceLocation(CXSourceLocation location)
filename = FetchString(clang_getFileName(file));
}
CXChildVisitResult visitor( CXCursor cursor, CXCursor /* parent */, CXClientData clientData )
void Clang::Dispose()
{
#if 0
static Index<unsigned> visited;
unsigned h = clang_hashCursor(cursor);
if(visited.Find(h) >= 0)
return CXChildVisit_Continue;
visited.Add(h);
#endif
CXSourceLocation cxlocation = clang_getCursorLocation( cursor );
SourceLocation location = cxlocation;
// if( clang_Location_isFromMainFile( location ) == 0 )
// return CXChildVisit_Continue;
CXCursorKind cursorKind = clang_getCursorKind( cursor );
unsigned int curLevel = *( reinterpret_cast<unsigned int*>(clientData));
unsigned int nextLevel = curLevel + 1;
if(curLevel > 100000 && curLevel - 100000 > 2)
return CXChildVisit_Continue;
if (1 || findarg(cursorKind, CXCursorKind::CXCursor_FunctionDecl, CXCursorKind::CXCursor_CXXMethod,
CXCursorKind::CXCursor_FunctionTemplate, CXCursorKind::CXCursor_Constructor) >= 0
|| clang_Location_isFromMainFile(cxlocation)) {
String indent = curLevel > 100000 ? String('=', curLevel - 100000) : String('-', curLevel);
LOG(indent << " " << GetCursorKindName(cursorKind)
<< " '" << GetCursorSpelling(cursor) << "' "
<< " '" << GetTypeSpelling(cursor) << "' " << location);
String h = FetchString(clang_getCursorUSR(cursor));
if(h.GetCount())
LOG(indent << " USR: " << h);
CXCursor c2 = clang_getCursorReferenced(cursor);
if(!clang_Cursor_isNull(c2)) {
LOG(indent << "Referenced: " << GetCursorSpelling(c2) << ' ' << GetCursorKindName(clang_getCursorKind(c2)));
String h = FetchString(clang_getCursorUSR(c2));
if(h.GetCount())
LOG(indent << "->USR: " << h);
// int h = nextLevel < 100000 ? nextLevel + 100000 : nextLevel;
// clang_visitChildren(c2, visitor, &h);
}
// clang_visitChildren(cursor, visitor, &nextLevel);
}
return CXChildVisit_Continue;
if(tu) clang_disposeTranslationUnit(tu);
tu = nullptr;
}
CXTranslationUnit Clang(const String& cmdline_, Vector<Tuple2<String, String>> file, unsigned options)
bool Clang::Parse(const String& filename, const String& content, const String& includes, const String& defines, dword options)
{
static CXIndex index = clang_createIndex(0, 0);
if (!index) {
LLOG("createIndex failed");
return nullptr;
}
String cmdline = cmdline_;
if(!index) return false;
String cmdline;
cmdline << filename << " -DflagDEBUG -DflagDEBUG_FULL -DflagBLITZ -DflagWIN32 -DflagMAIN -DflagGUI -xc++ -std=c++17 ";
cmdline << RedefineMacros();
Vector<String> sa = Split(cmdline, ' ');
Buffer<const char *> argv(sa.GetCount());
int i = 0;
for(const String& s : sa)
argv[i++] = ~s;
CXTranslationUnit tu;
Vector<String> args;
for(const String& s : Split(includes, ';'))
args.Add("-I" + s);
Buffer<CXUnsavedFile> ufile(file.GetCount());
CXUnsavedFile *t = ufile;
for(const auto& f : file) {
t->Filename = ~f.a;
t->Contents = ~f.b;
t->Length = f.b.GetCount();
t++;
}
for(const String& s : Split(defines, ';'))
args.Add("-D" + s);
args.Append(Split(cmdline, ' '));
tu = clang_parseTranslationUnit(index, nullptr, argv, sa.GetCount(), ufile, file.GetCount(), options);
Vector<const char *> argv;
for(const String& s : args)
argv.Add(~s);
CXUnsavedFile ufile = { ~filename, ~content, (unsigned)content.GetCount() };
tu = clang_parseTranslationUnit(index, nullptr, argv, argv.GetCount(), &ufile, 1, options);
DumpDiagnostics(tu);
return tu;
}
#if 0
String PrecompileHeader(String& content, const Vector<String>& includes)
bool Clang::ReParse(const String& filename, const String& content)
{
String out;
String hdr;
StringStream ss(content);
while(!ss.IsEof()) {
String l0 = ss.GetLine();
String l = TrimLeft(ss.GetLine()); // todo COMMENTS!
if(l.GetCount() == 0)
continue;
if(l.StartsWith("#include")) {
hdr << l << "\n";
out << "\n";
}
else {
out << l0 << "\n";
break;
}
}
if(hdr.GetCount() == 0)
return Null;
out << LoadStream(ss);
content = out;
String pch_header2 = "c:/xxx/$pch.h";
String pch_file = pch_header2 + ".pch";
SaveFile(pch_header2, hdr); // CLANG needs a copy of header
String cmdline;
for(String s : includes)
cmdline << " -I" << s;
cmdline << " -xc++ ";
cmdline << pch_header2;
/*
CXTranslationUnit tu;
{
TIMING("Precompile");
tu = Clang(cmdline, Vector<Tuple<String, String>>(), CXTranslationUnit_ForSerialization);
if(tu) {
clang_saveTranslationUnit(tu, pch_file, clang_defaultSaveOptions(tu));
clang_disposeTranslationUnit(tu);
content = out;
return pch_file;
}
}
*/
return Null;
}
void ClangFile(const String& filename, const String& content_, const Vector<String>& includes, int line, int column)
{
String content = content_;
// String pch = PrecompileHeader(content, includes);
String cmdline;
// if(pch.GetCount())
// cmdline << "-include-pch " << pch << ' ';
cmdline << filename << RedefineMacros() << " -DflagDEBUG -DflagDEBUG_FULL -DflagBLITZ -DflagWIN32 -xc++ -std=c++17 ";
;
// if(pch.GetCount())
// cmdline << " -I" + GetFileFolder(pch) + " -include " + GetFileName(pch) + " -Winvalid-pch ";
for(String s : includes)
cmdline << " -I" << s;
DDUMP(cmdline);
CXTranslationUnit tu;
{
RTIMING("Translate");
tu = Clang(cmdline, { { filename, content } }, CXTranslationUnit_PrecompiledPreamble|CXTranslationUnit_CreatePreambleOnFirstParse|CXTranslationUnit_KeepGoing|CXTranslationUnit_RetainExcludedConditionalBlocks);
}
// CXCursor rootCursor = clang_getTranslationUnitCursor(tu);
// unsigned int treeLevel = 0;
// clang_visitChildren(rootCursor, visitor, &treeLevel);
unsigned int completionFlags = (CXCodeComplete_IncludeCodePatterns|CXCodeComplete_IncludeBriefComments);
// completionFlags |= CXCodeComplete_IncludeMacros;
CXUnsavedFile ufile = { ~filename, ~content, (unsigned)content.GetCount() };
CXCodeCompleteResults *results;
{
RTIMING("Complete");
DDUMP(line);
DDUMP(column);
DDUMP(filename);
results = clang_codeCompleteAt(tu, filename, line, column, &ufile, 1, completionFlags);
if(clang_reparseTranslationUnit(tu, 1, &ufile, 0)) {
Dispose();
return false;
}
if (results) {
RTIMING("Parse results");
DLOG("=====================================");
DDUMP(FetchString(clang_codeCompleteGetContainerUSR(results)));
for (unsigned int i = 0; i < results->NumResults; ++i) {
const CXCursorKind kind = results->Results[i].CursorKind;
const CXCompletionString& string = results->Results[i].CompletionString;
/*
const CXAvailabilityKind availabilityKind = clang_getCompletionAvailability(string);
if (!(options.options & Server::CompletionsNoFilter)) {
switch (availabilityKind) {
case CXAvailability_Available:
break;
case CXAvailability_Deprecated:
break;
case CXAvailability_NotAccessible:
continue;
case CXAvailability_NotAvailable: // protected members are erroneously flagged as NotAvailable in clang 3.6
continue;
}
}
*/
if(kind == CXCursor_MacroDefinition) // we probably want this only on Ctrl+Space
continue;
String name;
String signature;
int args = -1;
const int priority = clang_getCompletionPriority(string);
const int chunkCount = clang_getNumCompletionChunks(string);
for (int j=0; j<chunkCount; ++j) {
const CXCompletionChunkKind chunkKind = clang_getCompletionChunkKind(string, j);
String text = FetchString(clang_getCompletionChunkText(string, j));
if (chunkKind == CXCompletionChunk_TypedText) {
name = text;
signature << text;
args = signature.GetCount();
}
else
if (chunkKind == CXCompletionChunk_Placeholder) {
signature << text;
} else {
signature << text;
if (chunkKind == CXCompletionChunk_ResultType) {
signature << ' ';
}
}
}
/*
String annotation;
const unsigned int annotations = clang_getCompletionNumAnnotations(string);
for (unsigned j=0; j<annotations; ++j)
MergeWith(annotation, ", ", FetchString(clang_getCompletionAnnotation(string, j)));
*/
DLOG(GetCursorKindName(kind) << ", @" << priority << " " << name << ": " << signature);
if(args >= 0)
DLOG(" Args: " << signature.Mid(args));
DLOG(" Parent: " << FetchString(clang_getCompletionParent(string, NULL)));
/*
DLOG(" Annotation: " << annotation);
if (candidate) {
candidate->kind = RTags::eatString(clang_getCursorKindSpelling(kind));
candidate->priority = priority;
candidate->parent = RTags::eatString(clang_getCompletionParent(string, nullptr));
candidate->brief_comment = RTags::eatString(clang_getCompletionBriefComment(string));
candidates.push_back(candidate);
const unsigned int annotations = clang_getCompletionNumAnnotations(string);
for (unsigned j=0; j<annotations; ++j) {
const CXStringScope annotation = clang_getCompletionAnnotation(string, j);
const char *cstr = clang_getCString(annotation);
if (strlen(cstr)) {
if (!candidate->annotation.empty())
candidate->annotation += ' ';
candidate->annotation + cstr;
}
}
}
*/
}
// if (options.options & Server::CompletionDiagnostics)
// processDiagnostics(request, results, cache->translationUnit->unit);
clang_disposeCodeCompleteResults(results);
}
clang_disposeTranslationUnit(tu);
return true;
}
#if 0
Vector<String> sa = Split(cmdline, ' ');
Buffer<const char *> argv(sa.GetCount());
int i = 0;
for(const String& s : sa)
argv[i++] = ~s;
CXIndex index = clang_createIndex(0, 0);
if (!index)
Panic("createIndex failed");
Clang::Clang()
{
index = clang_createIndex(0, 0);
}
unsigned options = clang_defaultEditingTranslationUnitOptions();
DDUMP(options);
CXTranslationUnit tu;
{
TIMING("Parse");
CXUnsavedFile file = { ~filename, ~content, (unsigned)content.GetCount() };
tu = clang_parseTranslationUnit(index, nullptr, argv, sa.GetCount(), nullptr, 0, options);
if(!tu) {
DLOG("Parse failed");
return;
}
}
if(0) {
TIMING("Reparse");
int failure = clang_reparseTranslationUnit(tu, 0, nullptr, options);
if (failure)
Panic("Reparse failed");
}
#endif
#endif
Clang::~Clang()
{
Dispose();
clang_disposeIndex(index);
}
void DumpDiagnostics(CXTranslationUnit tu)
{

View file

@ -22,9 +22,7 @@ struct SourceLocation {
SourceLocation(CXSourceLocation location);
};
void ClangFile(const String& filename, const String& content, const Vector<String>& includes, int line, int column);
String RedefineMacros();
CXTranslationUnit Clang(const String& cmdline, Vector<Tuple2<String, String>> file, unsigned options = 0);
enum AdditionalKinds {
KIND_INCLUDEFILE = -1000,
@ -93,6 +91,18 @@ struct CurrentFileContext {
String content;
};
struct Clang {
CXIndex index = nullptr;
CXTranslationUnit tu = nullptr;
void Dispose();
bool Parse(const String& filename, const String& content, const String& includes, const String& defines, dword options);
bool ReParse(const String& filename, const String& content);
Clang();
~Clang();
};
// void CurrentFileVisit(CXTranslationUnit tu);
void StartCurrentFileParserThread();
@ -104,6 +114,47 @@ String CleanupPretty(const String& signature);
bool IsSourceFile(const String& path);
class ClangVisitor {
bool initialized = false;
CXPrintingPolicy pp_id, pp_pretty;
CXCursor cursor;
int kind;
String name;
String id;
String type;
String scope;
String nspace;
String pretty;
bool external;
bool annotation;
int line;
int column;
void ProcessNode(CXCursor c);
friend CXChildVisitResult clang_visitor(CXCursor cursor, CXCursor p, CXClientData clientData);
public:
virtual void Item() = 0;
int GetKind() const { return kind; }
String GetId() const { return id; }
String GetName() const { return name; }
String GetType() const { return type; }
String GetScope() const { return scope; }
String GetNamespace() const { return nspace; }
String GetPretty() const { return pretty; }
bool IsDefinition() const { return clang_isCursorDefinition(cursor); }
bool IsExtern() const { return external; }
bool IsAnnotation() const { return annotation; }
int GetLine() const { return line; }
int GetColumn() const { return column; }
void Do(CXTranslationUnit tu);
~ClangVisitor();
};
void SetCurrentFile(const CurrentFileContext& ctx, Event<const Vector<AnnotationItem>&> done);
void StartAutoComplete(const CurrentFileContext& ctx, int line, int column, bool macros,
Event<const Vector<AutoCompleteItem>&> done);

View file

@ -16,5 +16,7 @@ file
Signature.cpp,
clang.cpp,
Codebase.cpp,
Visitor.cpp,
AutoComplete.cpp,
CurrentFile.cpp;