int ClassHierarchyJob::execute() { Symbol symbol = project()->findSymbol(location); if (symbol.isNull()) return 1; if (!symbol.isClass() || !symbol.isDefinition()) symbol = project()->findTarget(symbol.location); if (!symbol.isClass()) return 1; typedef std::function<Set<Symbol>(const Symbol &)> FindFunc; std::function<void (const Symbol &, const char *title, int, FindFunc)> recurse = [&](const Symbol &symbol, const char *title, int indent, FindFunc find) { auto classes = find(symbol); if (!indent) { if (classes.isEmpty()) { return; } write(title); indent = 2; write<256>(" %s\t%s", symbol.symbolName.constData(), symbol.location.key(keyFlags()).constData()); } else { write<256>("%s%s\t%s", String(indent, ' ').constData(), symbol.symbolName.constData(), symbol.location.key(keyFlags()).constData()); } for (const Symbol &sym : classes) { recurse(sym, title, indent + 2, find); } }; recurse(symbol, "Superclasses:", 0, [this](const Symbol &sym) { Set<Symbol> ret; for (const String &usr : sym.baseClasses) { for (const auto &s : project()->findByUsr(usr, sym.location.fileId(), Project::ArgDependsOn)) { if (s.isDefinition()) { ret.insert(s); break; } } } return ret; }); recurse(symbol, "Subclasses:", 0, [this](const Symbol &sym) { return project()->findSubclasses(sym); }); return 0; }
bool QueryJob::write(const Location &location, Flags<WriteFlag> flags) { if (location.isNull()) return false; if (!(flags & Unfiltered)) { if (!filterLocation(location)) return false; flags |= Unfiltered; } String out = location.key(keyFlags()); const bool containingFunction = queryFlags() & QueryMessage::ContainingFunction; const bool cursorKind = queryFlags() & QueryMessage::CursorKind; const bool displayName = queryFlags() & QueryMessage::DisplayName; if (containingFunction || cursorKind || displayName || !mKindFilters.isEmpty()) { int idx; Symbol symbol = project()->findSymbol(location, &idx); if (symbol.isNull()) { error() << "Somehow can't find" << location << "in symbols"; } else { if (!filterKind(symbol.kind)) return false; if (displayName) out += '\t' + symbol.displayName(); if (cursorKind) out += '\t' + symbol.kindSpelling(); if (containingFunction) { const uint32_t fileId = location.fileId(); const unsigned int line = location.line(); const unsigned int column = location.column(); auto fileMap = project()->openSymbols(location.fileId()); if (fileMap) { while (idx > 0) { symbol = fileMap->valueAt(--idx); if (symbol.location.fileId() != fileId) break; if (symbol.isDefinition() && RTags::isContainer(symbol.kind) && comparePosition(line, column, symbol.startLine, symbol.startColumn) >= 0 && comparePosition(line, column, symbol.endLine, symbol.endColumn) <= 0) { out += "\tfunction: " + symbol.symbolName; break; } } } } } } return write(out, flags); }
bool QueryJob::write(const Symbol &symbol, Flags<Symbol::ToStringFlag> toStringFlags, Flags<WriteFlag> writeFlags) { if (symbol.isNull()) return false; if (!filterLocation(symbol.location)) return false; if (!filterKind(symbol.kind)) return false; return write(symbol.toString(toStringFlags, keyFlags(), project()), writeFlags|Unfiltered); }
int ReferencesJob::execute() { const bool rename = queryFlags() & QueryMessage::Rename; std::shared_ptr<Project> proj = project(); if (!proj) return 1; Set<Symbol> refs; Map<Location, std::pair<bool, CXCursorKind> > references; if (!symbolName.isEmpty()) { const bool hasFilter = QueryJob::hasFilter(); auto inserter = [this, hasFilter](Project::SymbolMatchType type, const String &string, const Set<Location> &locs) { if (type == Project::StartsWith) { const int paren = string.indexOf('('); if (paren == -1 || paren != symbolName.size() || RTags::isFunctionVariable(string)) return; } for (const auto &l : locs) { if (!hasFilter || filter(l.path())) { locations.insert(l); } } }; proj->findSymbols(symbolName, inserter, queryFlags()); } const bool declarationOnly = queryFlags() & QueryMessage::DeclarationOnly; const bool definitionOnly = queryFlags() & QueryMessage::DefinitionOnly; Location startLocation; bool first = true; for (auto it = locations.begin(); it != locations.end(); ++it) { const Location pos = *it; Symbol sym = proj->findSymbol(pos); if (sym.isNull()) continue; if (first && !(queryFlags() & QueryMessage::NoSortReferencesByInput)) { first = false; startLocation = sym.location; } if (sym.isReference()) sym = proj->findTarget(sym); if (sym.isNull()) continue; if (rename && sym.isConstructorOrDestructor()) { const Location loc = sym.location; sym.clear(); const Set<String> usrs = proj->findTargetUsrs(loc); for (const String &usr : usrs) { for (const Symbol &s : proj->findByUsr(usr, loc.fileId(), Project::ArgDependsOn, loc)) { if (s.isClass()) { sym = s; if (s.isDefinition()) break; } } } if (sym.isNull()) continue; } if (queryFlags() & QueryMessage::AllReferences) { const Set<Symbol> all = proj->findAllReferences(sym); for (const auto &symbol : all) { if (rename) { if (symbol.kind == CXCursor_MacroExpansion && sym.kind != CXCursor_MacroDefinition) continue; if (symbol.flags & Symbol::AutoRef) continue; } else if (sym.isClass() && symbol.isConstructorOrDestructor()) { continue; } const bool def = symbol.isDefinition(); if (def) { if (declarationOnly) continue; } else if (definitionOnly) { continue; } references[symbol.location] = std::make_pair(def, symbol.kind); } } else if (queryFlags() & QueryMessage::FindVirtuals) { const Set<Symbol> virtuals = proj->findVirtuals(sym); for (const auto &symbol : virtuals) { const bool def = symbol.isDefinition(); if (def) { if (declarationOnly) continue; } else if (definitionOnly) { continue; } references[symbol.location] = std::make_pair(def, symbol.kind); } } else { const Set<Symbol> symbols = proj->findCallers(sym); for (const auto &symbol : symbols) { const bool def = symbol.isDefinition(); if (def) { if (declarationOnly) continue; } else if (definitionOnly) { continue; } references[symbol.location] = std::make_pair(false, CXCursor_FirstInvalid); } } } Flags<QueryJob::WriteFlag> writeFlags; Flags<Location::KeyFlag> kf = keyFlags(); if (queryFlags() & QueryMessage::Elisp) { write("(list ", DontQuote); writeFlags |= QueryJob::NoContext; } else if (queryFlags() & QueryMessage::NoContext) { writeFlags |= QueryJob::NoContext; } auto writeCons = [this](const String &car, const String &cdr) { write("(cons ", DontQuote); write(car, DontQuote); write(cdr); write(")", DontQuote); }; auto writeLoc = [this, writeCons, writeFlags, kf](const Location &loc) { if (queryFlags() & QueryMessage::Elisp) { if (!filterLocation(loc)) return; write("(list ", DontQuote); locationToString(loc, [writeCons, this](LocationPiece piece, const String &string) { switch (piece) { case Piece_ContainingFunctionLocation: if (queryFlags() & QueryMessage::ContainingFunctionLocation) writeCons("'cfl", string); break; case Piece_ContainingFunctionName: if (queryFlags() & QueryMessage::ContainingFunction) writeCons("'cf", string); break; case Piece_Location: writeCons("'loc", string); break; case Piece_Context: if (!(queryFlags() & QueryMessage::NoContext)) writeCons("'ctx", string); break; case Piece_SymbolName: case Piece_Kind: break; } }); write(")", DontQuote); } else { write(loc, writeFlags); } }; if (rename) { if (!references.isEmpty()) { if (queryFlags() & QueryMessage::ReverseSort) { Map<Location, std::pair<bool, CXCursorKind> >::const_iterator it = references.end(); do { --it; writeLoc(it->first); } while (it != references.begin()); } else { for (const auto &it : references) { writeLoc(it.first); } } } } else { List<RTags::SortedSymbol> sorted; sorted.reserve(references.size()); for (Map<Location, std::pair<bool, CXCursorKind> >::const_iterator it = references.begin(); it != references.end(); ++it) { sorted.append(RTags::SortedSymbol(it->first, it->second.first, it->second.second)); } if (queryFlags() & QueryMessage::ReverseSort) { std::sort(sorted.begin(), sorted.end(), std::greater<RTags::SortedSymbol>()); } else { std::sort(sorted.begin(), sorted.end()); } int startIndex = 0; const int count = sorted.size(); if (!startLocation.isNull()) { for (int i=0; i<count; ++i) { if (sorted.at(i).location == startLocation) { startIndex = i + 1; break; } } } for (int i=0; i<count; ++i) { const Location &loc = sorted.at((startIndex + i) % count).location; writeLoc(loc); } } if (queryFlags() & QueryMessage::Elisp) write(")", DontQuote); return references.isEmpty() ? 1 : 0; }