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)); } } }
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; }
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(); } }
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; }
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; } } }
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; }
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(); }
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); } } }
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; }
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)); } }