String CursorInfo::toString(unsigned cursorInfoFlags, unsigned keyFlags) const { String ret = String::format<1024>("SymbolName: %s\n" "Kind: %s\n" "%s" // type "SymbolLength: %u\n" "%s" // range "%s" // enumValue "%s", // definition symbolName.constData(), kindSpelling().constData(), kind >= JSInvalid ? "" : String::format<32>("Type: %s\n", RTags::eatString(clang_getTypeKindSpelling(type)).constData()).constData(), symbolLength, start != -1 && end != -1 ? String::format<32>("Range: %d-%d\n", start, end).constData() : "", #if CINDEX_VERSION_MINOR > 1 kind == CXCursor_EnumConstantDecl ? String::format<32>("Enum Value: %lld\n", enumValue).constData() : #endif "", isDefinition() ? "Definition\n" : ""); if (!targets.isEmpty() && !(cursorInfoFlags & IgnoreTargets)) { ret.append("Targets:\n"); for (Set<Location>::const_iterator tit = targets.begin(); tit != targets.end(); ++tit) { const Location &l = *tit; ret.append(String::format<128>(" %s\n", l.key(keyFlags).constData())); } } if (!references.isEmpty() && !(cursorInfoFlags & IgnoreReferences)) { ret.append("References:\n"); for (Set<Location>::const_iterator rit = references.begin(); rit != references.end(); ++rit) { const Location &l = *rit; ret.append(String::format<128>(" %s\n", l.key(keyFlags).constData())); } } return ret; }
String Symbol::toString(const std::shared_ptr<Project> &project, const Flags<ToStringFlag> cursorInfoFlags, Flags<Location::ToStringFlag> locationToStringFlags, const Set<String> &pieceFilters) const { auto filterPiece = [&pieceFilters](const char *name) { return pieceFilters.isEmpty() || pieceFilters.contains(name); }; auto properties = [this, &filterPiece]() -> String { List<String> ret; if (isDefinition() && filterPiece("definition")) ret << "Definition"; if (isContainer() && filterPiece("container")) ret << "Container"; if ((flags & PureVirtualMethod) == PureVirtualMethod && filterPiece("purevirtual")) ret << "Pure Virtual"; if (flags & VirtualMethod && filterPiece("virtual")) ret << "Virtual"; if (flags & ConstMethod) { if (filterPiece("constmethod")) ret << "ConstMethod"; } else if (flags & StaticMethod && filterPiece("static")) { ret << "Static"; } if (flags & Variadic && filterPiece("variadic")) ret << "Variadic"; if (flags & Auto && filterPiece("auto")) ret << "Auto"; if (flags & MacroExpansion && filterPiece("macroexpansion")) ret << "MacroExpansion"; if (flags & TemplateSpecialization && filterPiece("templatespecialization")) ret << "TemplateSpecialization"; if (flags & TemplateReference && filterPiece("templatereference")) ret << "TemplateReference"; if (ret.isEmpty()) return String(); return String::join(ret, ' ') + '\n'; }; List<String> bases; List<String> args; if (project) { if (filterPiece("baseclasses")) { for (const auto &base : baseClasses) { bool found = false; for (const auto &sym : project->findByUsr(base, location.fileId(), Project::ArgDependsOn)) { bases << sym.symbolName; found = true; break; } if (!found) { bases << base; } } } if (filterPiece("arguments")) { for (const auto &arg : arguments) { const String symName = project->findSymbol(arg.cursor).symbolName; if (!symName.isEmpty()) { args << symName; } else { args << arg.cursor.toString(locationToStringFlags & ~Location::ShowContext); } } } } else if (filterPiece("baseClasses")) { bases = baseClasses; } String ret; auto writePiece = [&ret, &filterPiece](const char *key, const char *filter, const String &piece) { if (piece.isEmpty()) return; if (!filterPiece(filter)) return; if (key && strlen(key)) ret << key << ": "; ret << piece << "\n"; }; writePiece(0, "location", location.toString(locationToStringFlags)); writePiece("SymbolName", "symbolname", symbolName); writePiece("Kind", "kind", kindSpelling()); if (filterPiece("type")) { if (!typeName.isEmpty()) { ret += "Type: " + typeName + "\n"; } else if (type != CXType_Invalid) { ret += "Type: " + RTags::eatString(clang_getTypeKindSpelling(type)) + "\n"; } } writePiece("SymbolLength", "symbollength", std::to_string(symbolLength)); if (startLine != -1) writePiece("Range", "range", String::format<32>("%d:%d-%d:%d", startLine, startColumn, endLine, endColumn)); #if CINDEX_VERSION_MINOR > 1 if (kind == CXCursor_EnumConstantDecl) writePiece("Enum Value", "enumvalue", String::format<32>("%lld/0x%0llx", static_cast<long long>(enumValue), static_cast<long long>(enumValue))); if (isDefinition() && RTags::isFunction(kind)) writePiece("Stack cost", "stackcost", std::to_string(stackCost)); #endif writePiece(0, "linkage", linkageSpelling(linkage)); ret += properties(); writePiece("Usr", "usr", usr); if (size) writePiece("sizeof", "sizeof", std::to_string(size)); if (fieldOffset >= 0) writePiece("Field offset (bits/bytes)", "fieldoffset", String::format<32>("%d/%d", fieldOffset, fieldOffset / 8)); if (alignment >= 0) writePiece("Alignment", "alignment", std::to_string(alignment)); if (!args.isEmpty()) writePiece("Arguments", "arguments", String::join(args, ", ")); if (!bases.isEmpty()) writePiece("Base classes", "baseclasses", String::join(bases, ", ")); writePiece("Brief comment", "briefcomment", briefComment); writePiece("XML comment", "xmlcomment", xmlComment); if ((cursorInfoFlags & IncludeParents && filterPiece("parent")) || (cursorInfoFlags & (IncludeContainingFunction) && filterPiece("cf")) || (cursorInfoFlags & (IncludeContainingFunctionLocation) && filterPiece("cfl"))) { auto syms = project->openSymbols(location.fileId()); uint32_t idx = -1; if (syms) { idx = syms->lowerBound(location); if (idx == std::numeric_limits<uint32_t>::max()) { idx = syms->count() - 1; } } const unsigned int line = location.line(); const unsigned int column = location.column(); while (idx-- > 0) { const Symbol s = syms->valueAt(idx); if (s.isDefinition() && s.isContainer() && comparePosition(line, column, s.startLine, s.startColumn) >= 0 && comparePosition(line, column, s.endLine, s.endColumn) <= 0) { if (cursorInfoFlags & IncludeContainingFunctionLocation) writePiece("Containing function location", "cfl", s.location.toString(locationToStringFlags)); if (cursorInfoFlags & IncludeContainingFunction) writePiece("Containing function", "cf", s.symbolName); if (cursorInfoFlags & IncludeParents) writePiece("Parent", "parent", s.location.toString(locationToStringFlags)); // redundant, this is a mess break; } } } if (cursorInfoFlags & IncludeTargets && project && filterPiece("targets")) { const auto targets = project->findTargets(*this); if (targets.size()) { ret.append("Targets:\n"); auto best = RTags::bestTarget(targets); ret.append(String::format<128>(" %s\n", best.location.toString(locationToStringFlags).constData())); for (const auto &tit : targets) { if (tit.location != best.location) ret.append(String::format<128>(" %s\n", tit.location.toString(locationToStringFlags).constData())); } } } if (cursorInfoFlags & IncludeReferences && project && !isReference() && filterPiece("references")) { const auto references = project->findCallers(*this); if (references.size()) { ret.append("References:\n"); for (const auto &r : references) { ret.append(String::format<128>(" %s\n", r.location.toString(locationToStringFlags).constData())); } } } return ret; }
String Symbol::toString(Flags<ToStringFlag> cursorInfoFlags, Flags<Location::ToStringFlag> locationToStringFlags, const std::shared_ptr<Project> &project) const { auto properties = [this]() { List<String> ret; if (isDefinition()) ret << "Definition"; if (isContainer()) ret << "Container"; if ((flags & PureVirtualMethod) == PureVirtualMethod) { ret << "Pure Virtual"; } else if (flags & VirtualMethod) { ret << "Virtual"; } if (flags & ConstMethod) { ret << "Const"; } else if (flags & StaticMethod) { ret << "Static"; } if (flags & Variadic) ret << "Variadic"; if (flags & Auto) ret << "Auto"; if (flags & AutoRef) ret << "AutoRef"; if (flags & MacroExpansion) ret << "MacroExpansion"; if (flags & TemplateSpecialization) ret << "TemplateSpecialization"; if (ret.isEmpty()) return String(); String joined = String::join(ret, ' '); joined += '\n'; return joined; }; List<String> bases; List<String> args; if (project) { for (const auto &base : baseClasses) { bool found = false; for (const auto &sym : project->findByUsr(base, location.fileId(), Project::ArgDependsOn, location)) { bases << sym.symbolName; found = true; break; } if (!found) { bases << base; } } for (const auto &arg : arguments) { const String symName = project->findSymbol(arg.cursor).symbolName; if (!symName.isEmpty()) { args << symName; } else { args << arg.cursor.toString(locationToStringFlags & ~Location::ShowContext); } } } else { bases = baseClasses; } auto printTypeName = [this]() { String str; if (!typeName.isEmpty()) { str = typeName; } else if (type != CXType_Invalid) { str = RTags::eatString(clang_getTypeKindSpelling(type)); } else { return String(); } return String::format<128>("Type: %s\n", str.constData()); }; String ret = String::format<1024>("%s\n" "SymbolName: %s\n" "Kind: %s\n" "%s" // type "SymbolLength: %u\n" "%s" // range "%s" // enumValue/stackCost "%s" // linkage "%s" // properties "%s" // usr "%s" // sizeof "%s" // fieldoffset "%s" // alignment "%s" // arguments "%s" // baseclasses "%s" // briefComment "%s", // xmlComment location.toString(locationToStringFlags).constData(), symbolName.constData(), kindSpelling().constData(), printTypeName().constData(), symbolLength, startLine != -1 ? String::format<32>("Range: %d:%d-%d:%d\n", startLine, startColumn, endLine, endColumn).constData() : "", #if CINDEX_VERSION_MINOR > 1 (kind == CXCursor_EnumConstantDecl ? String::format<32>("Enum Value: %lld/0x%0llx\n", static_cast<long long>(enumValue), static_cast<long long>(enumValue)).constData() : (isDefinition() && RTags::isFunction(kind) ? String::format<32>("Stack cost: %d\n", stackCost).constData() : "")), #else "", #endif linkageSpelling(linkage), properties().constData(), usr.isEmpty() ? "" : String::format<64>("Usr: %s\n", usr.constData()).constData(), size > 0 ? String::format<16>("sizeof: %d\n", size).constData() : "", fieldOffset >= 0 ? String::format<32>("field offset (bits/bytes): %d/%d\n", fieldOffset, fieldOffset / 8).constData() : "", alignment >= 0 ? String::format<32>("alignment (bytes): %d\n", alignment).constData() : "", args.isEmpty() ? "" : String::format<1024>("Arguments: %s\n", String::join(args, ", ").constData()).constData(), bases.isEmpty() ? "" : String::format<64>("BaseClasses: %s\n", String::join(bases, ", ").constData()).constData(), briefComment.isEmpty() ? "" : String::format<1024>("Brief comment: %s\n", briefComment.constData()).constData(), xmlComment.isEmpty() ? "" : String::format<16384>("XML comment: %s\n", xmlComment.constData()).constData()); if (cursorInfoFlags & IncludeTargets && project) { const auto targets = project->findTargets(*this); if (targets.size()) { ret.append("Targets:\n"); auto best = RTags::bestTarget(targets); ret.append(String::format<128>(" %s\n", best.location.toString(locationToStringFlags).constData())); for (const auto &tit : targets) { if (tit.location != best.location) ret.append(String::format<128>(" %s\n", tit.location.toString(locationToStringFlags).constData())); } } } if (cursorInfoFlags & IncludeReferences && project && !isReference()) { const auto references = project->findCallers(*this); if (references.size()) { ret.append("References:\n"); for (const auto &r : references) { ret.append(String::format<128>(" %s\n", r.location.toString(locationToStringFlags).constData())); } } } return ret; }
String Symbol::toString(Flags<ToStringFlag> cursorInfoFlags, Flags<Location::ToStringFlag> locationToStringFlags, const std::shared_ptr<Project> &project) const { auto properties = [this]() { List<String> ret; if (isDefinition()) ret << "Definition"; if (isContainer()) ret << "Container"; if ((flags & PureVirtualMethod) == PureVirtualMethod) { ret << "Pure Virtual"; } else if (flags & VirtualMethod) { ret << "Virtual"; } if (flags & ConstMethod) { ret << "Const"; } else if (flags & StaticMethod) { ret << "Static"; } if (flags & Variadic) ret << "Variadic"; if (flags & Auto) ret << "Auto"; if (flags & AutoRef) ret << "AutoRef"; if (flags & MacroExpansion) ret << "MacroExpansion"; if (flags & TemplateSpecialization) ret << "TemplateSpecialization"; if (ret.isEmpty()) return String(); String joined = String::join(ret, ' '); joined += '\n'; return joined; }; List<String> bases; if (project) { extern String findSymbolNameByUsr(const std::shared_ptr<Project> &, const String &, const Location &location); for (const auto &base : baseClasses) { const String symbolName = findSymbolNameByUsr(project, base, location); if (!symbolName.isEmpty()) { bases << symbolName; } } } else { bases = baseClasses; } auto printTypeName = [this]() { String str; if (!typeName.isEmpty()) { str = typeName; } else if (type != CXType_Invalid) { str = RTags::eatString(clang_getTypeKindSpelling(type)); } else { return String(); } return String::format<128>("Type: %s\n", str.constData()); }; String ret = String::format<1024>("SymbolName: %s\n" "Kind: %s\n" "%s" // type "SymbolLength: %u\n" "%s" // range "%s" // enumValue "%s" // linkage "%s" // properties "%s" // usr "%s" // sizeof "%s" // fieldoffset "%s" // baseclasses "%s" // briefComment "%s", // xmlComment symbolName.constData(), kindSpelling().constData(), printTypeName().constData(), symbolLength, startLine != -1 ? String::format<32>("Range: %d:%d-%d:%d\n", startLine, startColumn, endLine, endColumn).constData() : "", #if CINDEX_VERSION_MINOR > 1 kind == CXCursor_EnumConstantDecl ? String::format<32>("Enum Value: %lld\n", enumValue).constData() : #endif "", linkageSpelling(linkage), properties().constData(), usr.isEmpty() ? "" : String::format<64>("Usr: %s\n", usr.constData()).constData(), size > 0 ? String::format<16>("sizeof: %d\n", size).constData() : "", fieldOffset >= 0 ? String::format<32>("field offset (bits/bytes): %d/%d\n", fieldOffset, fieldOffset / 8).constData() : "", alignment >= 0 ? String::format<32>("alignment (bytes): %d\n", alignment).constData() : "", bases.isEmpty() ? "" : String::format<64>("BaseClasses: %s\n", String::join(bases, ", ").constData()).constData(), briefComment.isEmpty() ? "" : String::format<1024>("Brief comment: %s\n", briefComment.constData()).constData(), xmlComment.isEmpty() ? "" : String::format<16384>("Xml comment: %s\n", xmlComment.constData()).constData()); if (!(cursorInfoFlags & IgnoreTargets) && project) { extern Set<Symbol> findTargets(const std::shared_ptr<Project> &, const Symbol &); auto targets = findTargets(project, *this); if (targets.size()) { ret.append("Targets:\n"); auto best = RTags::bestTarget(targets); ret.append(String::format<128>(" %s\n", best.location.toString(locationToStringFlags).constData())); for (const auto &tit : targets) { if (tit.location != best.location) ret.append(String::format<128>(" %s\n", tit.location.toString(locationToStringFlags).constData())); } } } if (!(cursorInfoFlags & IgnoreReferences) && project && !isReference()) { extern Set<Symbol> findCallers(const std::shared_ptr<Project> &, const Symbol &); auto references = findCallers(project, *this); if (references.size()) { ret.append("References:\n"); for (const auto &r : references) { ret.append(String::format<128>(" %s\n", r.location.toString(locationToStringFlags).constData())); } } } return ret; }