void BoomAnalyzer::transform(Scope& s) {
  fht_->spectrum(s.data());
  fht_->scale(s.data(), 1.0 / 50);

  s.resize(scope_.size() <= kMaxBandCount / 2 ? kMaxBandCount / 2
                                              : scope_.size());
}
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 #3
0
bool Project::save()
{
    MutexLocker lock(&mMutex);
    if (!Server::instance()->saveFileIds())
        return false;

    StopWatch timer;
    Path srcPath = mPath;
    RTags::encodePath(srcPath);
    const Server::Options &options = Server::instance()->options();
    const Path p = options.dataDir + srcPath;
    FILE *f = fopen(p.constData(), "w");
    if (!f) {
        error("Can't open file %s", p.constData());
        return false;
    }
    Serializer out(f);
    out << static_cast<int>(Server::DatabaseVersion);
    const int pos = ftell(f);
    out << static_cast<int>(0);
    {
        Scope<const SymbolMap &> scope = lockSymbolsForRead();
        out << scope.data();
    }
    {
        Scope<const SymbolNameMap &> scope = lockSymbolNamesForRead();
        out << scope.data();
    }
    {
        Scope<const UsrMap &> scope = lockUsrForRead();
        out << scope.data();
    }
    out << mDependencies << mSources << mVisitedFiles;

    const int size = ftell(f);
    fseek(f, pos, SEEK_SET);
    out << size;

    error() << "saved project" << path() << "in" << String::format<12>("%dms", timer.elapsed()).constData();
    fclose(f);
    return true;
}
Beispiel #4
0
void Project::startDirtyJobs()
{
    Set<uint32_t> dirtyFiles;
    Map<Path, List<String> > toIndex;
    {
        MutexLocker lock(&mMutex);
        std::swap(dirtyFiles, mModifiedFiles);
        for (Set<uint32_t>::const_iterator it = dirtyFiles.begin(); it != dirtyFiles.end(); ++it) {
            const Set<uint32_t> deps = mDependencies.value(*it);
            dirtyFiles += deps;
            mVisitedFiles.remove(*it);
            mVisitedFiles -= deps;
        }
        mPendingDirtyFiles.unite(dirtyFiles);
    }
    bool indexed = false;
    for (Set<uint32_t>::const_iterator it = dirtyFiles.begin(); it != dirtyFiles.end(); ++it) {
        const SourceInformationMap::const_iterator found = mSources.find(*it);
        if (found != mSources.end()) {
            index(found->second, IndexerJob::Dirty);
            indexed = true;
        }
    }
    if (!indexed && !mPendingDirtyFiles.isEmpty()) {
        {
            Scope<SymbolMap&> symbols = lockSymbolsForWrite();
            RTags::dirtySymbols(symbols.data(), mPendingDirtyFiles);
        }
        {
            Scope<SymbolNameMap&> symbolNames = lockSymbolNamesForWrite();
            RTags::dirtySymbolNames(symbolNames.data(), mPendingDirtyFiles);
        }
        {
            Scope<UsrMap&> usr = lockUsrForWrite();
            RTags::dirtyUsr(usr.data(), mPendingDirtyFiles);
        }
        mPendingDirtyFiles.clear();
    }
}
Beispiel #5
0
Set<String> ListSymbolsJob::imenu(const shared_ptr<Project> &project)
{
    Set<String> out;

    Scope<const SymbolMap&> symbols = project->lockSymbolsForRead();
    const SymbolMap &map = symbols.data();
    const List<String> paths = pathFilters();
    if (paths.isEmpty()) {
        error() << "--imenu must take path filters";
        return out;
    }

    for (int i=0; i<paths.size(); ++i) {
        const Path file = paths.at(i);
        if (!file.isFile()) {
            error() << "Invalid path filter for --imenu" << file;
            continue;
        }
        const uint32_t fileId = Location::fileId(file);
        if (!fileId)
            continue;
        for (SymbolMap::const_iterator it = map.lower_bound(Location(fileId, 0));
             it != map.end() && it->first.fileId() == fileId; ++it) {
            const CursorInfo &cursorInfo = it->second;
            if (RTags::isReference(cursorInfo.kind))
                continue;
            switch (cursorInfo.kind) {
            case CXCursor_VarDecl:
            case CXCursor_ParmDecl:
            case CXCursor_InclusionDirective:
            case CXCursor_EnumConstantDecl:
                break;
            case CXCursor_ClassDecl:
            case CXCursor_StructDecl:
            case CXCursor_ClassTemplate:
                if (!cursorInfo.isDefinition())
                    break;
                // fall through
            default: {
                const String &symbolName = it->second.symbolName;
                if (!string.isEmpty() && !symbolName.contains(string))
                    continue;
                out.insert(symbolName);
                break; }
            }
        }
    }
    return out;
}
Beispiel #6
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 #7
0
bool Project::match(const Match &p)
{
    Path paths[] = { p.pattern(), p.pattern() };
    paths[1].resolve();
    const int count = paths[1].compare(paths[0]) ? 2 : 1;
    Scope<const FilesMap&> files = lockFilesForRead();
    for (int i=0; i<count; ++i) {
        const Path &path = paths[i];
        if (files.data().contains(path) || p.match(mPath))
            return true;
        const uint32_t id = Location::fileId(path);
        if (isIndexed(id))
            return true;

    }
    return false;
}
Beispiel #8
0
int Project::syncDB()
{
    if (mPendingDirtyFiles.isEmpty() && mPendingData.isEmpty())
        return -1;
    StopWatch watch;
    Scope<SymbolMap&> symbols = lockSymbolsForWrite();
    Scope<SymbolNameMap&> symbolNames = lockSymbolNamesForWrite();
    Scope<UsrMap&> usr = lockUsrForWrite();
    if (!mPendingDirtyFiles.isEmpty()) {
        RTags::dirtySymbols(symbols.data(), mPendingDirtyFiles);
        RTags::dirtySymbolNames(symbolNames.data(), mPendingDirtyFiles);
        RTags::dirtyUsr(usr.data(), mPendingDirtyFiles);
        mPendingDirtyFiles.clear();
    }

    Set<uint32_t> newFiles;
    for (Map<uint32_t, shared_ptr<IndexData> >::iterator it = mPendingData.begin(); it != mPendingData.end(); ++it) {
        const shared_ptr<IndexData> &data = it->second;
        addDependencies(data->dependencies, newFiles);
        addFixIts(data->dependencies, data->fixIts);
        writeCursors(data->symbols, symbols.data());
        writeUsr(data->usrMap, usr.data(), symbols.data());
        writeReferences(data->references, symbols.data());
        writeSymbolNames(data->symbolNames, symbolNames.data());
    }
    for (Set<uint32_t>::const_iterator it = newFiles.begin(); it != newFiles.end(); ++it) {
        const Path path = Location::path(*it);
        const Path dir = path.parentDir();
        if (dir.isEmpty()) {
            error() << "Got empty parent dir for" << path << *it;
        } else if (mWatchedPaths.insert(dir)) {
            mWatcher.watch(dir);
        }
    }
    mPendingData.clear();
    if (Server::instance()->options().options & Server::Validate) {
        shared_ptr<ValidateDBJob> validate(new ValidateDBJob(static_pointer_cast<Project>(shared_from_this()), mPreviousErrors));
        Server::instance()->startQueryJob(validate);
    }
    return watch.elapsed();
}
Beispiel #9
0
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);
        }
    }
}
Beispiel #10
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 #11
0
bool Project::restore()
{
    StopWatch timer;
    Path path = mPath;
    RTags::encodePath(path);
    const Path p = Server::instance()->options().dataDir + path;
    bool restoreError = false;
    FILE *f = fopen(p.constData(), "r");
    if (!f)
        return false;

    Deserializer in(f);
    int version;
    in >> version;
    if (version != Server::DatabaseVersion) {
        error("Wrong database version. Expected %d, got %d for %s. Removing.", Server::DatabaseVersion, version, p.constData());
        restoreError = true;
        goto end;
    }
    {
        int fs;
        in >> fs;
        if (fs != Rct::fileSize(f)) {
            error("%s seems to be corrupted, refusing to restore %s",
                  p.constData(), mPath.constData());
            restoreError = true;
            goto end;
        }
    }
    {
        {
            Scope<SymbolMap &> scope = lockSymbolsForWrite();
            in >> scope.data();
        }
        {
            Scope<SymbolNameMap &> scope = lockSymbolNamesForWrite();
            in >> scope.data();
        }
        {
            Scope<UsrMap &> scope = lockUsrForWrite();
            in >> scope.data();
        }


        in >> mDependencies >> mSources >> mVisitedFiles;

        DependencyMap reversedDependencies;
        // these dependencies are in the form of:
        // Path.cpp: Path.h, String.h ...
        // mDependencies are like this:
        // Path.h: Path.cpp, Server.cpp ...

        for (DependencyMap::const_iterator it = mDependencies.begin(); it != mDependencies.end(); ++it) {
            const Path dir = Location::path(it->first).parentDir();
            if (dir.isEmpty()) {
                error() << "File busted" << it->first << Location::path(it->first);
                continue;
            }
            if (mWatchedPaths.insert(dir))
                mWatcher.watch(dir);
            for (Set<uint32_t>::const_iterator s = it->second.begin(); s != it->second.end(); ++s) {
                reversedDependencies[*s].insert(it->first);
            }
        }

        SourceInformationMap::iterator it = mSources.begin();
        while (it != mSources.end()) {
            if (!it->second.sourceFile.isFile()) {
                error() << it->second.sourceFile << "seems to have disappeared";
                mSources.erase(it++);
                mModifiedFiles.insert(it->first);
            } else {
                const time_t parsed = it->second.parsed;
                // error() << "parsed" << String::formatTime(parsed, String::DateTime) << parsed;
                assert(mDependencies.value(it->first).contains(it->first));
                assert(mDependencies.contains(it->first));
                const Set<uint32_t> &deps = reversedDependencies[it->first];
                for (Set<uint32_t>::const_iterator d = deps.begin(); d != deps.end(); ++d) {
                    if (!mModifiedFiles.contains(*d) && Location::path(*d).lastModified() > parsed)
                        mModifiedFiles.insert(*d);
                }
                ++it;
            }
        }
        if (!mModifiedFiles.isEmpty())
            startDirtyJobs();
    }
end:
    fclose(f);
    if (restoreError) {
        Path::rm(p);
        return false;
    } else {
        error() << "Restored project" << mPath << "in" << timer.elapsed() << "ms";
    }

    return true;
}
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));
    }
}