static String toJSON(const Location &loc, uint32_t fileId, int length, int srcRootLength) { if (loc.fileId() == fileId) { return String::format<64>("{\"offset\":%d,\"length\":%d}", loc.offset(), length); } else { return String::format<64>("{\"file\":\"%s\",\"offset\":%d,\"length\":%d}", Location::path(loc.fileId()).constData() + srcRootLength, loc.offset(), length); } }
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; }
static inline SymbolMap::const_iterator findCursorInfo(const SymbolMap &map, const Location &location, const String &context, bool scan) { if (context.isEmpty() || !scan) { SymbolMap::const_iterator it = map.lower_bound(location); if (it != map.end() && it->first == location) { return it; } else if (it != map.begin()) { --it; if (it->first.fileId() == location.fileId()) { const int off = location.offset() - it->first.offset(); if (it->second.symbolLength > off && (context.isEmpty() || it->second.symbolName.contains(context))) { return it; } } } return map.end(); } SymbolMap::const_iterator f = map.lower_bound(location); if (f != map.begin() && (f == map.end() || f->first != location)) --f; SymbolMap::const_iterator b = f; enum { Search = 32 }; for (int j=0; j<Search; ++j) { if (f != map.end()) { if (location.fileId() != f->first.fileId()) { if (b == map.begin()) break; f = map.end(); } else if (f->second.symbolName.contains(context)) { // error() << "found it forward" << j; return f; } else { ++f; } } if (b != map.begin()) { --b; if (location.fileId() != b->first.fileId()) { if (f == map.end()) break; b = map.begin(); } else if (b->second.symbolName.contains(context)) { // error() << "found it backward" << j; return b; } } } return map.end(); }
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); }
void DumpThread::handleReference(const Location &loc, const CXCursor &ref) { if (clang_getCursorKind(ref) == CXCursor_Namespace) return; const Location refLoc = createLocation(ref); if (refLoc.isNull() || refLoc.fileId() == loc.fileId()) return; Dep *dep = mDependencies[loc.fileId()]; assert(dep); Dep *refDep = mDependencies[refLoc.fileId()]; assert(refDep); auto &refs = dep->references[refDep->fileId]; refs[loc] = refLoc; }
void IndexerJob::inclusionVisitor(CXFile includedFile, CXSourceLocation *includeStack, unsigned includeLen, CXClientData userData) { IndexerJob *job = static_cast<IndexerJob*>(userData); const Location l(includedFile, 0); const Path path = l.path(); job->mData->symbolNames[path].insert(l); const char *fn = path.fileName(); job->mData->symbolNames[String(fn, strlen(fn))].insert(l); const uint32_t fileId = l.fileId(); if (!includeLen) { job->mData->dependencies[fileId].insert(fileId); } else { for (unsigned i=0; i<includeLen; ++i) { CXFile originatingFile; clang_getSpellingLocation(includeStack[i], &originatingFile, 0, 0, 0); Location loc(originatingFile, 0); const uint32_t f = loc.fileId(); if (f) job->mData->dependencies[fileId].insert(f); } } }
void ClangIndexer::handleInclude(const CXCursor &cursor, CXCursorKind kind, const Location &location) { assert(kind == CXCursor_InclusionDirective); (void)kind; CXFile includedFile = clang_getIncludedFile(cursor); if (includedFile) { const Location refLoc = createLocation(includedFile, 1, 1); if (!refLoc.isNull()) { { String include = "#include "; const Path path = refLoc.path(); assert(mSource.fileId); mData->dependencies[refLoc.fileId()].insert(mSource.fileId); mData->symbolNames[(include + path)].insert(location); mData->symbolNames[(include + path.fileName())].insert(location); } std::shared_ptr<CursorInfo> &info = mData->symbols[location]; if (!info) info = std::make_shared<CursorInfo>(); info->targets.insert(refLoc); info->kind = cursor.kind; info->definition = false; info->symbolName = "#include " + RTags::eatString(clang_getCursorDisplayName(cursor)); info->symbolLength = info->symbolName.size() + 2; // this fails for things like: // # include <foobar.h> } } }
void ClangIndexer::superclassTemplateMemberFunctionUgleHack(const CXCursor &cursor, CXCursorKind kind, const Location &location, const CXCursor &ref, const CXCursor &parent) { // This is for references to superclass template functions. Awful awful // shit. See https://github.com/Andersbakken/rtags/issues/62 and commit // for details. I really should report this as a bug. if (kind == CXCursor_MemberRefExpr && clang_getCursorKind(parent) == CXCursor_CallExpr) { const CXCursor templateRef = RTags::findChild(cursor, CXCursor_TemplateRef); if (templateRef == CXCursor_TemplateRef) { const CXCursor classTemplate = clang_getCursorReferenced(templateRef); if (classTemplate == CXCursor_ClassTemplate) { FILE *f = fopen(location.path().constData(), "r"); if (f) { const CXSourceRange range = clang_getCursorExtent(cursor); const CXSourceLocation end = clang_getRangeEnd(range); unsigned offset; clang_getSpellingLocation(end, 0, 0, 0, &offset); String name; while (offset > 0) { fseek(f, --offset, SEEK_SET); char ch = static_cast<char>(fgetc(f)); if (isalnum(ch) || ch == '_' || ch == '~') { name.prepend(ch); } else { break; } } fclose(f); if (!name.isEmpty()) { RTags::Filter out; out.kinds.insert(CXCursor_MemberRefExpr); const int argCount = RTags::children(parent, RTags::Filter(), out).size(); RTags::Filter in(RTags::Filter::And); in.names.insert(name); in.argumentCount = argCount; const List<CXCursor> alternatives = RTags::children(classTemplate, in); switch (alternatives.size()) { case 1: // ### not sure this is correct with line/col handleReference(cursor, kind, Location(location.fileId(), location.line(), location.column() + 1), alternatives.first(), parent); break; case 0: break; default: warning() << "Can't decide which of these cursors are right for me" << cursor << alternatives << "Need to parse types"; break; } } } } } } }
void DumpThread::handleInclude(const Location &loc, const CXCursor &cursor) { CXFile includedFile = clang_getIncludedFile(cursor); if (includedFile) { CXStringScope fn = clang_getFileName(includedFile); const char *cstr = clang_getCString(fn); if (!cstr) { clang_disposeString(fn); return; } const Path p = Path::resolved(cstr); clang_disposeString(fn); const uint32_t fileId = Location::insertFile(p); Dep *&source = mDependencies[loc.fileId()]; if (!source) source = new Dep(loc.fileId()); Dep *&include = mDependencies[fileId]; if (!include) include = new Dep(fileId); source->include(include); } }
void ClangIndexer::inclusionVisitor(CXFile includedFile, CXSourceLocation *includeStack, unsigned includeLen, CXClientData userData) { ClangIndexer *indexer = static_cast<ClangIndexer*>(userData); const Location l = indexer->createLocation(includedFile, 1, 1); const uint32_t fileId = l.fileId(); if (!includeLen) { indexer->mData->dependencies[fileId].insert(fileId); } else { for (unsigned i=0; i<includeLen; ++i) { CXFile originatingFile; clang_getSpellingLocation(includeStack[i], &originatingFile, 0, 0, 0); const Location loc = indexer->createLocation(originatingFile, 1, 1); const uint32_t f = loc.fileId(); if (f) indexer->mData->dependencies[fileId].insert(f); } } }
CXChildVisitResult IndexerJob::verboseVisitor(CXCursor cursor, CXCursor, CXClientData userData) { VerboseVisitorUserData *u = reinterpret_cast<VerboseVisitorUserData*>(userData); Location loc = u->job->createLocation(cursor); if (loc.fileId()) { CXCursor ref = clang_getCursorReferenced(cursor); VerboseVisitorUserData *u = reinterpret_cast<VerboseVisitorUserData*>(userData); if (u->indent >= 0) u->out += String(u->indent, ' '); u->out += RTags::cursorToString(cursor); if (clang_equalCursors(ref, cursor)) { u->out += " refs self"; } else if (!clang_equalCursors(ref, nullCursor)) { u->out += " refs " + RTags::cursorToString(ref); } if (loc.fileId() && u->job->mVisitedFiles.contains(loc.fileId())) { if (u->job->mData->references.contains(loc)) { u->out += " used as reference\n"; } else if (u->job->mData->symbols.contains(loc)) { u->out += " used as cursor\n"; } else { u->out += " not used\n"; } } else { u->out += " not indexed\n"; } } if (u->indent >= 0) { u->indent += 2; clang_visitChildren(cursor, IndexerJob::verboseVisitor, userData); u->indent -= 2; return CXChildVisit_Continue; } else { return CXChildVisit_Recurse; } }
bool QueryJob::filterLocation(Location loc) const { if (mFileFilter && loc.fileId() != mFileFilter) return false; const int minLine = mQueryMessage ? mQueryMessage->minLine() : -1; if (minLine != -1) { assert(mQueryMessage); assert(mQueryMessage->maxLine() != -1); const int maxLine = mQueryMessage->maxLine(); assert(maxLine != -1); const int line = loc.line(); if (line < minLine || line > maxLine) { return false; } } if (!mFilters.isEmpty()) { for (const std::shared_ptr<Filter> &filter : mFilters) { if (filter->match(loc.fileId(), loc.path())) return true; } return false; } return true; }
static inline List<Path> headersForSymbol(const std::shared_ptr<Project> &project, const Location &loc) { List<Path> ret; const Path &path = loc.path(); if (path.isHeader()) { ret.append(path); if (const DependencyNode *node = project->dependencies().value(loc.fileId())) { for (const auto &dependent : node->dependents) { const Path p = Location::path(dependent.first); if (p.isHeader() && dependent.second->includes.size() == 1) { ret.append(p); // allow headers that only include one header if we don't // find anything for the real header } } } } return ret; }
int FindSymbolsJob::execute() { int ret = 2; if (std::shared_ptr<Project> proj = project()) { Set<Symbol> symbols; Location filter; const uint32_t filteredFile = fileFilter(); if (filteredFile) filter = Location(filteredFile, 0, 0); auto inserter = [proj, this, &symbols, &filter, filteredFile](Project::SymbolMatchType type, const String &symbolName, const Set<Location> &locations) { if (filter.fileId()) { auto it = locations.lower_bound(filter); if (it == locations.end() || it->fileId() != filteredFile) return; } if (type == Project::StartsWith) { const size_t paren = symbolName.indexOf('('); if (paren == String::npos || paren != string.size() || RTags::isFunctionVariable(symbolName)) return; } for (const auto &it : locations) { const Symbol sym = proj->findSymbol(it); if (!sym.isNull()) symbols.insert(sym); } }; proj->findSymbols(string, inserter, queryFlags()); if (!symbols.isEmpty()) { const List<RTags::SortedSymbol> sorted = proj->sort(symbols, queryFlags()); const Flags<WriteFlag> writeFlags = fileFilter() ? Unfiltered : NoWriteFlags; const int count = sorted.size(); ret = count ? 0 : 1; for (int i=0; i<count; ++i) { write(sorted.at(i).location, writeFlags); } } } return ret; }
CXChildVisitResult IndexerJob::dumpVisitor(CXCursor cursor, CXCursor, CXClientData userData) { DumpUserData *dump = reinterpret_cast<DumpUserData*>(userData); assert(dump); assert(dump->job); Location loc = dump->job->createLocation(cursor); if (loc.fileId()) { CXCursor ref = clang_getCursorReferenced(cursor); String out; out.reserve(256); int col = -1; if (dump->showContext) { out.append(loc.context(&col)); if (col != -1) { out.append(String::format<32>(" // %d, %d: ", col, dump->indentLevel)); } else { out.append(String::format<32>(" // %d: ", dump->indentLevel)); } } else { out.append(String(dump->indentLevel * 2, ' ')); } out.append(RTags::cursorToString(cursor, RTags::AllCursorToStringFlags)); out.append(" " + typeName(cursor) + " "); if (clang_equalCursors(ref, cursor)) { out.append("refs self"); } else if (!clang_equalCursors(ref, nullCursor)) { out.append("refs "); out.append(RTags::cursorToString(ref, RTags::AllCursorToStringFlags)); } dump->job->write(out); } ++dump->indentLevel; clang_visitChildren(cursor, IndexerJob::dumpVisitor, userData); --dump->indentLevel; return CXChildVisit_Continue; }
SymbolMap::const_iterator findCursorInfo(const SymbolMap &map, const Location &location) { if (map.isEmpty()) return map.end(); SymbolMap::const_iterator it = map.find(location); if (it != map.end()) return it; it = map.lower_bound(location); if (it == map.end()) { --it; } else { const int cmp = it->first.compare(location); if (!cmp) return it; --it; } if (location.fileId() != it->first.fileId()) return map.end(); const int off = location.offset() - it->first.offset(); if (it->second.symbolLength > off) return it; return map.end(); }
bool ClangIndexer::diagnose() { if (!mClangUnit) { return false; } List<String> compilationErrors; const unsigned diagnosticCount = clang_getNumDiagnostics(mClangUnit); Map<Location, XmlEntry> xmlEntries; for (unsigned i=0; i<diagnosticCount; ++i) { CXDiagnostic diagnostic = clang_getDiagnostic(mClangUnit, i); const CXSourceLocation diagLoc = clang_getDiagnosticLocation(diagnostic); const Location loc = createLocation(diagLoc, 0); const uint32_t fileId = loc.fileId(); if (mData->visited.value(fileId)) { const String msg = RTags::eatString(clang_getDiagnosticSpelling(diagnostic)); const CXDiagnosticSeverity sev = clang_getDiagnosticSeverity(diagnostic); XmlEntry::Type type = XmlEntry::None; switch (sev) { case CXDiagnostic_Warning: type = XmlEntry::Warning; break; case CXDiagnostic_Error: case CXDiagnostic_Fatal: type = XmlEntry::Error; break; default: break; } if (type != XmlEntry::None) { const unsigned rangeCount = clang_getDiagnosticNumRanges(diagnostic); bool ok = false; for (unsigned rangePos = 0; rangePos < rangeCount; ++rangePos) { const CXSourceRange range = clang_getDiagnosticRange(diagnostic, rangePos); const CXSourceLocation start = clang_getRangeStart(range); const CXSourceLocation end = clang_getRangeEnd(range); unsigned startOffset, endOffset; clang_getSpellingLocation(start, 0, 0, 0, &startOffset); clang_getSpellingLocation(end, 0, 0, 0, &endOffset); if (!rangePos && !startOffset && !endOffset) { // huh, range invalid? fall back to diag location break; } else { unsigned int line, column; clang_getPresumedLocation(start, 0, &line, &column); const Location key(loc.fileId(), line, column); xmlEntries[key] = XmlEntry(type, msg, endOffset - startOffset); ok = true; break; } } if (!ok) { unsigned line, column; clang_getPresumedLocation(diagLoc, 0, &line, &column); const Location key(loc.fileId(), line, column); xmlEntries[key] = XmlEntry(type, msg); // no length } } // logDirect(RTags::CompilationError, msg.constData()); const unsigned fixItCount = clang_getDiagnosticNumFixIts(diagnostic); for (unsigned f=0; f<fixItCount; ++f) { CXSourceRange range; const CXStringScope stringScope = clang_getDiagnosticFixIt(diagnostic, f, &range); CXSourceLocation start = clang_getRangeStart(range); unsigned line, column; CXString file; clang_getPresumedLocation(start, &file, &line, &column); CXStringScope fileScope(file); const Location loc = createLocation(clang_getCString(file), line, column); if (mData->visited.value(loc.fileId())) { unsigned int startOffset, endOffset; CXSourceLocation end = clang_getRangeEnd(range); clang_getSpellingLocation(start, 0, 0, 0, &startOffset); clang_getSpellingLocation(end, 0, 0, 0, &endOffset); const char *string = clang_getCString(stringScope); error("Fixit for %s:%d:%d: Replace %d characters with [%s]", loc.path().constData(), line, column, endOffset - startOffset, string); XmlEntry &entry = xmlEntries[Location(loc.fileId(), line, column)]; entry.type = XmlEntry::Fixit; if (entry.message.isEmpty()) { entry.message = String::format<64>("did you mean '%s'?", string); } entry.length = endOffset - startOffset; mData->fixIts[loc.fileId()].insert(FixIt(line, column, endOffset - startOffset, string)); } } } clang_disposeDiagnostic(diagnostic); } mData->xmlDiagnostics = "<?xml version=\"1.0\" encoding=\"utf-8\"?><checkstyle>"; if (!xmlEntries.isEmpty()) { Map<Location, XmlEntry>::const_iterator entry = xmlEntries.begin(); const Map<Location, XmlEntry>::const_iterator end = xmlEntries.end(); const char *severities[] = { "none", "warning", "error", "fixit" }; uint32_t lastFileId = 0; while (entry != end) { const Location &loc = entry->first; const XmlEntry &xmlEntry = entry->second; if (loc.fileId() != lastFileId) { if (lastFileId) mData->xmlDiagnostics += "</file>"; lastFileId = loc.fileId(); mData->xmlDiagnostics += String::format<128>("<file name=\"%s\">", loc.path().constData()); } mData->xmlDiagnostics += String::format("<error line=\"%d\" column=\"%d\" %sseverity=\"%s\" message=\"%s\"/>", loc.line(), loc.column(), (xmlEntry.length <= 0 ? "" : String::format<32>("length=\"%d\" ", xmlEntry.length).constData()), severities[xmlEntry.type], xmlEscape(xmlEntry.message).constData()); ++entry; } if (lastFileId) mData->xmlDiagnostics += "</file>"; } for (Hash<uint32_t, bool>::const_iterator it = mData->visited.begin(); it != mData->visited.end(); ++it) { if (it->second) { const Map<Location, XmlEntry>::const_iterator x = xmlEntries.lower_bound(Location(it->first, 0, 0)); if (x == xmlEntries.end() || x->first.fileId() != it->first) { const String fn = Location::path(it->first); mData->xmlDiagnostics += String::format("<file name=\"%s\"/>", fn.constData()); } } } mData->xmlDiagnostics += "</checkstyle>"; return true; }
CXChildVisitResult DumpThread::visit(const CXCursor &cursor) { if (isAborted()) return CXChildVisit_Break; const Location location = createLocation(cursor); if (!location.isNull()) { if (mQueryFlags & QueryMessage::DumpCheckIncludes) { checkIncludes(location, cursor); return CXChildVisit_Recurse; } else { Flags<Location::ToStringFlag> locationFlags; if (mQueryFlags & QueryMessage::NoColor) locationFlags |= Location::NoColor; CXSourceRange range = clang_getCursorExtent(cursor); CXSourceLocation rangeEnd = clang_getRangeEnd(range); unsigned int endLine, endColumn; clang_getPresumedLocation(rangeEnd, 0, &endLine, &endColumn); if (!(mQueryFlags & QueryMessage::DumpIncludeHeaders) && location.fileId() != mSource.fileId) { return CXChildVisit_Continue; } String message; message.reserve(256); if (!(mQueryFlags & QueryMessage::NoContext)) { message = location.context(locationFlags); } if (endLine == location.line()) { message += String::format<32>(" // %d-%d, %d: ", location.column(), endColumn, mIndentLevel); } else { message += String::format<32>(" // %d-%d:%d, %d: ", location.column(), endLine, endColumn, mIndentLevel); } message += RTags::cursorToString(cursor, RTags::AllCursorToStringFlags); message.append(" " + RTags::typeName(cursor));; if (clang_getCursorKind(cursor) == CXCursor_VarDecl) { const std::shared_ptr<RTags::Auto> autoResolved = RTags::resolveAuto(cursor); if (autoResolved && !clang_equalCursors(autoResolved->cursor, nullCursor)) { message += "auto resolves to " + RTags::cursorToString(autoResolved->cursor, RTags::AllCursorToStringFlags); } } CXCursor ref = clang_getCursorReferenced(cursor); if (clang_equalCursors(ref, cursor)) { message.append("refs self"); } else if (!clang_equalCursors(ref, nullCursor)) { message.append("refs "); message.append(RTags::cursorToString(ref, RTags::AllCursorToStringFlags)); } CXCursor canonical = clang_getCanonicalCursor(cursor); if (!clang_equalCursors(canonical, cursor) && !clang_equalCursors(canonical, nullCursor)) { message.append("canonical "); message.append(RTags::cursorToString(canonical, RTags::AllCursorToStringFlags)); } CXCursor specialized = clang_getSpecializedCursorTemplate(cursor); if (!clang_equalCursors(specialized, cursor) && !clang_equalCursors(specialized, nullCursor)) { message.append("specialized "); message.append(RTags::cursorToString(specialized, RTags::AllCursorToStringFlags)); } writeToConnetion(message); } } ++mIndentLevel; clang_visitChildren(cursor, DumpThread::visitor, this); if (isAborted()) return CXChildVisit_Break; --mIndentLevel; return CXChildVisit_Continue; }
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; }