static int Next(sqlite3_tokenizer_cursor *pCursor, const char **ppToken, int *pnBytes, int *piStartOffset, int *piEndOffset, int *piPosition) { if (pCursor) { CursorInfo *info = ((Cursor *) pCursor)->info; if (info) { return info->step(ppToken, pnBytes, piStartOffset, piEndOffset, piPosition); } } return SQLITE_NOMEM; }
static inline void allImpl(const SymbolMap &map, const Location &loc, const CursorInfo &info, SymbolMap &out, Mode mode, CXCursorKind kind) { if (out.contains(loc)) return; out[loc] = info; typedef SymbolMap (CursorInfo::*Function)(const SymbolMap &map) const; const SymbolMap targets = info.targetInfos(map); for (SymbolMap::const_iterator t = targets.begin(); t != targets.end(); ++t) { bool ok = false; switch (mode) { case VirtualRefs: case NormalRefs: ok = (t->second.kind == kind); break; case ClassRefs: ok = (t->second.isClass() || t->second.kind == CXCursor_Destructor || t->second.kind == CXCursor_Constructor); break; } if (ok) allImpl(map, t->first, t->second, out, mode, kind); } const SymbolMap refs = info.referenceInfos(map); for (SymbolMap::const_iterator r = refs.begin(); r != refs.end(); ++r) { switch (mode) { case NormalRefs: out[r->first] = r->second; break; case VirtualRefs: if (r->second.kind == kind) { allImpl(map, r->first, r->second, out, mode, kind); } else { out[r->first] = r->second; } break; case ClassRefs: if (info.isClass()) // for class/struct we want the references inserted directly regardless and also recursed out[r->first] = r->second; if (r->second.isClass() || r->second.kind == CXCursor_Destructor || r->second.kind == CXCursor_Constructor) { // if is a constructor/destructor/class reference we want to recurse it allImpl(map, r->first, r->second, out, mode, kind); } } } }
void FollowLocationJob::execute() { Scope<const SymbolMap&> scope = project()->lockSymbolsForRead(); if (scope.isNull()) return; const SymbolMap &map = scope.data(); const SymbolMap::const_iterator it = RTags::findCursorInfo(map, location); if (it == map.end()) return; const CursorInfo &cursorInfo = it->second; if (cursorInfo.isClass() && cursorInfo.isDefinition()) return; Location loc; CursorInfo target = cursorInfo.bestTarget(map, &loc); if (!loc.isNull()) { if (cursorInfo.kind != target.kind) { if (!target.isDefinition() && !target.targets.isEmpty()) { switch (target.kind) { case CXCursor_ClassDecl: case CXCursor_ClassTemplate: case CXCursor_StructDecl: case CXCursor_FunctionDecl: case CXCursor_CXXMethod: case CXCursor_Destructor: case CXCursor_Constructor: case CXCursor_FunctionTemplate: target = target.bestTarget(map, &loc); break; default: break; } } } if (!loc.isNull()) { write(loc); } } }
void ReferencesJob::execute() { shared_ptr<Project> proj = project(); Location startLocation; Set<Location> references; if (proj) { if (!symbolName.isEmpty()) { Scope<const SymbolNameMap&> scope = proj->lockSymbolNamesForRead(); if (scope.isNull()) return; locations = scope.data().value(symbolName); } if (!locations.isEmpty()) { Scope<const SymbolMap&> scope = proj->lockSymbolsForRead(); if (scope.isNull()) return; const SymbolMap &map = scope.data(); for (Set<Location>::const_iterator it = locations.begin(); it != locations.end(); ++it) { Location pos; CursorInfo cursorInfo = RTags::findCursorInfo(map, *it, &pos); if (startLocation.isNull()) startLocation = pos; if (RTags::isReference(cursorInfo.kind)) { cursorInfo = cursorInfo.bestTarget(map, &pos); } if (queryFlags() & QueryMessage::ReferencesForRenameSymbol) { const SymbolMap all = cursorInfo.allReferences(pos, map); bool classRename = false; switch (cursorInfo.kind) { case CXCursor_Constructor: case CXCursor_Destructor: classRename = true; break; default: classRename = cursorInfo.isClass(); break; } for (SymbolMap::const_iterator a = all.begin(); a != all.end(); ++a) { if (!classRename) { references.insert(a->first); } else { enum State { FoundConstructor = 0x1, FoundClass = 0x2, FoundReferences = 0x4 }; unsigned state = 0; const SymbolMap targets = a->second.targetInfos(map); for (SymbolMap::const_iterator t = targets.begin(); t != targets.end(); ++t) { if (t->second.kind != a->second.kind) state |= FoundReferences; if (t->second.kind == CXCursor_Constructor) { state |= FoundConstructor; } else if (t->second.isClass()) { state |= FoundClass; } } if ((state & (FoundConstructor|FoundClass)) != FoundConstructor || !(state & FoundReferences)) { references.insert(a->first); } } } } else if (queryFlags() & QueryMessage::FindVirtuals) { const SymbolMap virtuals = cursorInfo.virtuals(pos, map); for (SymbolMap::const_iterator v = virtuals.begin(); v != virtuals.end(); ++v) { references.insert(v->first); } } else { const SymbolMap callers = cursorInfo.callers(pos, map); for (SymbolMap::const_iterator c = callers.begin(); c != callers.end(); ++c) { references.insert(c->first); } } } } } List<Location> sorted = references.toList(); if (queryFlags() & QueryMessage::ReverseSort) { std::sort(sorted.begin(), sorted.end(), std::greater<Location>()); } else { std::sort(sorted.begin(), sorted.end()); } // We don't want to do the startIndex stuff when renaming. The only way to // tell the difference between rtags-find-all-references and // rtags-rename-symbol is that the latter does a reverse sort. It kinda // doesn't make sense to have this behavior in reverse sort anyway so I // won't formalize the rename parameters to indicate that we're renaming int startIndex = 0; const int count = sorted.size(); if (!(queryFlags() & QueryMessage::ReverseSort) && sorted.size() != 1 && !startLocation.isNull()) { startIndex = sorted.indexOf(startLocation) + 1; } const unsigned keyFlags = Job::keyFlags(); for (int i=0; i<count; ++i) { const Location &loc = sorted.at((startIndex + i) % count); write(loc.key(keyFlags)); } }