Exemplo n.º 1
0
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 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));
    }
}