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 &sym, const char *title, int indent, FindFunc find) { auto classes = find(sym); if (!indent) { if (classes.isEmpty()) { return; } write(title); indent = 2; write<256>(" %s\t%s", sym.symbolName.constData(), sym.location.toString(locationToStringFlags()).constData()); } else { write<256>("%s%s\t%s", String(indent, ' ').constData(), sym.symbolName.constData(), sym.location.toString(locationToStringFlags()).constData()); } for (const Symbol &c : classes) { recurse(c, 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::locationToString(Location location, const std::function<void(LocationPiece, const String &)> &cb, Flags<WriteFlag> writeFlags) { if (location.isNull()) return false; Flags<Location::ToStringFlag> kf = locationToStringFlags(); kf &= ~Location::ShowContext; cb(Piece_Location, location.toString(kf, &mContextCache)); if (!(writeFlags & NoContext) && !(queryFlags() & QueryMessage::NoContext)) cb(Piece_Context, location.context(kf, &mContextCache)); const bool containingFunction = queryFlags() & QueryMessage::ContainingFunction; const bool containingFunctionLocation = queryFlags() & QueryMessage::ContainingFunctionLocation; const bool cursorKind = queryFlags() & QueryMessage::CursorKind; const bool displayName = queryFlags() & QueryMessage::DisplayName; if (containingFunction || containingFunctionLocation || 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 (!mKindFilters.filter(symbol)) return false; if (displayName) cb(Piece_SymbolName, symbol.displayName()); if (cursorKind) cb(Piece_Kind, symbol.kindSpelling()); if (containingFunction || containingFunctionLocation) { 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) { if (containingFunction) cb(Piece_ContainingFunctionName, symbol.symbolName); if (containingFunctionLocation) cb(Piece_ContainingFunctionLocation, symbol.location.toString(locationToStringFlags() & ~Location::ShowContext)); break; } } } } } } return true; }
bool QueryJob::write(const Symbol &symbol, Flags<WriteFlag> writeFlags) { Flags<Symbol::ToStringFlag> toStringFlags; if (queryFlags() & QueryMessage::SymbolInfoIncludeTargets) toStringFlags |= Symbol::IncludeTargets; if (queryFlags() & QueryMessage::SymbolInfoIncludeReferences) toStringFlags |= Symbol::IncludeReferences; if (queryFlags() & QueryMessage::SymbolInfoIncludeParents) toStringFlags |= Symbol::IncludeParents; if (queryFlags() & QueryMessage::SymbolInfoIncludeBaseClasses) toStringFlags |= Symbol::IncludeBaseClasses; if (queryFlags() & (QueryMessage::ContainingFunction|QueryMessage::JSON|QueryMessage::Elisp)) toStringFlags |= Symbol::IncludeContainingFunction; if (queryFlags() & (QueryMessage::ContainingFunctionLocation|QueryMessage::JSON|QueryMessage::Elisp)) toStringFlags |= Symbol::IncludeContainingFunctionLocation; if (symbol.isNull()) return false; if (!filterLocation(symbol.location)) return false; if (!mKindFilters.filter(symbol)) return false; String out; if (queryFlags() & (QueryMessage::Elisp|QueryMessage::JSON)) { Value val = symbol.toValue(project(), toStringFlags, locationToStringFlags() | Location::NoColor, mPieceFilters); if (queryFlags() & QueryMessage::Elisp) { out = RTags::toElisp(val); } else { out = val.toJSON(); } } else { out = symbol.toString(project(), toStringFlags, locationToStringFlags(), mPieceFilters); } return write(out, writeFlags|Unfiltered); }
int StatusJob::execute() { auto match = [this](const char *name) { return !strncasecmp(query.constData(), name, query.size()); }; bool matched = false; const char *alternatives = "fileids|watchedpaths|dependencies|cursors|symbols|targets|symbolnames|sources|jobs|info|compilers|headererrors|memory"; if (match("fileids")) { matched = true; if (!write(delimiter) || !write("fileids") || !write(delimiter)) return 1; const Hash<uint32_t, Path> paths = Location::idsToPaths(); for (Hash<uint32_t, Path>::const_iterator it = paths.begin(); it != paths.end(); ++it) { if (!write<256>(" %u: %s", it->first, it->second.constData())) return 1; } if (isAborted()) return 1; } if (match("headererrors")) { matched = true; if (!write(delimiter) || !write("headererrors") || !write(delimiter)) return 1; for (auto err : Server::instance()->jobScheduler()->headerErrors()) { if (!write(Location::path(err))) return 1; } if (isAborted()) return 1; } if (query.isEmpty() || match("info")) { matched = true; if (!write(delimiter) || !write("info") || !write(delimiter)) return 1; String out; Log log(&out); #ifdef NDEBUG out << "Running a release build\n"; #else out << "Running a debug build\n"; #endif const Server::Options &opt = Server::instance()->options(); out << "socketFile" << opt.socketFile << '\n' << "dataDir" << opt.dataDir << '\n' << "options" << opt.options << "jobCount" << opt.jobCount << '\n' << "rpVisitFileTimeout" << opt.rpVisitFileTimeout << '\n' << "rpIndexDataMessageTimeout" << opt.rpIndexDataMessageTimeout << '\n' << "rpConnectTimeout" << opt.rpConnectTimeout << '\n' << "rpConnectTimeout" << opt.rpConnectTimeout << '\n' << "threadStackSize" << opt.threadStackSize << '\n' << "defaultArguments" << opt.defaultArguments << '\n' << "includePaths" << opt.includePaths << '\n' << "defines" << opt.defines << '\n' << "ignoredCompilers" << opt.ignoredCompilers; write(out); } std::shared_ptr<Project> proj = project(); if (!proj) { if (!matched) write(alternatives); return matched ? 0 : 1; } if (query.isEmpty() || match("watchedpaths")) { matched = true; if (!write(delimiter) || !write("watchedpaths") || !write(delimiter)) return 1; Hash<Path, Flags<Project::WatchMode> > watched = proj->watchedPaths(); auto watchModeToString = [](Flags<Project::WatchMode> mode) { List<String> ret; if (mode & Project::Watch_FileManager) ret << "filemanager"; if (mode & Project::Watch_SourceFile) ret << "source"; if (mode & Project::Watch_Dependency) ret << "dependency"; if (mode & Project::Watch_CompilationDatabase) ret << "compilationdatabase"; return String::join(ret, '|'); }; for (const auto &it : watched) { if (!write<256>(" %s (%s)", it.first.constData(), watchModeToString(it.second).constData())) { return 1; } } } const Dependencies &deps = proj->dependencies(); if (query.isEmpty() || match("dependencies")) { matched = true; if (!write(delimiter) || !write("dependencies") || !write(delimiter)) return 1; for (auto it : deps) { write(proj->dumpDependencies(it.first)); } if (isAborted()) return 1; } if (query.isEmpty() || match("symbols") || match("cursors")) { matched = true; write(delimiter); write("symbols"); write(delimiter); for (const auto &dep : deps) { auto symbols = proj->openSymbols(dep.first); if (!symbols) continue; const int count = symbols->count(); for (int i=0; i<count; ++i) { const Location loc = symbols->keyAt(i); const Symbol c = symbols->valueAt(i); write(loc); write(c); write("------------------------"); if (isAborted()) return 1; } } } if (query.isEmpty() || match("targets")) { matched = true; write(delimiter); write("targets"); write(delimiter); for (const auto &dep : deps) { auto targets = proj->openTargets(dep.first); if (!targets) continue; const int count = targets->count(); for (int i=0; i<count; ++i) { const String usr = targets->keyAt(i); write<128>(" %s", usr.constData()); for (const auto &t : proj->findByUsr(usr, dep.first, Project::ArgDependsOn)) { write<1024>(" %s\t%s", t.location.toString(locationToStringFlags()).constData(), t.kindSpelling().constData()); } for (const auto &location : targets->valueAt(i)) { write<1024>(" %s", location.toString(locationToStringFlags()).constData()); } write("------------------------"); if (isAborted()) return 1; } } } if (query.isEmpty() || match("symbolnames")) { matched = true; write(delimiter); write("symbolnames"); write(delimiter); for (const auto &dep : deps) { auto symNames = proj->openSymbolNames(dep.first); if (!symNames) continue; const int count = symNames->count(); for (int i=0; i<count; ++i) { write<128>(" %s", symNames->keyAt(i).constData()); for (const Location &loc : symNames->valueAt(i)) { write<1024>(" %s", loc.toString().constData()); } write("------------------------"); if (isAborted()) return 1; } } } if (query.isEmpty() || match("sources")) { matched = true; const Sources &map = proj->sources(); if (!write(delimiter) || !write("sources") || !write(delimiter)) return 1; for (Sources::const_iterator it = map.begin(); it != map.end(); ++it) { if (!write<512>(" %s: %s", it->second.sourceFile().constData(), it->second.toString().constData())) return 1; } } if (query.isEmpty() || match("jobs")) { matched = true; if (!write(delimiter) || !write("jobs") || !write(delimiter)) return 1; Server::instance()->dumpJobs(connection()); } if (query.isEmpty() || match("compilers")) { matched = true; if (!write(delimiter) || !write("compilers") || !write(delimiter)) return 1; Source source; for (const Path &compiler : CompilerManager::compilers()) { source.compilerId = Location::insertFile(compiler); source.defines.clear(); source.includePaths.clear(); CompilerManager::applyToSource(source, true, true); write(compiler); write(" Defines:"); for (const auto &it : source.defines) write<512>(" %s", it.toString().constData()); write(" Includepaths:"); for (const auto &it : source.includePaths) write<512>(" %s", it.toString().constData()); write(""); } } if (query.isEmpty() || match("memory")) { write(proj->estimateMemory()); matched = true; } if (!matched) { write<256>("rc -s %s", alternatives); return 1; } else { return 0; } }
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 size_t paren = string.indexOf('('); if (paren == String::npos || 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()) { const Symbol target = proj->findTarget(sym); if (!target.isNull() && target.kind != CXCursor_MacroExpansion) sym = target; } 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::ToStringFlag> kf = locationToStringFlags(); 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](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) { Location loc = sorted.at((startIndex + i) % count).location; writeLoc(loc); } } if (queryFlags() & QueryMessage::Elisp) write(")", DontQuote); return references.isEmpty() ? 1 : 0; }