Beispiel #1
0
bool QueryJob::filter(const String &value) const
{
    if (mFilters.isEmpty() && !(queryFlags() & QueryMessage::FilterSystemIncludes))
        return true;

    const char *val = value.constData();
    while (*val && isspace(*val))
        ++val;
    const char *space = strchr(val, ' ');
    Path path;
    uint32_t fileId = 0;
    if (space) {
        path.assign(val, space - val);
    } else {
        path = val;
    }

    if (!path.isFile())
        return true; // non-file things go unfiltered

    if (queryFlags() & QueryMessage::FilterSystemIncludes && Path::isSystem(val))
        return false;
    fileId = Location::fileId(path);

    if (mFilters.isEmpty())
        return true;

    for (const std::shared_ptr<Filter> &filter : mFilters) {
        if (filter->match(fileId, path))
            return true;
    }
    return false;
}
Beispiel #2
0
int FollowLocationJob::execute()
{
    const Symbol symbol = project()->findSymbol(location);
    if (symbol.isNull())
        return 1;

    if (queryFlags() & QueryMessage::AllTargets) {
        const Set<String> usrs = project()->findTargetUsrs(location);
        for (const String &usr : usrs) {
            for (const Symbol &s : project()->findByUsr(usr, location.fileId(), Project::ArgDependsOn, location)) {
                write(s.toString());
            }
        }
    }

    const auto target = project()->findTarget(symbol);
    if (target.isNull())
        return 1;

    if (symbol.usr == target.usr) {
        write(target.location);
        return 0;
    }

    if (queryFlags() & QueryMessage::DeclarationOnly ? target.isDefinition() : !target.isDefinition()) {
        const auto other = project()->findTarget(target);
        if (!other.isNull() && other.usr == target.usr) {
            write(other.location);
            return 0;
        }
    }
    write(target.location);
    return 0;
}
Beispiel #3
0
void ListSymbolsJob::execute()
{
    Set<String> out;
    std::shared_ptr<Project> proj = project();
    if (proj) {
        if (queryFlags() & QueryMessage::IMenu) {
            out = imenu(proj);
        } else {
            out = listSymbols(proj);
        }
    }

    const bool elispList = queryFlags() & QueryMessage::ElispList;

    if (elispList) {
        write("(list", IgnoreMax|DontQuote);
        for (Set<String>::const_iterator it = out.begin(); it != out.end(); ++it) {
            write(*it);
        }
        write(")", IgnoreMax|DontQuote);
    } else {
        List<String> sorted = out.toList();
        if (queryFlags() & QueryMessage::ReverseSort) {
            std::sort(sorted.begin(), sorted.end(), std::greater<String>());
        } else {
            std::sort(sorted.begin(), sorted.end());
        }
        const int count = sorted.size();
        for (int i=0; i<count; ++i) {
            write(sorted.at(i));
        }
    }
}
Beispiel #4
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;
}
Beispiel #5
0
int ListSymbolsJob::execute()
{
    Set<String> out;
    std::shared_ptr<Project> proj = project();
    if (proj) {
        if (queryFlags() & QueryMessage::WildcardSymbolNames
                && (string.contains('*') || string.contains('?')) && !string.endsWith('*')) {
            string += '*';
        }
        List<QueryMessage::PathFilter> filters = pathFilters();
        List<Path> paths;
        for (const auto &filter : filters) {
            if (filter.mode == QueryMessage::PathFilter::Self) {
                paths.append(filter.pattern);
                if (!paths.last().isFile()) {
                    paths.clear();
                    break;
                }
            } else {
                paths.clear();
                break;
            }
        }
        if (!paths.isEmpty()) {
            out = listSymbolsWithPathFilter(proj, paths);
        } else {
            out = listSymbols(proj);
        }
    }

    if (queryFlags() & QueryMessage::Elisp) {
        write("(list", IgnoreMax | DontQuote);
        for (Set<String>::const_iterator it = out.begin(); it != out.end(); ++it) {
            write(*it);
        }
        write(")", IgnoreMax | DontQuote);
    } else {
        List<String> sorted = out.toList();
        if (queryFlags() & QueryMessage::ReverseSort) {
            std::sort(sorted.begin(), sorted.end(), std::greater<String>());
        } else {
            std::sort(sorted.begin(), sorted.end());
        }
        const int count = sorted.size();
        for (int i = 0; i < count; ++i) {
            write(sorted.at(i));
        }
    }
    return out.isEmpty() ? 1 : 0;
}
Beispiel #6
0
Set<String> ListSymbolsJob::listSymbolsWithPathFilter(const std::shared_ptr<Project> &project, const List<Path> &paths) const
{
    Set<String> out;
    const bool wildcard = queryFlags() & QueryMessage::WildcardSymbolNames && (string.contains('*') || string.contains('?'));
    const bool stripParentheses = queryFlags() & QueryMessage::StripParentheses;
    const bool caseInsensitive = queryFlags() & QueryMessage::MatchCaseInsensitive;
    const String::CaseSensitivity cs = caseInsensitive ? String::CaseInsensitive : String::CaseSensitive;
    for (size_t i=0; i<paths.size(); ++i) {
        const Path file = paths.at(i);
        const uint32_t fileId = Location::fileId(file);
        if (!fileId)
            continue;
        auto symbols = project->openSymbols(fileId);
        if (!symbols)
            continue;
        const int count = symbols->count();
        for (int j=0; j<count; ++j) {
            const Symbol &symbol = symbols->valueAt(j);
            if (!filterKind(symbol)) {
                continue;
            }
            const String &symbolName = symbol.symbolName;
            if (symbolName.isEmpty())
                continue;
            if (!string.isEmpty()) {
                if (wildcard) {
                    if (!Project::matchSymbolName(string, symbolName, cs)) {
                        continue;
                    }
                } else if (!symbolName.contains(string, cs)) {
                    continue;
                }
            }

            if (stripParentheses) {
                const int paren = symbolName.indexOf('(');
                if (paren == -1) {
                    out.insert(symbolName);
                } else {
                    if (!RTags::isFunctionVariable(symbolName))
                        out.insert(symbolName.left(paren));
                }
            } else {
                out.insert(symbolName);
            }
        }
    }
    return out;
}
Beispiel #7
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);
}
void FindSymbolsJob::execute()
{
    Map<Location, bool> out;
    shared_ptr<Project> proj = project();
    if (proj) {
        Scope<const SymbolNameMap&> scope = proj->lockSymbolNamesForRead();
        if (scope.isNull())
            return;
        const SymbolNameMap &map = scope.data();
        const SymbolNameMap::const_iterator it = map.find(string);
        if (it != map.end()) {
            const Set<Location> &locations = it->second;
            for (Set<Location>::const_iterator i = locations.begin(); i != locations.end(); ++i) {
                out[*i] = true;
            }
        }
    }

    if (out.size()) {
        Scope<const SymbolMap&> scope = proj->lockSymbolsForRead();
        const SymbolMap *map = &scope.data();
        List<RTags::SortedCursor> sorted;
        sorted.reserve(out.size());
        for (Map<Location, bool>::const_iterator it = out.begin(); it != out.end(); ++it) {
            RTags::SortedCursor node(it->first);
            if (it->second && map) {
                const SymbolMap::const_iterator found = map->find(it->first);
                if (found != map->end()) {
                    node.isDefinition = found->second.isDefinition();
                    node.kind = found->second.kind;
                }
            }
            sorted.push_back(node);
        }

        if (queryFlags() & QueryMessage::ReverseSort) {
            std::sort(sorted.begin(), sorted.end(), std::greater<RTags::SortedCursor>());
        } else {
            std::sort(sorted.begin(), sorted.end());
        }
        const uint32_t keyFlags = QueryMessage::keyFlags(queryFlags());
        const int count = sorted.size();
        for (int i=0; i<count; ++i) {
            write(sorted.at(i).location.key(keyFlags));
        }
    }
}
Beispiel #9
0
void CursorInfoJob::execute()
{
    Scope<const SymbolMap &> scope = project()->lockSymbolsForRead();
    if (scope.isNull())
        return;
    const SymbolMap &map = scope.data();
    if (map.isEmpty())
        return;
    bool moved = false;
    SymbolMap::const_iterator it = RTags::findCursorInfo(map, location, queryFlags() & QueryMessage::ValidateSymbol ? &moved : 0);
    if (moved) {
        write("Symbol has moved");
        return;
    }

    unsigned ciFlags = 0;
    if (!(queryFlags() & QueryMessage::CursorInfoIncludeTargets))
        ciFlags |= CursorInfo::IgnoreTargets;
    if (!(queryFlags() & QueryMessage::CursorInfoIncludeReferences))
        ciFlags |= CursorInfo::IgnoreReferences;
    if (it != map.end()) {
        write(it->first);
        write(it->second, ciFlags);
    } else {
        it = map.lower_bound(location);
        if (it == map.end())
            --it;
    }
    ciFlags |= CursorInfo::IgnoreTargets|CursorInfo::IgnoreReferences;
    if (it != map.begin() && queryFlags() & QueryMessage::CursorInfoIncludeParents) {
        const uint32_t fileId = location.fileId();
        const int offset = location.offset();
        while (true) {
            --it;
            if (it->first.fileId() != fileId)
                break;
            if (it->second.isDefinition() && RTags::isContainer(it->second.kind) && offset >= it->second.start && offset <= it->second.end) {
                write("====================");
                write(it->first);
                write(it->second, ciFlags);
            }
            if (it == map.begin())
                break;
        }
    }
}
Beispiel #10
0
int DependenciesJob::execute()
{
    std::shared_ptr<Project> proj = project();
    if (!proj)
        return 2;
    write(proj->dumpDependencies(mFileId, mArgs, queryFlags()));
    return 0;
}
Beispiel #11
0
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;
}
Beispiel #12
0
Set<String> ListSymbolsJob::listSymbols(const std::shared_ptr<Project> &project) const
{
    const bool hasFilter = QueryJob::hasFilter();
    const bool stripParentheses = queryFlags() & QueryMessage::StripParentheses;
    const bool imenu = queryFlags() & QueryMessage::IMenu;

    Set<String> out;
    auto inserter = [this, &project, hasFilter, stripParentheses, imenu, &out](Project::SymbolMatchType,
                    const String &string,
    const Set<Location> &locations) {
        if (hasFilter) {
            bool ok = false;
            for (const auto &l : locations) {
                if (filter(l.path())) {
                    ok = true;
                    break;
                }
            }
            if (!ok)
                return;
        }
        if (imenu) {
            const Symbol sym = project->findSymbol(*locations.begin());
            if (!isImenuSymbol(sym))
                return;
        }
        const int paren = string.indexOf('(');
        if (paren == -1) {
            out.insert(string);
        } else {
            if (!RTags::isFunctionVariable(string))
                out.insert(string.left(paren));
            if (!stripParentheses)
                out.insert(string);
        }
    };

    project->findSymbols(string, inserter, queryFlags());
    return out;
}
Beispiel #13
0
Set<String> ListSymbolsJob::listSymbols(const std::shared_ptr<Project> &project)
{
    const bool hasFilter = QueryJob::hasFilter();
    const bool stripParentheses = queryFlags() & QueryMessage::StripParentheses;
    Set<String> out;
    auto inserter = [this, hasFilter, stripParentheses, &out](Project::SymbolMatchType,
                                                              const String &string,
                                                              const Set<Location> &locations) {
        if (hasFilter) {
            bool ok = false;
            for (const auto &l : locations) {
                if (filter(l.path())) {
                    ok = true;
                    break;
                }
            }
            if (!ok)
                return;
        }
        const int paren = string.indexOf('(');
        if (paren == -1) {
            out.insert(string);
        } else {
            if (!RTags::isFunctionVariable(string))
                out.insert(string.left(paren));
            if (!stripParentheses)
                out.insert(string);
        }
    };
    if (queryFlags() & QueryMessage::WildcardSymbolNames
        && (string.contains('*') || string.contains('?'))
        && !string.endsWith('*'))
        string += '*';

    project->findSymbols(string, inserter, queryFlags());
    return out;
}
Beispiel #14
0
Set<String> ListSymbolsJob::listSymbols(const shared_ptr<Project> &project)
{
    Set<String> out;
    const bool hasFilter = Job::hasFilter();
    const bool stripParentheses = queryFlags() & QueryMessage::StripParentheses;

    Scope<const SymbolNameMap&> symbolNames = project->lockSymbolNamesForRead();
    const SymbolNameMap &map = symbolNames.data();
    SymbolNameMap::const_iterator it = string.isEmpty() ? map.begin() : map.lower_bound(string);
    int count = 0;
    while (it != map.end()) {
        const String &entry = it->first;
        ++it;
        if (!string.isEmpty() && !entry.startsWith(string))
            break;
        bool ok = true;
        if (hasFilter) {
            ok = false;
            const Set<Location> &locations = it->second;
            for (Set<Location>::const_iterator i = locations.begin(); i != locations.end(); ++i) {
                if (filter(i->path())) {
                    ok = true;
                    break;
                }
            }
        }
        if (ok) {
            const int paren = entry.indexOf('(');
            if (paren == -1) {
                out.insert(entry);
            } else {
                out.insert(entry.left(paren));
                if (!stripParentheses)
                    out.insert(entry);
            }
        }
        if (!(++count % 100) && isAborted())
            break;
    }
    return out;
}
Beispiel #15
0
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);
}
Beispiel #16
0
void IndexerJob::execute()
{
    if (isAborted())
        return;
    mTimer.start();
    mData.reset(new IndexData);
    if (mType == Dump) {
        assert(id() != -1);
        if (shared_ptr<Project> p = project()) {
            for (int i=0; i<mSourceInformation.builds.size(); ++i) {
                parse(i);
                if (mUnits.at(i).second) {
                    DumpUserData u = { 0, this, !(queryFlags() & QueryMessage::NoContext) };
                    clang_visitChildren(clang_getTranslationUnitCursor(mUnits.at(i).second),
                                        IndexerJob::dumpVisitor, &u);
                }
            }
        }
    } else {
        {
            MutexLocker lock(&mMutex);
            mStarted = true;
        }
        int errorCount = 0;
        int unitCount = 0;
        const int buildCount = mSourceInformation.builds.size();
        for (int i=0; i<buildCount; ++i) {
            if (!parse(i)) {
                goto end;
            }
            if (mUnits.at(i).second)
                ++unitCount;
        }
        mParseTime = time(0);

        for (int i=0; i<buildCount; ++i) {
            int err = 0;
            if (!visit(i) || !diagnose(i, &err))
                goto end;
            errorCount += err;
        }
        {
            mData->message += mSourceInformation.sourceFile.toTilde();
            if (buildCount > 1)
                mData->message += String::format<16>(" (%d builds)", buildCount);
            if (!unitCount) {
                mData->message += " error";
            } else if (unitCount != buildCount) {
                mData->message += String::format<16>(" (%d errors, %d ok)", buildCount - unitCount, unitCount);
            }
            mData->message += String::format<16>(" in %sms. ", String::number(mTimer.elapsed()).constData());
            if (unitCount) {
                mData->message += String::format<1024>("(%d syms, %d symNames, %d refs, %d deps, %d files)",
                                                       mData->symbols.size(), mData->symbolNames.size(), mData->references.size(),
                                                       mData->dependencies.size(), mVisitedFiles.size());
            } else if (mData->dependencies.size()) {
                mData->message += String::format<16>("(%d deps)", mData->dependencies.size());
            }
            if (mType == Dirty)
                mData->message += " (dirty)";
        }
  end:
        shared_ptr<Project> p = project();
        if (p) {
            shared_ptr<IndexerJob> job = static_pointer_cast<IndexerJob>(shared_from_this());
            p->onJobFinished(job);
        }
    }
    for (int i=0; i<mUnits.size(); ++i) {
        if (mUnits.at(i).first)
            clang_disposeIndex(mUnits.at(i).first);
        if (mUnits.at(i).second)
            clang_disposeTranslationUnit(mUnits.at(i).second);
    }
    mUnits.clear();
}
Beispiel #17
0
int TokensJob::execute()
{
    std::shared_ptr<Project> proj = project();
    if (!proj)
        return 1;
    auto map = proj->openTokens(mFileId);
    if (!map)
        return 2;

    const uint32_t count = map->count();
    uint32_t i = 0;
    if (mFrom != 0) {
        i = map->lowerBound(mFrom);
        if (i > 0 && i < count) {
            const Token val = map->valueAt(i - 1);
            if (val.offset + val.length >= mFrom)
                --i;
        }
    }

    std::function<bool(const Token &)> writeToken;
    if (queryFlags() & QueryMessage::Elisp) {
        const char *elispFormat = "(cons %d (list (cons 'length %d) (cons 'kind \"%s\") (cons 'spelling \"%s\")))";
        write("(list");
        if (queryFlags() & QueryMessage::TokensIncludeSymbols) {
            writeToken = [this, &proj, elispFormat](const Token &token) {
                String out = String::format<1024>(elispFormat,
                                                  token.offset, token.length, RTags::tokenKindSpelling(token.kind),
                                                  RTags::elispEscape(token.spelling).constData());
                const Symbol sym = proj->findSymbol(token.location);
                if (!sym.isNull()) {
                    out.chop(2);
                    out << " (cons 'symbol ";
                }
                if (!write(out))
                    return false;

                if (!sym.isNull())
                    return write(sym) && write(")))");
                return true;
            };

        } else {
            writeToken = [this, elispFormat](const Token &token) {
                return write<1024>(elispFormat,
                                   token.offset, token.length, RTags::tokenKindSpelling(token.kind),
                                   RTags::elispEscape(token.spelling).constData());
            };
        }
    } else {
        writeToken = [this](const Token &token) {
            return write(token.toString());
        };
    }

    while (i < count) {
        const Token token = map->valueAt(i++);
        if (token.offset > mTo)
            break;
        if (!writeToken(token))
            return 4;
    }

    if (queryFlags() & QueryMessage::Elisp) {
        write(")");
    }

    return 0;
}
Beispiel #18
0
int ReferencesJob::execute()
{
    std::shared_ptr<Project> proj = project();
    Location startLocation;
    Map<Location, std::pair<bool, uint16_t> > references;
    if (proj) {
        if (!symbolName.isEmpty())
            locations = proj->locations(symbolName);
        if (!locations.isEmpty()) {
            const SymbolMap &map = proj->symbols();

            for (Set<Location>::const_iterator it = locations.begin(); it != locations.end(); ++it) {
                Location pos;
                SymbolMap::const_iterator found;
                found = RTags::findCursorInfo(map, *it);
                if (found == map.end())
                    continue;
                pos = found->first;
                if (startLocation.isNull())
                    startLocation = pos;
                std::shared_ptr<CursorInfo> cursorInfo = found->second;
                if (!cursorInfo)
                    continue;
                if (RTags::isReference(cursorInfo->kind)) {
                    cursorInfo = cursorInfo->bestTarget(map, &pos);
                    if (!cursorInfo)
                        continue;
                }
                if (queryFlags() & QueryMessage::AllReferences) {
                    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[a->first] = std::make_pair(a->second->isDefinition(), a->second->kind);
                        } 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[a->first] = std::make_pair(a->second->isDefinition(), a->second->kind);
                            }
                        }
                    }
                } else if (queryFlags() & QueryMessage::FindVirtuals) {
                    const SymbolMap virtuals = cursorInfo->virtuals(pos, map);
                    const bool declarationOnly = queryFlags() & QueryMessage::DeclarationOnly;
                    for (SymbolMap::const_iterator v = virtuals.begin(); v != virtuals.end(); ++v) {
                        const bool def = v->second->isDefinition();
                        if (declarationOnly && def) {
                            const std::shared_ptr<CursorInfo> decl = v->second->bestTarget(map);
                            if (decl && !decl->isNull())
                                continue;
                        }
                        references[v->first] = std::make_pair(def, v->second->kind);
                    }
                    startLocation.clear();
                    // since one normally calls this on a declaration it kinda
                    // doesn't work that well do the clever offset thing
                    // underneath
                } else {
                    const SymbolMap callers = cursorInfo->callers(pos, map);
                    for (SymbolMap::const_iterator c = callers.begin(); c != callers.end(); ++c) {
                        references[c->first] = std::make_pair(false, CXCursor_FirstInvalid);
                        // For find callers we don't want to prefer definitions or do ranks on cursors
                    }
                }
            }
        }
    }
    enum { Rename = (QueryMessage::ReverseSort|QueryMessage::AllReferences) };
    if ((queryFlags() & Rename) == Rename) {
        if (!references.isEmpty()) {
            Map<Location, std::pair<bool, uint16_t> >::const_iterator it = references.end();
            do {
                --it;
                write(it->first);
            } while (it != references.begin());
            return 0;
        }
    } else {
        List<RTags::SortedCursor> sorted;
        sorted.reserve(references.size());
        for (Map<Location, std::pair<bool, uint16_t> >::const_iterator it = references.begin();
             it != references.end(); ++it) {
            sorted.append(RTags::SortedCursor(it->first, it->second.first, it->second.second));
        }
        if (queryFlags() & QueryMessage::ReverseSort) {
            std::sort(sorted.begin(), sorted.end(), std::greater<RTags::SortedCursor>());
        } else {
            std::sort(sorted.begin(), sorted.end());
        }
        int startIndex = 0;
        const int count = sorted.size();
        if (!startLocation.isNull() && !(queryFlags() & QueryMessage::NoSortReferencesByInput)) {
            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;
            write(loc);
        }
        if (count)
            return 0;
    }
    return 1;
}
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));
    }
}
Beispiel #20
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;
}
Beispiel #21
0
int FindFileJob::execute()
{
    std::shared_ptr<Project> proj = project();
    if (!proj) {
        return 1;
    }
    if (!proj->fileManager())
        return 1;
    const Path srcRoot = proj->path();
    assert(srcRoot.endsWith('/'));

    enum Mode {
        All,
        FilePath,
        Regex,
        Pattern,
    } mode = All;

    String::CaseSensitivity cs = String::CaseSensitive;
    if (queryFlags() & QueryMessage::MatchRegex) {
        mode = Regex;
    } else if (!mPattern.isEmpty()) {
        mode = mPattern[0] == '/' ? FilePath : Pattern;
    }
    if (queryFlags() & QueryMessage::MatchCaseInsensitive)
        cs = String::CaseInsensitive;

    String out;
    out.reserve(PATH_MAX);
    const bool absolutePath = queryFlags() & QueryMessage::AbsolutePath;
    if (absolutePath)
        out.append(srcRoot);
    const Files& dirs = proj->files();
    assert(proj->fileManager());
    if (dirs.isEmpty())
        proj->fileManager()->load(FileManager::Synchronous);
    Files::const_iterator dirit = dirs.begin();
    bool foundExact = false;
    const int patternSize = mPattern.size();
    List<String> matches;
    const bool preferExact = queryFlags() & QueryMessage::FindFilePreferExact;
    int ret = 1;
    bool firstElisp = queryFlags() & QueryMessage::Elisp;

    auto writeFile = [this, &firstElisp](const Path &path) {
        if (firstElisp) {
            firstElisp = false;
            if (!write("(list", DontQuote))
                return false;
        }
        return write(path);
    };
    while (dirit != dirs.end()) {
        const Path &dir = dirit->first;
        if (dir.size() < srcRoot.size()) {
            continue;
        } else {
            out.append(dir.constData() + srcRoot.size(), dir.size() - srcRoot.size());
        }

        const Set<String> &files = dirit->second;
        for (Set<String>::const_iterator it = files.begin(); it != files.end(); ++it) {
            const String &key = *it;
            out.append(key);
            bool ok;
            switch (mode) {
            case All:
                ok = true;
                break;
            case Regex:
                ok = Rct::contains(out, mRegex);
                break;
            case FilePath:
            case Pattern:
                if (!preferExact) {
                    ok = out.contains(mPattern, cs);
                } else {
                    const int outSize = out.size();
                    const bool exact = (outSize > patternSize && out.endsWith(mPattern) && out.at(outSize - (patternSize + 1)) == '/');
                    if (exact) {
                        ok = true;
                        if (!foundExact) {
                            matches.clear();
                            foundExact = true;
                        }
                    } else {
                        ok = !foundExact && out.contains(mPattern, cs);
                    }
                }
                if (!ok && mode == FilePath) {
                    Path p(out);
                    if (!absolutePath)
                        p.prepend(srcRoot);
                    p.resolve();
                    if (p == mPattern)
                        ok = true;
                }
                break;
            }
            if (ok) {
                ret = 0;

                Path matched = out;
                if (absolutePath)
                    matched.resolve();
                if (preferExact && !foundExact) {
                    matches.append(matched);
                } else {
                    if (!writeFile(matched))
                        return 1;
                }
            }
            out.chop(key.size());
        }
        out.chop(dir.size() - srcRoot.size());
        ++dirit;
    }
    for (List<String>::const_iterator it = matches.begin(); it != matches.end(); ++it) {
        if (!writeFile(*it)) {
            return 1;
        }
    }
    if (queryFlags() & QueryMessage::Elisp && !firstElisp && !write(")", DontQuote))
        return 1;
    return ret;
}
Beispiel #22
0
int IncludeFileJob::execute()
{
    if (mSource.isNull()) {
        return 1;
    }
    const Path directory = mSource.sourceFile().parentDir();
    Set<Location> last;
    int matches = 0;
    auto process = [&directory, this](const Set<Location> &locations) {
        for (const Location &loc : locations) {
            bool first = true;
            for (const Path &path : headersForSymbol(project(), loc)) {
                bool found = false;
                const Symbol sym = project()->findSymbol(loc);
                switch (sym.kind) {
                case CXCursor_ClassDecl:
                case CXCursor_StructDecl:
                case CXCursor_ClassTemplate:
                case CXCursor_TypedefDecl:
                    if (!sym.isDefinition())
                        break;
                case CXCursor_FunctionDecl:
                case CXCursor_FunctionTemplate: {
                    List<String> alternatives;
                    if (path.startsWith(directory))
                        alternatives << String::format<256>("#include \"%s\"", path.mid(directory.size()).constData());
                    for (const Source::Include &inc : mSource.includePaths) {
                        const Path p = inc.path.ensureTrailingSlash();
                        if (path.startsWith(p)) {
                            alternatives << String::format<256>("#include <%s>", path.mid(p.size()).constData());
                        }
                    }
                    const int tail = strlen(path.fileName()) + 1;
                    List<String>::iterator it = alternatives.begin();
                    while (it != alternatives.end()) {
                        bool drop = false;
                        for (List<String>::const_iterator it2 = it + 1; it2 != alternatives.end(); ++it2) {
                            if (it2->size() < it->size()) {
                                if (!strncmp(it2->constData() + 9, it->constData() + 9, it2->size() - tail - 9)) {
                                    drop = true;
                                    break;
                                }
                            }
                        }
                        if (drop) {
                            it = alternatives.erase(it);
                        } else {
                            ++it;
                        }
                    }
                    std::sort(alternatives.begin(), alternatives.end(), [](const String &a, const String &b) {
                            return a.size() < b.size();
                        });
                    for (const auto &a : alternatives) {
                        found = true;
                        write(a);
                    }
                    break; }
                default:
                    break;
                }
                if (first) {
                    if (found)
                        break;
                    first = false;
                }

            }
        }
    };
    project()->findSymbols(mSymbol, [&](Project::SymbolMatchType type, const String &symbolName, const Set<Location> &locations) {
            ++matches;
            bool fuzzy = false;
            if (type == Project::StartsWith) {
                fuzzy = true;
                const int paren = symbolName.indexOf('(');
                if (paren == mSymbol.size() && !RTags::isFunctionVariable(symbolName))
                    fuzzy = false;
            }

            if (!fuzzy) {
                process(locations);
            } else if (matches == 1) {
                last = locations;
            }
        }, queryFlags());
    if (matches == 1 && !last.isEmpty()) {
        process(last);
    }

    return 0;
}
Beispiel #23
0
Set<String> ListSymbolsJob::listSymbols(const std::shared_ptr<Project> &project)
{
    Set<String> out;
    const bool hasFilter = Job::hasFilter();
    const bool stripParentheses = queryFlags() & QueryMessage::StripParentheses;
    const bool wildcard = queryFlags() & QueryMessage::WildcardSymbolNames && (string.contains('*') || string.contains('?'));
    const bool caseInsensitive = queryFlags() & QueryMessage::MatchCaseInsensitive;
    const String::CaseSensitivity cs = caseInsensitive ? String::CaseInsensitive : String::CaseSensitive;
    String lowerBound;
    // error() << "SHOBA" << wildcard << string;
    if (wildcard) {
        if (!string.endsWith('*'))
            string.append('*');
        if (!caseInsensitive) {
            for (int i=0; i<string.size(); ++i) {
                if (string.at(i) == '?' || string.at(i) == '*') {
                    lowerBound = string.left(i);
                    break;
                }
            }
        }
    } else if (!caseInsensitive) {
        lowerBound = string;
    }

    const SymbolNameMap &map = project->symbolNames();
    SymbolNameMap::const_iterator it = string.isEmpty() || caseInsensitive ? map.begin() : map.lower_bound(lowerBound);
    int count = 0;
    while (it != map.end()) {
        const String &entry = it->first;
        ++it;
        if (!string.isEmpty()) {
            if (wildcard) {
                if (!Rct::wildCmp(string.constData(), entry.constData(), cs)) {
                    continue;
                }
            } else if (!entry.startsWith(string, cs)) {
                if (!caseInsensitive) {
                    break;
                } else {
                    continue;
                }
            }
        }
        bool ok = true;
        if (hasFilter) {
            ok = false;
            const Set<Location> &locations = it->second;
            for (Set<Location>::const_iterator i = locations.begin(); i != locations.end(); ++i) {
                if (filter(i->path())) {
                    ok = true;
                    break;
                }
            }
        }
        if (ok) {
            const int paren = entry.indexOf('(');
            if (paren == -1) {
                out.insert(entry);
            } else {
                out.insert(entry.left(paren));
                if (!stripParentheses)
                    out.insert(entry);
            }
        }
        if (!(++count % 100) && isAborted())
            break;
    }
    return out;
}