diff --git a/uppsrc/ide/clang/AutoComplete.cpp b/uppsrc/ide/clang/AutoComplete.cpp new file mode 100644 index 000000000..ea0c71dc7 --- /dev/null +++ b/uppsrc/ide/clang/AutoComplete.cpp @@ -0,0 +1,3 @@ +#include "clang.h" + +void foo() {} \ No newline at end of file diff --git a/uppsrc/ide/clang/Codebase.cpp b/uppsrc/ide/clang/Codebase.cpp index 76e644c1d..5a53bbe70 100644 --- a/uppsrc/ide/clang/Codebase.cpp +++ b/uppsrc/ide/clang/Codebase.cpp @@ -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 visited; unsigned h = clang_hashCursor(cursor); if(visited.Find(h) >= 0) diff --git a/uppsrc/ide/clang/CurrentFile.cpp b/uppsrc/ide/clang/CurrentFile.cpp index ff8ad380d..f69ba0322 100644 --- a/uppsrc/ide/clang/CurrentFile.cpp +++ b/uppsrc/ide/clang/CurrentFile.cpp @@ -14,196 +14,6 @@ Event&> autocomplete_done; bool do_annotations; Event&> 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 *>(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 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 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 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 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() diff --git a/uppsrc/ide/clang/Visitor.cpp b/uppsrc/ide/clang/Visitor.cpp new file mode 100644 index 000000000..361eefb14 --- /dev/null +++ b/uppsrc/ide/clang/Visitor.cpp @@ -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); + } +} diff --git a/uppsrc/ide/clang/clang.cpp b/uppsrc/ide/clang/clang.cpp index fba995b2b..6f660635c 100644 --- a/uppsrc/ide/clang/clang.cpp +++ b/uppsrc/ide/clang/clang.cpp @@ -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 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(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> 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 sa = Split(cmdline, ' '); - - Buffer argv(sa.GetCount()); - int i = 0; - for(const String& s : sa) - argv[i++] = ~s; - - CXTranslationUnit tu; + Vector args; + for(const String& s : Split(includes, ';')) + args.Add("-I" + s); - Buffer 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 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& 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>(), 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& 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= 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; jannotation.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 sa = Split(cmdline, ' '); - - Buffer 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) { diff --git a/uppsrc/ide/clang/clang.h b/uppsrc/ide/clang/clang.h index 3b9d8917b..eae65f07a 100644 --- a/uppsrc/ide/clang/clang.h +++ b/uppsrc/ide/clang/clang.h @@ -22,9 +22,7 @@ struct SourceLocation { SourceLocation(CXSourceLocation location); }; -void ClangFile(const String& filename, const String& content, const Vector& includes, int line, int column); String RedefineMacros(); -CXTranslationUnit Clang(const String& cmdline, Vector> 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&> done); void StartAutoComplete(const CurrentFileContext& ctx, int line, int column, bool macros, Event&> done); diff --git a/uppsrc/ide/clang/clang.upp b/uppsrc/ide/clang/clang.upp index da143bf1f..387c6c899 100644 --- a/uppsrc/ide/clang/clang.upp +++ b/uppsrc/ide/clang/clang.upp @@ -16,5 +16,7 @@ file Signature.cpp, clang.cpp, Codebase.cpp, + Visitor.cpp, + AutoComplete.cpp, CurrentFile.cpp;