Skip to content

Commit

Permalink
Rework QueryJob::filtering a little. Add a new dependency-filter which
Browse files Browse the repository at this point in the history
requires the location in question to be a dependee of a the filter file.
  • Loading branch information
Andersbakken committed Sep 3, 2015
1 parent 9f4531e commit a6d05eb
Show file tree
Hide file tree
Showing 9 changed files with 181 additions and 73 deletions.
21 changes: 15 additions & 6 deletions src/ListSymbolsJob.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,20 @@ int ListSymbolsJob::execute()
&& (string.contains('*') || string.contains('?')) && !string.endsWith('*')) {
string += '*';
}
const List<String> paths = pathFilters();
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 {
Expand Down Expand Up @@ -66,7 +79,7 @@ int ListSymbolsJob::execute()
return out.isEmpty() ? 1 : 0;
}

Set<String> ListSymbolsJob::listSymbolsWithPathFilter(const std::shared_ptr<Project> &project, const List<String> &paths) const
Set<String> ListSymbolsJob::listSymbolsWithPathFilter(const std::shared_ptr<Project> &project, const List<Path> &paths) const
{
Set<String> out;
const bool imenu = queryFlags() & QueryMessage::IMenu;
Expand All @@ -76,10 +89,6 @@ Set<String> ListSymbolsJob::listSymbolsWithPathFilter(const std::shared_ptr<Proj
const String::CaseSensitivity cs = caseInsensitive ? String::CaseInsensitive : String::CaseSensitive;
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;
Expand Down
2 changes: 1 addition & 1 deletion src/ListSymbolsJob.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ class ListSymbolsJob : public QueryJob
ListSymbolsJob(const std::shared_ptr<QueryMessage> &query, const std::shared_ptr<Project> &proj);
protected:
virtual int execute() override;
Set<String> listSymbolsWithPathFilter(const std::shared_ptr<Project> &project, const List<String> &paths) const;
Set<String> listSymbolsWithPathFilter(const std::shared_ptr<Project> &project, const List<Path> &paths) const;
Set<String> listSymbols(const std::shared_ptr<Project> &project) const;
static bool isImenuSymbol(const Symbol &symbol)
{
Expand Down
17 changes: 16 additions & 1 deletion src/Project.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -918,6 +918,22 @@ Set<uint32_t> Project::dependencies(uint32_t fileId, DependencyMode mode) const
return ret;
}

bool Project::dependsOn(uint32_t source, uint32_t header) const
{
std::function<bool(DependencyNode *node)> dep = [&](DependencyNode *node) {
assert(node);
if (node->dependents.contains(source))
return true;
for (const std::pair<uint32_t, DependencyNode*> &n : node->dependents) {
if (dep(n.second))
return true;
}
return false;
};
DependencyNode *node = mDependencies.value(header);
return node && dep(node);
}

void Project::removeDependencies(uint32_t fileId)
{
if (DependencyNode *node = mDependencies.take(fileId)) {
Expand Down Expand Up @@ -1952,4 +1968,3 @@ void Project::prepare(uint32_t fileId)
endScope();
}
}

1 change: 1 addition & 0 deletions src/Project.h
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,7 @@ class Project : public std::enable_shared_from_this<Project>
};

Set<uint32_t> dependencies(uint32_t fileId, DependencyMode mode) const;
bool dependsOn(uint32_t source, uint32_t header) const;
String dumpDependencies(uint32_t fileId, const List<String> &args = List<String>()) const;
const Hash<uint32_t, DependencyNode*> &dependencies() const { return mDependencies; }
const Declarations &declarations() const { return mDeclarations; }
Expand Down
107 changes: 55 additions & 52 deletions src/QueryJob.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,23 +24,30 @@ along with RTags. If not, see <http://www.gnu.org/licenses/>. */
QueryJob::QueryJob(const std::shared_ptr<QueryMessage> &query,
const std::shared_ptr<Project> &proj,
Flags<JobFlag> jobFlags)
: mAborted(false), mLinesWritten(0), mQueryMessage(query), mJobFlags(jobFlags), mProject(proj)
: mAborted(false), mLinesWritten(0), mQueryMessage(query), mJobFlags(jobFlags), mProject(proj), mFileFilter(0)
{
if (mProject)
mProject->beginScope();
assert(query);
if (query->flags() & QueryMessage::SilentQuery)
setJobFlag(QuietJob);
const List<String> &pathFilters = query->pathFilters();
const List<QueryMessage::PathFilter> &pathFilters = query->pathFilters();
if (!pathFilters.isEmpty()) {
if (query->flags() & QueryMessage::MatchRegex) {
const int size = pathFilters.size();
mPathFiltersRegex.reserve(size);
for (int i=0; i<size; ++i) {
mPathFiltersRegex.append(std::regex(pathFilters.at(i).ref()));
if (pathFilters.size() == 1 && pathFilters.first().mode == QueryMessage::PathFilter::Self) {
mFileFilter = Location::fileId(pathFilters.first().pattern);
}
if (!mFileFilter) {
for (const QueryMessage::PathFilter &filter : pathFilters) {
if (filter.mode == QueryMessage::PathFilter::Dependency) {
uint32_t f = Location::fileId(filter.pattern);
if (f && mProject)
mFilters.append(std::shared_ptr<Filter>(new DependencyFilter(f, mProject)));
} else if (query->flags() & QueryMessage::MatchRegex) {
mFilters.append(std::shared_ptr<Filter>(new RegexFilter(filter.pattern)));
} else {
mFilters.append(std::shared_ptr<Filter>(new PathFilter(filter.pattern)));
}
}
} else {
mPathFilters = pathFilters;
}
}
mKindFilters = query->kindFilters();
Expand All @@ -52,14 +59,6 @@ QueryJob::~QueryJob()
mProject->endScope();
}

uint32_t QueryJob::fileFilter() const
{
if (mPathFilters.size() == 1) {
return Location::fileId(mPathFilters.first());
}
return 0;
}

bool QueryJob::write(const String &out, Flags<WriteFlag> flags)
{
if ((mJobFlags & WriteUnfiltered) || (flags & Unfiltered) || filter(out)) {
Expand Down Expand Up @@ -117,15 +116,10 @@ bool QueryJob::write(const Location &location, Flags<WriteFlag> flags)
{
if (location.isNull())
return false;
if (filterLocation(location))
return false;
if (!(flags & WriteUnfiltered)) {
const uint32_t filter = fileFilter();
if (filter) {
if (filter != location.fileId())
return false;
flags |= Unfiltered;
}
if (!(flags & Unfiltered)) {
if (!filterLocation(location))
return false;
flags |= Unfiltered;
}
String out = location.key(keyFlags());
const bool containingFunction = queryFlags() & QueryMessage::ContainingFunction;
Expand All @@ -137,7 +131,7 @@ bool QueryJob::write(const Location &location, Flags<WriteFlag> flags)
if (symbol.isNull()) {
error() << "Somehow can't find" << location << "in symbols";
} else {
if (!mKindFilters.isEmpty() && filterKind(symbol.kind))
if (!filterKind(symbol.kind))
return false;
if (displayName)
out += '\t' + symbol.displayName();
Expand Down Expand Up @@ -175,50 +169,49 @@ bool QueryJob::write(const Symbol &symbol,
if (symbol.isNull())
return false;

if (filterLocation(symbol.location))
if (!filterLocation(symbol.location))
return false;

if (!mKindFilters.isEmpty() && filterKind(symbol.kind))
if (!filterKind(symbol.kind))
return false;

return write(symbol.toString(toStringFlags, keyFlags(), project()), writeFlags);
return write(symbol.toString(toStringFlags, keyFlags(), project()), writeFlags|Unfiltered);
}

bool QueryJob::filter(const String &value) const
{
if (mPathFilters.isEmpty() && mPathFiltersRegex.isEmpty() && !(queryFlags() & QueryMessage::FilterSystemIncludes))
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 (mPathFilters.isEmpty() && mPathFiltersRegex.isEmpty())
if (mFilters.isEmpty())
return true;

assert(mPathFilters.isEmpty() != mPathFiltersRegex.isEmpty());
String copy;
const String &ref = (val != value.constData() ? copy : value);
if (val != value.constData())
copy = val;
error() << mPathFilters << ref;
if (!mPathFilters.isEmpty())
return RTags::startsWith(mPathFilters, ref);

assert(!mPathFiltersRegex.isEmpty());

const int count = mPathFiltersRegex.size();
for (int i=0; i<count; ++i) {
if (std::regex_search(ref.constData(), mPathFiltersRegex.at(i)))
for (const std::shared_ptr<Filter> &filter : mFilters) {
if (filter->match(fileId, path))
return true;
}
return false;
}


int QueryJob::run(const std::shared_ptr<Connection> &connection)
{
assert(connection);
Expand All @@ -230,6 +223,8 @@ int QueryJob::run(const std::shared_ptr<Connection> &connection)

bool QueryJob::filterLocation(const Location &loc) const
{
if (mFileFilter && loc.fileId() != mFileFilter)
return false;
const int minLine = mQueryMessage ? mQueryMessage->minLine() : -1;
if (minLine != -1) {
assert(mQueryMessage);
Expand All @@ -238,19 +233,27 @@ bool QueryJob::filterLocation(const Location &loc) const
assert(maxLine != -1);
const int line = loc.line();
if (line < minLine || line > maxLine) {
return true;
return false;
}
}
return false;
if (!mFilters.isEmpty()) {
for (const std::shared_ptr<Filter> &filter : mFilters) {
if (filter->match(loc.fileId(), loc.path()))
return true;
}
return false;
}
return true;
}

bool QueryJob::filterKind(CXCursorKind kind) const
{
assert(!mKindFilters.isEmpty());
if (mKindFilters.isEmpty())
return true;
const String kindSpelling = Symbol::kindSpelling(kind);
for (auto k : mKindFilters) {
if (kindSpelling.contains(k, String::CaseInsensitive))
return false;
return true;
}
return true;
return false;
}
49 changes: 44 additions & 5 deletions src/QueryJob.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ along with RTags. If not, see <http://www.gnu.org/licenses/>. */
#include "QueryMessage.h"
#include <mutex>
#include <rct/Flags.h>
#include "Project.h"

class Location;
class QueryMessage;
Expand All @@ -47,9 +48,14 @@ class QueryJob
Flags<JobFlag> jobFlags = Flags<JobFlag>());
virtual ~QueryJob();

bool hasFilter() const { return !mPathFilters.isEmpty() || !mPathFiltersRegex.isEmpty(); }
List<String> pathFilters() const { return mPathFilters; }
uint32_t fileFilter() const;
bool hasFilter() const { return mFileFilter || !mFilters.isEmpty(); }
List<QueryMessage::PathFilter> pathFilters() const
{
if (mQueryMessage)
return mQueryMessage->pathFilters();
return List<QueryMessage::PathFilter>();
}
uint32_t fileFilter() const { return mFileFilter; }
enum WriteFlag {
NoWriteFlags = 0x0,
IgnoreMax = 0x1,
Expand Down Expand Up @@ -80,6 +86,39 @@ class QueryJob
std::mutex &mutex() const { return mMutex; }
const std::shared_ptr<Connection> &connection() const { return mConnection; }
private:
class Filter
{
public:
virtual ~Filter() {}
virtual bool match(uint32_t fileId, const Path &path) const = 0;
};
class PathFilter : public Filter
{
public:
PathFilter(const Path &p) : pattern(p) {}
virtual bool match(uint32_t, const Path &path) const { return path.startsWith(pattern); }

const Path pattern;
};
class RegexFilter : public Filter
{
public:
RegexFilter(const String &str) : regex(str.ref()) {}
virtual bool match(uint32_t, const Path &path) const { return std::regex_search(path.constData(), regex); }

const std::regex regex;
};

class DependencyFilter : public Filter
{
public:
DependencyFilter(uint32_t f, const std::shared_ptr<Project> &p) : fileId(f), project(p) {}
virtual bool match(uint32_t f, const Path &) const { return project->dependsOn(f, fileId); }

const uint32_t fileId;
const std::shared_ptr<Project> project;
};

bool filterLocation(const Location &loc) const;
bool filterKind(CXCursorKind kind) const;
mutable std::mutex mMutex;
Expand All @@ -90,8 +129,8 @@ class QueryJob
Flags<JobFlag> mJobFlags;
Signal<std::function<void(const String &)> > mOutput;
std::shared_ptr<Project> mProject;
List<String> mPathFilters;
List<std::regex> mPathFiltersRegex;
uint32_t mFileFilter;
List<std::shared_ptr<Filter> > mFilters;
Set<String> mKindFilters;
String mBuffer;
std::shared_ptr<Connection> mConnection;
Expand Down
Loading

0 comments on commit a6d05eb

Please sign in to comment.