virtual enum CXChildVisitResult visit(CXCursor cursor, CXCursor parent) { CXFile file; unsigned int line, column, offset; clang_getInstantiationLocation( clang_getCursorLocation(cursor), &file, &line, &column, &offset); CXCursorKind kind = clang_getCursorKind(cursor); const char* cursorFilename = clang_getCString(clang_getFileName(file)); if (!clang_getFileName(file).data || strcmp(cursorFilename, translationUnitFilename) != 0) { return CXChildVisit_Continue; } CXCursor refCursor = clang_getCursorReferenced(cursor); if (!clang_equalCursors(refCursor, clang_getNullCursor())) { CXFile refFile; unsigned int refLine, refColumn, refOffset; clang_getInstantiationLocation( clang_getCursorLocation(refCursor), &refFile, &refLine, &refColumn, &refOffset); if (clang_getFileName(refFile).data) { std::string referencedUsr(clang_getCString(clang_getCursorUSR(refCursor))); if (!referencedUsr.empty()) { std::stringstream ss; ss << cursorFilename << ":" << line << ":" << column << ":" << kind; std::string location(ss.str()); usrToReferences[referencedUsr].insert(location); } } } return CXChildVisit_Recurse; }
std::string Cursor::get_usr() const { UniqueCXString cx_string(clang_getCursorUSR(m_cx_cursor)); if ( !cx_string ) { CLANGXX_THROW_LogicError("Error retrieving a Unified Symbol Resolution (USR) for the entity referenced by this cursor."); } return clang_getCString(cx_string.get()); }
void ClangParser::linkIdentifier(CodeOutputInterface &ol,FileDef *fd, uint &line,uint &column,const char *text,int tokenIndex) { CXCursor c = p->cursors[tokenIndex]; CXCursor r = clang_getCursorReferenced(c); if (!clang_equalCursors(r, c)) { c=r; // link to referenced location } CXCursor t = clang_getSpecializedCursorTemplate(c); if (!clang_Cursor_isNull(t) && !clang_equalCursors(t,c)) { c=t; // link to template } CXString usr = clang_getCursorUSR(c); const char *usrStr = clang_getCString(usr); Definition *d = usrStr ? Doxygen::clangUsrMap->find(usrStr) : 0; //CXCursorKind kind = clang_getCursorKind(c); //if (d==0) //{ // printf("didn't find definition for '%s' usr='******' kind=%d\n", // text,usrStr,kind); //} //else //{ // printf("found definition for '%s' usr='******' name='%s'\n", // text,usrStr,d->name().data()); //} if (d && d->isLinkable()) { if (g_insideBody && g_currentMemberDef && d->definitionType()==Definition::TypeMember && (g_currentMemberDef!=d || g_currentLine<line)) // avoid self-reference { addDocCrossReference(g_currentMemberDef,(MemberDef*)d); } writeMultiLineCodeLink(ol,fd,line,column,d,text); } else { codifyLines(ol,fd,text,line,column); } clang_disposeString(usr); }
void ClangParser::linkIdentifier(CodeOutputInterface &ol, QSharedPointer<FileDef> fd, uint &line, uint &column, const QString &text, int tokenIndex) { CXCursor c = p->cursors[tokenIndex]; CXCursor r = clang_getCursorReferenced(c); if (! clang_equalCursors(r, c)) { // link to referenced location c = r; } CXCursor t = clang_getSpecializedCursorTemplate(c); if (! clang_Cursor_isNull(t) && !clang_equalCursors(t, c)) { // link to template c = t; } CXString usr = clang_getCursorUSR(c); const char *usrStr = clang_getCString(usr); QSharedPointer<Definition> d; if (usrStr) { d = Doxy_Globals::clangUsrMap.value(usrStr); } if (d && d->isLinkable()) { if (g_insideBody && g_currentMemberDef && d->definitionType() == Definition::TypeMember && (g_currentMemberDef != d || g_currentLine < line)) { // avoid self-reference addDocCrossReference(g_currentMemberDef, d.dynamicCast<MemberDef>()); } writeMultiLineCodeLink(ol, fd, line, column, d, text); } else { codifyLines(ol, fd, text, line, column, ""); } clang_disposeString(usr); }
enum CXChildVisitResult USRVisitor(CXCursor C, CXCursor parent, CXClientData ClientData) { VisitorData *Data = (VisitorData *)ClientData; if (!Data->Filter || (C.kind == *(enum CXCursorKind *)Data->Filter)) { CXString USR = clang_getCursorUSR(C); if (!clang_getCString(USR)) { clang_disposeString(USR); return CXChildVisit_Continue; } printf("// %s: %s %s", FileCheckPrefix, GetCursorSource(C), clang_getCString(USR)); PrintCursorExtent(C); printf("\n"); clang_disposeString(USR); return CXChildVisit_Recurse; } return CXChildVisit_Continue; }
static void printCursor(CXCursor cursor) { CXFile file; unsigned int off, line, col; CXSourceLocation location = clang_getCursorLocation(cursor); clang_getSpellingLocation(location, &file, &line, &col, &off); CXString fileName = clang_getFileName(file); const char *fileNameCStr = clang_getCString(fileName); if (fileNameCStr) { CXSourceRange range = clang_getCursorExtent(cursor); unsigned int start, end; clang_getSpellingLocation(clang_getRangeStart(range), 0, 0, 0, &start); clang_getSpellingLocation(clang_getRangeEnd(range), 0, 0, 0, &end); printf("%s:%d:%d (%d, %d-%d) ", fileNameCStr, line, col, off, start, end); } clang_disposeString(fileName); printString("kind", clang_getCursorKindSpelling(clang_getCursorKind(cursor))); printString("display name", clang_getCursorDisplayName(cursor)); printString("usr", clang_getCursorUSR(cursor)); if (clang_isCursorDefinition(cursor)) printf("definition "); printf("\n"); }
bool IndexerJob::handleCursor(const CXCursor &cursor, CXCursorKind kind, const Location &location) { CursorInfo &info = mData->symbols[location]; if (!info.symbolLength || !RTags::isCursor(info.kind)) { CXStringScope name = clang_getCursorSpelling(cursor); const char *cstr = name.data(); info.symbolLength = cstr ? strlen(cstr) : 0; info.type = clang_getCursorType(cursor).kind; if (!info.symbolLength) { // this is for these constructs: // typedef struct { // int a; // } foobar; // // We end up not getting a spelling for the cursor switch (kind) { case CXCursor_ClassDecl: info.symbolLength = 5; info.symbolName = "class"; break; case CXCursor_UnionDecl: info.symbolLength = 5; info.symbolName = "union"; break; case CXCursor_StructDecl: info.symbolLength = 6; info.symbolName = "struct"; break; default: mData->symbols.remove(location); return false; } } else { info.symbolName = addNamePermutations(cursor, location); } CXSourceRange range = clang_getCursorExtent(cursor); unsigned start, end; clang_getSpellingLocation(clang_getRangeStart(range), 0, 0, 0, &start); clang_getSpellingLocation(clang_getRangeEnd(range), 0, 0, 0, &end); info.start = start; info.end = end; if (kind == CXCursor_EnumConstantDecl) { #if CLANG_VERSION_MINOR > 1 info.enumValue = clang_getEnumConstantDeclValue(cursor); #else info.definition = clang_isCursorDefinition(cursor); #endif } else{ info.definition = clang_isCursorDefinition(cursor); } info.kind = kind; const String usr = RTags::eatString(clang_getCursorUSR(cursor)); if (!usr.isEmpty()) mData->usrMap[usr].insert(location); switch (info.kind) { case CXCursor_Constructor: case CXCursor_Destructor: { Location parentLocation = createLocation(clang_getCursorSemanticParent(cursor)); // consider doing this for only declaration/inline definition since // declaration and definition should know of one another if (parentLocation.isValid()) { CursorInfo &parent = mData->symbols[parentLocation]; parent.references.insert(location); info.references.insert(parentLocation); } break; } case CXCursor_CXXMethod: { List<CursorInfo*> infos; infos.append(&info); addOverriddenCursors(cursor, location, infos); break; } default: break; } } return true; }
std::string cursor::unified_symbol() { return string(clang_getCursorUSR(cur)).str(); }
QCString ClangParser::lookup(uint line,const char *symbol) { //printf("ClangParser::lookup(%d,%s)\n",line,symbol); QCString result; if (symbol==0) return result; static bool clangAssistedParsing = Config_getBool(CLANG_ASSISTED_PARSING); if (!clangAssistedParsing) return result; int sl = strlen(symbol); uint l = p->getCurrentTokenLine(); while (l>=line && p->curToken>0) { if (l==line) // already at the right line { p->curToken--; // linear search to start of the line l = p->getCurrentTokenLine(); } else { p->curToken/=2; // binary search backward l = p->getCurrentTokenLine(); } } bool found=FALSE; while (l<=line && p->curToken<p->numTokens && !found) { CXString tokenString = clang_getTokenSpelling(p->tu, p->tokens[p->curToken]); //if (l==line) //{ // printf("try to match symbol %s with token %s\n",symbol,clang_getCString(tokenString)); //} const char *ts = clang_getCString(tokenString); int tl = strlen(ts); int startIndex = p->curToken; if (l==line && strncmp(ts,symbol,tl)==0) // found partial match at the correct line { int offset = tl; while (offset<sl) // symbol spans multiple tokens { //printf("found partial match\n"); p->curToken++; if (p->curToken>=p->numTokens) { break; // end of token stream } l = p->getCurrentTokenLine(); clang_disposeString(tokenString); tokenString = clang_getTokenSpelling(p->tu, p->tokens[p->curToken]); ts = clang_getCString(tokenString); tl = ts ? strlen(ts) : 0; // skip over any spaces in the symbol char c; while (offset<sl && ((c=symbol[offset])==' ' || c=='\t' || c=='\r' || c=='\n')) { offset++; } if (strncmp(ts,symbol+offset,tl)!=0) // next token matches? { //printf("no match '%s'<->'%s'\n",ts,symbol+offset); break; // no match } //printf("partial match '%s'<->'%s'\n",ts,symbol+offset); offset+=tl; } if (offset==sl) // symbol matches the token(s) { CXCursor c = p->cursors[p->curToken]; CXString usr = clang_getCursorUSR(c); //printf("found full match %s usr='******'\n",symbol,clang_getCString(usr)); result = clang_getCString(usr); clang_disposeString(usr); found=TRUE; } else // reset token cursor to start of the search { p->curToken = startIndex; } } clang_disposeString(tokenString); p->curToken++; if (p->curToken<p->numTokens) { l = p->getCurrentTokenLine(); } } //if (!found) //{ // printf("Did not find symbol %s at line %d :-(\n",symbol,line); //} //else //{ // printf("Found symbol %s usr=%s\n",symbol,result.data()); //} return result; }
String cursorToString(CXCursor cursor, unsigned flags) { const CXCursorKind kind = clang_getCursorKind(cursor); String ret; ret.reserve(256); ret += eatString(clang_getCursorKindSpelling(kind)); if (clang_isInvalid(kind)) return ret; switch (RTags::cursorType(kind)) { case Reference: ret += " r"; break; case Cursor: ret += " c"; break; case Other: ret += " o"; break; case Include: ret += " i"; break; } const String name = eatString(clang_getCursorDisplayName(cursor)); const String other = eatString(clang_getCursorSpelling(cursor)); if (!name.isEmpty()) ret += " " + name; if (other != name && !other.isEmpty()) ret += " " + other; if (clang_isCursorDefinition(cursor)) ret += " def"; if (flags & IncludeUSR) ret += " " + eatString(clang_getCursorUSR(cursor)); CXFile file; unsigned off, line, col; //presumedLine, presumedCol, instantiationLoc, expansionLoc; CXSourceLocation location = clang_getCursorLocation(cursor); clang_getSpellingLocation(location, &file, &line, &col, &off); // clang_getPresumedLocation(location, 0, &presumedLine, &presumedCol); // clang_getInstantiationLocation(location, 0, 0, 0, &instantiationLoc); // clang_getExpansionLocation(location, 0, 0, 0, &expansionLoc); const Str fileName(clang_getFileName(file)); if (fileName.data() && *fileName.data()) { ret += ' '; ret += fileName.data(); ret += ','; ret += String::number(off); if (flags & IncludeRange) { ret += " ("; CXSourceRange range = clang_getCursorExtent(cursor); unsigned start, end; clang_getSpellingLocation(clang_getRangeStart(range), 0, 0, 0, &start); clang_getSpellingLocation(clang_getRangeEnd(range), 0, 0, 0, &end); ret += String::number(start); ret += '-'; ret += String::number(end); ret += ')'; } // if (presumedLine != line || presumedCol != col) // ret += String::snprintf<32>("presumed: %d:%d", presumedLine, presumedCol); // if (instantiationLoc != off) // ret += String::snprintf<32>("instantiation: %d", instantiationLoc); // if (expansionLoc != off) // ret += String::snprintf<32>("expansion: %d", expansionLoc); } return ret; }
bool ClangIndexer::handleCursor(const CXCursor &cursor, CXCursorKind kind, const Location &location) { // error() << "Got a cursor" << cursor; std::shared_ptr<CursorInfo> &info = mData->symbols[location]; if (!info) info = std::make_shared<CursorInfo>(); if (!info->symbolLength) { // if (mLogFile) { // String out; // Log(&out) << cursor << a; // fwrite(out.constData(), 1, out.size(), mLogFile); // fwrite("\n", 1, 1, mLogFile); // } CXStringScope name = clang_getCursorSpelling(cursor); const char *cstr = name.data(); info->symbolLength = cstr ? strlen(cstr) : 0; info->type = clang_getCursorType(cursor).kind; if (!info->symbolLength) { // this is for these constructs: // typedef struct { // int a; // } foobar; // // We end up not getting a spelling for the cursor switch (kind) { case CXCursor_ClassDecl: info->symbolLength = 5; info->symbolName = "class"; break; case CXCursor_UnionDecl: info->symbolLength = 5; info->symbolName = "union"; break; case CXCursor_StructDecl: info->symbolLength = 6; info->symbolName = "struct"; break; default: mData->symbols.remove(location); return false; } } else { info->symbolName = addNamePermutations(cursor, location); } CXSourceRange range = clang_getCursorExtent(cursor); CXSourceLocation rangeStart = clang_getRangeStart(range); CXSourceLocation rangeEnd = clang_getRangeEnd(range); unsigned startLine, startColumn, endLine, endColumn; clang_getPresumedLocation(rangeStart, 0, &startLine, &startColumn); clang_getPresumedLocation(rangeEnd, 0, &endLine, &endColumn); info->startLine = startLine; info->startColumn = startColumn; info->endLine = endLine; info->endColumn = endColumn; if (kind == CXCursor_EnumConstantDecl) { #if CINDEX_VERSION_MINOR > 1 info->enumValue = clang_getEnumConstantDeclValue(cursor); #else info->definition = 1; #endif } else { info->definition = clang_isCursorDefinition(cursor); } info->kind = kind; // apparently some function decls will give a different usr for // their definition and their declaration. Using the canonical // cursor's usr allows us to join them. Check JSClassRelease in // JavaScriptCore for an example. const String usr = RTags::eatString(clang_getCursorUSR(clang_getCanonicalCursor(cursor))); if (!usr.isEmpty()) mData->usrMap[usr].insert(location); switch (info->kind) { case CXCursor_Constructor: case CXCursor_Destructor: { Location parentLocation = createLocation(clang_getCursorSemanticParent(cursor)); // consider doing this for only declaration/inline definition since // declaration and definition should know of one another if (parentLocation.isValid()) { std::shared_ptr<CursorInfo> &parent = mData->symbols[parentLocation]; if (!parent) parent = std::make_shared<CursorInfo>(); parent->references.insert(location); info->references.insert(parentLocation); } break; } case CXCursor_CXXMethod: { List<CursorInfo*> infos; infos.append(info.get()); addOverriddenCursors(cursor, location, infos); break; } default: break; } } return true; }
void ClangIndexer::handleReference(const CXCursor &cursor, CXCursorKind kind, const Location &location, const CXCursor &ref, const CXCursor &parent) { const CXCursorKind refKind = clang_getCursorKind(ref); if (clang_isInvalid(refKind)) { superclassTemplateMemberFunctionUgleHack(cursor, kind, location, ref, parent); return; } bool isOperator = false; if (kind == CXCursor_CallExpr && (refKind == CXCursor_CXXMethod || refKind == CXCursor_ConversionFunction || refKind == CXCursor_FunctionDecl || refKind == CXCursor_FunctionTemplate)) { // these are bullshit, for this construct: // foo.bar(); // the position of the cursor is at the foo, not the bar. // They are not interesting for followLocation, renameSymbol or find // references so we toss them. // For functions it can be the position of the namespace. // E.g. Foo::bar(); cursor is on Foo // For constructors they happen to be the only thing we have that // actually refs the constructor and not the class so we have to keep // them for that. return; } switch (refKind) { case CXCursor_Constructor: if (isImplicit(ref)) return; break; case CXCursor_CXXMethod: case CXCursor_FunctionDecl: case CXCursor_FunctionTemplate: { CXStringScope scope = clang_getCursorDisplayName(ref); const char *data = scope.data(); if (data) { const int len = strlen(data); if (len > 8 && !strncmp(data, "operator", 8) && !isalnum(data[8]) && data[8] != '_') { if (isImplicit(ref)) return; // eat implicit operator calls isOperator = true; } } break; } default: break; } const Location reffedLoc = createLocation(ref); if (!reffedLoc.isValid()) { if (kind == CXCursor_ObjCMessageExpr) { mData->pendingReferenceMap[RTags::eatString(clang_getCursorUSR(clang_getCanonicalCursor(ref)))].insert(location); // insert it, we'll hook up the target and references later handleCursor(cursor, kind, location); } return; } std::shared_ptr<CursorInfo> &refInfo = mData->symbols[reffedLoc]; if ((!refInfo || !refInfo->symbolLength) && !handleCursor(ref, refKind, reffedLoc)) return; refInfo->references.insert(location); std::shared_ptr<CursorInfo> &info = mData->symbols[location]; if (!info) info = std::make_shared<CursorInfo>(); info->targets.insert(reffedLoc); // We need the new cursor to replace the symbolLength. This is important // in the following case: // struct R { R(const &r); ... } // R foo(); // ... // R r = foo(); // The first cursor on foo() will be a reference to the copy constructor and // this cursor will have a symbolLength of 1. Thus you won't be able to jump // to foo from the o. This is fixed by making sure the newer target, if // better, gets to decide on the symbolLength // The !isCursor is var decls and field decls where we set up a target even // if they're not considered references if (!RTags::isCursor(info->kind) && (!info->symbolLength || info->bestTarget(mData->symbols)->kind == refKind)) { CXSourceRange range = clang_getCursorExtent(cursor); CXSourceLocation rangeStart = clang_getRangeStart(range); CXSourceLocation rangeEnd = clang_getRangeEnd(range); unsigned startLine, startColumn, endLine, endColumn; clang_getPresumedLocation(rangeStart, 0, &startLine, &startColumn); clang_getPresumedLocation(rangeEnd, 0, &endLine, &endColumn); info->startLine = startLine; info->startColumn = startColumn; info->endLine = endLine; info->endColumn = endColumn; info->definition = false; info->kind = kind; if (isOperator) { unsigned start, end; clang_getSpellingLocation(rangeStart, 0, 0, 0, &start); clang_getSpellingLocation(rangeEnd, 0, 0, 0, &end); info->symbolLength = end - start; } else { info->symbolLength = refInfo->symbolLength; } info->symbolName = refInfo->symbolName; info->type = clang_getCursorType(cursor).kind; } }
json_t* render_type(CXType type) { int i; CXCursor decl = clang_getTypeDeclaration(type); json_t* js = json_object(); enum CXTypeKind kind = type.kind; if (type.kind == CXType_Unexposed) { // workaround for libclang bug if (clang_getResultType(type).kind != CXType_Invalid) { kind = CXType_FunctionProto; } } if (clang_isVolatileQualifiedType(type)) { json_object_set_new(js, "volatile", json_true()); } if (clang_isConstQualifiedType(type)) { json_object_set_new(js, "const", json_true()); } if (clang_isRestrictQualifiedType(type)) { json_object_set_new(js, "restrict", json_true()); } static const struct { enum CXTypeKind kind; const char* name; } PRIMITIVE_TYPES[] = { {CXType_Void, "void"}, {CXType_Bool, "bool"}, {CXType_Char_U, "char"}, {CXType_Char_S, "char"}, {CXType_UChar, "unsigned char"}, {CXType_SChar, "signed char"}, {CXType_WChar, "wchar_t"}, {CXType_Char16, "char16_t"}, {CXType_Char32, "char32_t"}, {CXType_Short, "short"}, {CXType_UShort, "unsigned short"}, {CXType_Int, "int"}, {CXType_UInt, "unsigned int"}, {CXType_Long, "long"}, {CXType_ULong, "unsigned long"}, {CXType_LongLong, "unsigned long"}, {CXType_ULongLong, "unsigned long long"}, {CXType_Int128, "__int128"}, {CXType_UInt128, "unsigned __int128"}, {CXType_Float, "float"}, {CXType_Double, "double"}, {CXType_LongDouble, "long double"} }; switch (kind) { case CXType_Pointer: json_object_set_new(js, "kind", json_string("pointer")); json_object_set_new(js, "pointee", render_type(clang_getPointeeType(type))); return js; case CXType_ConstantArray: json_object_set_new(js, "kind", json_string("array")); json_object_set_new(js, "element", render_type(clang_getArrayElementType(type))); json_object_set_new(js, "length", json_integer(clang_getArraySize(type))); return js; case CXType_FunctionNoProto: case CXType_FunctionProto: json_object_set_new(js, "kind", json_string("function")); json_object_set_new(js, "return", render_type(clang_getResultType(type))); switch (clang_getFunctionTypeCallingConv(type)) { case CXCallingConv_C: json_object_set_new(js, "calling_convention", json_string("cdecl")); break; case CXCallingConv_X86StdCall: json_object_set_new(js, "calling_convention", json_string("stdcall")); break; case CXCallingConv_X86FastCall: json_object_set_new(js, "calling_convention", json_string("fastcall")); break; case CXCallingConv_X86ThisCall: json_object_set_new(js, "calling_convention", json_string("thiscall")); break; case CXCallingConv_X86Pascal: json_object_set_new(js, "calling_convention", json_string("pascal")); break; case CXCallingConv_AAPCS: json_object_set_new(js, "calling_convention", json_string("aapcs")); break; case CXCallingConv_AAPCS_VFP: json_object_set_new(js, "calling_convention", json_string("aapcs-vfp")); break; default: break; } json_t* arguments = json_array(); for (i=0; i<clang_getNumArgTypes(type); i++) { json_array_append_new(arguments, render_type(clang_getArgType(type, i))); } json_object_set_new(js, "arguments", arguments); return js; default: if (clang_getCursorKind(decl) != CXCursor_NoDeclFound) { json_object_set_new(js, "kind", json_string("ref")); json_object_set_new(js, "id", render_string(clang_getCursorUSR(decl))); } else { int found = 0, i; for (i=0; i<sizeof(PRIMITIVE_TYPES)/sizeof(PRIMITIVE_TYPES[0]); i++) { if (PRIMITIVE_TYPES[i].kind == kind) { json_object_set_new(js, "kind", json_string("primitive")); json_object_set_new(js, "primitive", json_string(PRIMITIVE_TYPES[i].name)); found = 1; break; } } if (!found) { json_object_set_new(js, "kind", json_string("unknown")); json_object_set_new(js, "clang_kind", render_string(clang_getTypeKindSpelling(kind))); } } return js; } }
enum CXChildVisitResult visit_program(CXCursor cursor, CXCursor parent, CXClientData data){ json_t* program = (json_t*)data; json_t* js = NULL; enum CXChildVisitResult ret = CXChildVisit_Continue; switch (clang_getCursorKind(cursor)) { case CXCursor_FunctionDecl: case CXCursor_VarDecl: js = json_object(); json_object_set_new(js, "name", render_string(clang_getCursorSpelling(cursor))); json_object_set_new(js, "display_name", render_string(clang_getCursorDisplayName(cursor))); json_object_set_new(js, "type", render_type(clang_getCursorType(cursor))); if (clang_getCursorKind(cursor) == CXCursor_FunctionDecl) { json_object_set_new(js, "argument_names", json_array()); json_object_set_new(js, "kind", json_string("function")); } else { json_object_set_new(js, "kind", json_string("variable")); } switch (clang_getCursorLinkage(cursor)) { case CXLinkage_Internal: json_object_set_new(js, "linkage", json_string("static")); break; case CXLinkage_UniqueExternal: json_object_set_new(js, "linkage", json_string("anonymous")); break; case CXLinkage_External: break; default: json_object_set_new(js, "linkage", json_string("unknown")); } clang_visitChildren(cursor, visit_object, (CXClientData)js); break; case CXCursor_StructDecl: case CXCursor_UnionDecl: js = json_object(); json_object_set_new(js, "kind", json_string(clang_getCursorKind(cursor) == CXCursor_UnionDecl ? "union" : "struct")); json_object_set_new(js, "name", render_string(clang_getCursorSpelling(cursor))); json_object_set_new(js, "fields", json_array()); clang_visitChildren(cursor, visit_structure, (CXClientData)js); ret = CXChildVisit_Recurse; break; case CXCursor_EnumDecl: js = json_object(); json_object_set_new(js, "kind", json_string("enum")); json_object_set_new(js, "name", render_string(clang_getCursorSpelling(cursor))); json_object_set_new(js, "values", json_array()); clang_visitChildren(cursor, visit_enum, (CXClientData)js); break; case CXCursor_TypedefDecl: js = json_object(); json_object_set_new(js, "kind", json_string("typedef")); json_object_set_new(js, "name", render_string(clang_getCursorSpelling(cursor))); json_object_set_new(js, "type", render_type(clang_getTypedefDeclUnderlyingType(cursor))); ret = CXChildVisit_Recurse; break; case CXCursor_FieldDecl: break; case CXCursor_MacroDefinition: js = json_object(); json_object_set_new(js, "kind", json_string("macro")); { CXToken* tokens; unsigned ntokens, i; CXString name = clang_getCursorSpelling(cursor); char value_buf[1024] = ""; json_object_set_new(js, "name", render_string(clang_getCursorSpelling(cursor))); clang_tokenize(TU, clang_getCursorExtent(cursor), &tokens, &ntokens); for (i=0; i<ntokens; i++) { CXString str = clang_getTokenSpelling(TU, tokens[i]); CXTokenKind tkind = clang_getTokenKind(tokens[i]); if (i == 0 && !strcmp(clang_getCString(name), clang_getCString(str))) { // macro name } else if (i == ntokens - 1 && tkind == CXToken_Punctuation && !strcmp("#", clang_getCString(str))) { // weird clang terminator thingy } else if (tkind == CXToken_Comment) { // comment } else { if (strlen(value_buf) > 0) { strncat(value_buf, " ", sizeof(value_buf) - strlen(value_buf) - 1); } strncat(value_buf, clang_getCString(str), sizeof(value_buf) - strlen(value_buf) - 1); } clang_disposeString(str); } clang_disposeTokens(TU, tokens, ntokens); if (strlen(value_buf) > 0) { long int intval; double dblval; char* endptr_int; char* endptr_dbl; intval = strtol(value_buf, &endptr_int, 0); dblval = strtod(value_buf, &endptr_dbl); if (endptr_int[0] == 0 || (endptr_int[1] == 0 && strchr("UuLl", endptr_int[0]) != NULL)) { json_object_set_new(js, "value", json_integer(intval)); } else if (endptr_dbl[0] == 0 || (endptr_dbl[1] == 0 && strchr("fF", endptr_dbl[0]) != NULL)) { json_object_set_new(js, "value", json_real(dblval)); } else { json_object_set_new(js, "value", json_string(value_buf)); } } } break; /* case CXCursor_PreprocessingDirective: case CXCursor_MacroExpansion: js = json_object(); json_object_set_new(js, "kind", json_string("macro")); json_object_set_new(js, "name", render_string(clang_getCursorSpelling(cursor))); putstring(clang_getCursorSpelling(cursor)); putstring(clang_getCursorDisplayName(cursor)); printf("%d\n", clang_getEnumConstantDeclValue(cursor)); ret = CXChildVisit_Recurse; */ default: js = json_object(); json_object_set_new(js, "name", render_string(clang_getCursorSpelling(cursor))); json_object_set_new(js, "type", render_type(clang_getCursorType(cursor))); json_object_set_new(js, "kind", json_string("wtf")); json_object_set_new(js, "wtf", render_string(clang_getCursorKindSpelling(clang_getCursorKind(cursor)))); } if (js) { json_t* str; if (!json_object_get(program, "")) json_object_set_new(program, "", json_array()); str = render_string(clang_getCursorUSR(cursor)); if (strlen(json_string_value(str)) == 0) { json_decref(str); json_array_append_new(json_object_get(program, ""), js); } else { json_object_set_with_key_new(program, render_string(clang_getCursorUSR(cursor)), js); } } return ret; }
QString ClangParser::lookup(uint line, const QString &symbol) { QString result; if (symbol.isEmpty()) { return result; } int sl = symbol.length(); uint l = p->getCurrentTokenLine(); while (l >= line && p->curToken > 0) { if (l == line) { // already at the right line p->curToken--; // linear search to start of the line l = p->getCurrentTokenLine(); } else { p->curToken /= 2; // binary search backward l = p->getCurrentTokenLine(); } } bool found = false; while (l <= line && p->curToken < p->numTokens && !found) { CXString tokenString = clang_getTokenSpelling(p->tu, p->tokens[p->curToken]); const char *ts = clang_getCString(tokenString); int tl = strlen(ts); int startIndex = p->curToken; if (l == line && strncmp(ts, symbol.toUtf8(), tl) == 0) { // found partial match at the correct line int offset = tl; while (offset < sl) { // symbol spans multiple tokens p->curToken++; if (p->curToken >= p->numTokens) { break; // end of token stream } l = p->getCurrentTokenLine(); clang_disposeString(tokenString); tokenString = clang_getTokenSpelling(p->tu, p->tokens[p->curToken]); ts = clang_getCString(tokenString); tl = ts ? strlen(ts) : 0; // skip over any spaces in the symbol QChar c; while (offset < sl && ((c = symbol[offset]) == ' ' || c == '\t' || c == '\r' || c == '\n')) { offset++; } if (strncmp(ts, symbol.mid(offset).toUtf8(), tl) != 0) { // next token matches? break; // no match } offset += tl; } if (offset == sl) { // symbol matches the token(s) CXCursor c = p->cursors[p->curToken]; CXString usr = clang_getCursorUSR(c); result = clang_getCString(usr); clang_disposeString(usr); found = true; } else { // reset token cursor to start of the search p->curToken = startIndex; } } clang_disposeString(tokenString); p->curToken++; if (p->curToken < p->numTokens) { l = p->getCurrentTokenLine(); } } return result; }
Utf8String Cursor::unifiedSymbolResolution() const { return ClangString(clang_getCursorUSR(cxCursor)); }