Example #1
0
static String toJSON(const Location &loc, uint32_t fileId, int length, int srcRootLength)
{
    if (loc.fileId() == fileId) {
        return String::format<64>("{\"offset\":%d,\"length\":%d}", loc.offset(), length);
    } else {
        return String::format<64>("{\"file\":\"%s\",\"offset\":%d,\"length\":%d}",
                                     Location::path(loc.fileId()).constData() + srcRootLength, loc.offset(), length);
    }
}
Example #2
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;
}
Example #3
0
static inline SymbolMap::const_iterator findCursorInfo(const SymbolMap &map, const Location &location, const String &context, bool scan)
{
    if (context.isEmpty() || !scan) {
        SymbolMap::const_iterator it = map.lower_bound(location);
        if (it != map.end() && it->first == location) {
            return it;
        } else if (it != map.begin()) {
            --it;
            if (it->first.fileId() == location.fileId()) {
                const int off = location.offset() - it->first.offset();
                if (it->second.symbolLength > off && (context.isEmpty() || it->second.symbolName.contains(context))) {
                    return it;
                }
            }
        }
        return map.end();
    }

    SymbolMap::const_iterator f = map.lower_bound(location);
    if (f != map.begin() && (f == map.end() || f->first != location))
        --f;
    SymbolMap::const_iterator b = f;

    enum { Search = 32 };
    for (int j=0; j<Search; ++j) {
        if (f != map.end()) {
            if (location.fileId() != f->first.fileId()) {
                if (b == map.begin())
                    break;
                f = map.end();
            } else if (f->second.symbolName.contains(context)) {
                // error() << "found it forward" << j;
                return f;
            } else {
                ++f;
            }
        }

        if (b != map.begin()) {
            --b;
            if (location.fileId() != b->first.fileId()) {
                if (f == map.end())
                    break;
                b = map.begin();
            } else if (b->second.symbolName.contains(context)) {
                // error() << "found it backward" << j;
                return b;
            }
        }
    }
    return map.end();
}
Example #4
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);
}
Example #5
0
void DumpThread::handleReference(const Location &loc, const CXCursor &ref)
{
    if (clang_getCursorKind(ref) == CXCursor_Namespace)
        return;
    const Location refLoc = createLocation(ref);
    if (refLoc.isNull() || refLoc.fileId() == loc.fileId())
        return;

    Dep *dep = mDependencies[loc.fileId()];
    assert(dep);
    Dep *refDep = mDependencies[refLoc.fileId()];
    assert(refDep);
    auto &refs = dep->references[refDep->fileId];
    refs[loc] = refLoc;
}
Example #6
0
void IndexerJob::inclusionVisitor(CXFile includedFile,
                                  CXSourceLocation *includeStack,
                                  unsigned includeLen,
                                  CXClientData userData)
{
    IndexerJob *job = static_cast<IndexerJob*>(userData);
    const Location l(includedFile, 0);

    const Path path = l.path();
    job->mData->symbolNames[path].insert(l);
    const char *fn = path.fileName();
    job->mData->symbolNames[String(fn, strlen(fn))].insert(l);

    const uint32_t fileId = l.fileId();
    if (!includeLen) {
        job->mData->dependencies[fileId].insert(fileId);
    } else {
        for (unsigned i=0; i<includeLen; ++i) {
            CXFile originatingFile;
            clang_getSpellingLocation(includeStack[i], &originatingFile, 0, 0, 0);
            Location loc(originatingFile, 0);
            const uint32_t f = loc.fileId();
            if (f)
                job->mData->dependencies[fileId].insert(f);
        }
    }
}
Example #7
0
void ClangIndexer::handleInclude(const CXCursor &cursor, CXCursorKind kind, const Location &location)
{
    assert(kind == CXCursor_InclusionDirective);
    (void)kind;
    CXFile includedFile = clang_getIncludedFile(cursor);
    if (includedFile) {
        const Location refLoc = createLocation(includedFile, 1, 1);
        if (!refLoc.isNull()) {
            {
                String include = "#include ";
                const Path path = refLoc.path();
                assert(mSource.fileId);
                mData->dependencies[refLoc.fileId()].insert(mSource.fileId);
                mData->symbolNames[(include + path)].insert(location);
                mData->symbolNames[(include + path.fileName())].insert(location);
            }
            std::shared_ptr<CursorInfo> &info = mData->symbols[location];
            if (!info)
                info = std::make_shared<CursorInfo>();
            info->targets.insert(refLoc);
            info->kind = cursor.kind;
            info->definition = false;
            info->symbolName = "#include " + RTags::eatString(clang_getCursorDisplayName(cursor));
            info->symbolLength = info->symbolName.size() + 2;
            // this fails for things like:
            // # include    <foobar.h>
        }
    }
}
Example #8
0
void ClangIndexer::superclassTemplateMemberFunctionUgleHack(const CXCursor &cursor, CXCursorKind kind,
                                                            const Location &location, const CXCursor &ref,
                                                            const CXCursor &parent)
{
    // This is for references to superclass template functions. Awful awful
    // shit. See https://github.com/Andersbakken/rtags/issues/62 and commit
    // for details. I really should report this as a bug.
    if (kind == CXCursor_MemberRefExpr && clang_getCursorKind(parent) == CXCursor_CallExpr) {
        const CXCursor templateRef = RTags::findChild(cursor, CXCursor_TemplateRef);
        if (templateRef == CXCursor_TemplateRef) {
            const CXCursor classTemplate = clang_getCursorReferenced(templateRef);
            if (classTemplate == CXCursor_ClassTemplate) {
                FILE *f = fopen(location.path().constData(), "r");
                if (f) {
                    const CXSourceRange range = clang_getCursorExtent(cursor);
                    const CXSourceLocation end = clang_getRangeEnd(range);
                    unsigned offset;
                    clang_getSpellingLocation(end, 0, 0, 0, &offset);

                    String name;
                    while (offset > 0) {
                        fseek(f, --offset, SEEK_SET);
                        char ch = static_cast<char>(fgetc(f));
                        if (isalnum(ch) || ch == '_' || ch == '~') {
                            name.prepend(ch);
                        } else {
                            break;
                        }
                    }
                    fclose(f);
                    if (!name.isEmpty()) {
                        RTags::Filter out;
                        out.kinds.insert(CXCursor_MemberRefExpr);
                        const int argCount = RTags::children(parent, RTags::Filter(), out).size();
                        RTags::Filter in(RTags::Filter::And);
                        in.names.insert(name);
                        in.argumentCount = argCount;
                        const List<CXCursor> alternatives = RTags::children(classTemplate, in);
                        switch (alternatives.size()) {
                        case 1:
                            // ### not sure this is correct with line/col
                            handleReference(cursor, kind, Location(location.fileId(), location.line(), location.column() + 1), alternatives.first(), parent);
                            break;
                        case 0:
                            break;
                        default:
                            warning() << "Can't decide which of these cursors are right for me"
                                      << cursor << alternatives
                                      << "Need to parse types";
                            break;
                        }
                    }
                }
            }
        }
    }
}
Example #9
0
void DumpThread::handleInclude(const Location &loc, const CXCursor &cursor)
{
    CXFile includedFile = clang_getIncludedFile(cursor);
    if (includedFile) {
        CXStringScope fn = clang_getFileName(includedFile);
        const char *cstr = clang_getCString(fn);
        if (!cstr) {
            clang_disposeString(fn);
            return;
        }
        const Path p = Path::resolved(cstr);
        clang_disposeString(fn);
        const uint32_t fileId = Location::insertFile(p);
        Dep *&source = mDependencies[loc.fileId()];
        if (!source)
            source = new Dep(loc.fileId());
        Dep *&include = mDependencies[fileId];
        if (!include)
            include = new Dep(fileId);
        source->include(include);
    }
}
Example #10
0
void ClangIndexer::inclusionVisitor(CXFile includedFile,
                                    CXSourceLocation *includeStack,
                                    unsigned includeLen,
                                    CXClientData userData)
{
    ClangIndexer *indexer = static_cast<ClangIndexer*>(userData);
    const Location l = indexer->createLocation(includedFile, 1, 1);

    const uint32_t fileId = l.fileId();
    if (!includeLen) {
        indexer->mData->dependencies[fileId].insert(fileId);
    } else {
        for (unsigned i=0; i<includeLen; ++i) {
            CXFile originatingFile;
            clang_getSpellingLocation(includeStack[i], &originatingFile, 0, 0, 0);
            const Location loc = indexer->createLocation(originatingFile, 1, 1);
            const uint32_t f = loc.fileId();
            if (f)
                indexer->mData->dependencies[fileId].insert(f);
        }
    }
}
Example #11
0
CXChildVisitResult IndexerJob::verboseVisitor(CXCursor cursor, CXCursor, CXClientData userData)
{
    VerboseVisitorUserData *u = reinterpret_cast<VerboseVisitorUserData*>(userData);
    Location loc = u->job->createLocation(cursor);
    if (loc.fileId()) {
        CXCursor ref = clang_getCursorReferenced(cursor);

        VerboseVisitorUserData *u = reinterpret_cast<VerboseVisitorUserData*>(userData);
        if (u->indent >= 0)
            u->out += String(u->indent, ' ');
        u->out += RTags::cursorToString(cursor);
        if (clang_equalCursors(ref, cursor)) {
            u->out += " refs self";
        } else if (!clang_equalCursors(ref, nullCursor)) {
            u->out += " refs " + RTags::cursorToString(ref);
        }

        if (loc.fileId() && u->job->mVisitedFiles.contains(loc.fileId())) {
            if (u->job->mData->references.contains(loc)) {
                u->out += " used as reference\n";
            } else if (u->job->mData->symbols.contains(loc)) {
                u->out += " used as cursor\n";
            } else {
                u->out += " not used\n";
            }
        } else {
            u->out += " not indexed\n";
        }
    }
    if (u->indent >= 0) {
        u->indent += 2;
        clang_visitChildren(cursor, IndexerJob::verboseVisitor, userData);
        u->indent -= 2;
        return CXChildVisit_Continue;
    } else {
        return CXChildVisit_Recurse;
    }
}
Example #12
0
bool QueryJob::filterLocation(Location loc) const
{
    if (mFileFilter && loc.fileId() != mFileFilter)
        return false;
    const int minLine = mQueryMessage ? mQueryMessage->minLine() : -1;
    if (minLine != -1) {
        assert(mQueryMessage);
        assert(mQueryMessage->maxLine() != -1);
        const int maxLine = mQueryMessage->maxLine();
        assert(maxLine != -1);
        const int line = loc.line();
        if (line < minLine || line > maxLine) {
            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;
}
Example #13
0
static inline List<Path> headersForSymbol(const std::shared_ptr<Project> &project, const Location &loc)
{
    List<Path> ret;
    const Path &path = loc.path();
    if (path.isHeader()) {
        ret.append(path);
        if (const DependencyNode *node = project->dependencies().value(loc.fileId())) {
            for (const auto &dependent : node->dependents) {
                const Path p = Location::path(dependent.first);
                if (p.isHeader() && dependent.second->includes.size() == 1) {
                    ret.append(p);
                    // allow headers that only include one header if we don't
                    // find anything for the real header
                }
            }
        }
    }
    return ret;
}
Example #14
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;
}
Example #15
0
CXChildVisitResult IndexerJob::dumpVisitor(CXCursor cursor, CXCursor, CXClientData userData)
{
    DumpUserData *dump = reinterpret_cast<DumpUserData*>(userData);
    assert(dump);
    assert(dump->job);
    Location loc = dump->job->createLocation(cursor);
    if (loc.fileId()) {
        CXCursor ref = clang_getCursorReferenced(cursor);
        String out;
        out.reserve(256);
        int col = -1;
        if (dump->showContext) {
            out.append(loc.context(&col));
            if (col != -1) {
                out.append(String::format<32>(" // %d, %d: ", col, dump->indentLevel));
            } else {
                out.append(String::format<32>(" // %d: ", dump->indentLevel));
            }
        } else {
            out.append(String(dump->indentLevel * 2, ' '));
        }
        out.append(RTags::cursorToString(cursor, RTags::AllCursorToStringFlags));
        out.append(" " + typeName(cursor) + " ");
        if (clang_equalCursors(ref, cursor)) {
            out.append("refs self");
        } else if (!clang_equalCursors(ref, nullCursor)) {
            out.append("refs ");
            out.append(RTags::cursorToString(ref, RTags::AllCursorToStringFlags));
        }
        dump->job->write(out);
    }
    ++dump->indentLevel;
    clang_visitChildren(cursor, IndexerJob::dumpVisitor, userData);
    --dump->indentLevel;
    return CXChildVisit_Continue;
}
SymbolMap::const_iterator findCursorInfo(const SymbolMap &map, const Location &location)
{
    if (map.isEmpty())
        return map.end();

    SymbolMap::const_iterator it = map.find(location);
    if (it != map.end())
        return it;
    it = map.lower_bound(location);
    if (it == map.end()) {
        --it;
    } else {
        const int cmp = it->first.compare(location);
        if (!cmp)
            return it;
        --it;
    }
    if (location.fileId() != it->first.fileId())
        return map.end();
    const int off = location.offset() - it->first.offset();
    if (it->second.symbolLength > off)
        return it;
    return map.end();
}
Example #17
0
bool ClangIndexer::diagnose()
{
    if (!mClangUnit) {
        return false;
    }

    List<String> compilationErrors;
    const unsigned diagnosticCount = clang_getNumDiagnostics(mClangUnit);

    Map<Location, XmlEntry> xmlEntries;

    for (unsigned i=0; i<diagnosticCount; ++i) {
        CXDiagnostic diagnostic = clang_getDiagnostic(mClangUnit, i);
        const CXSourceLocation diagLoc = clang_getDiagnosticLocation(diagnostic);
        const Location loc = createLocation(diagLoc, 0);
        const uint32_t fileId = loc.fileId();
        if (mData->visited.value(fileId)) {
            const String msg = RTags::eatString(clang_getDiagnosticSpelling(diagnostic));
            const CXDiagnosticSeverity sev = clang_getDiagnosticSeverity(diagnostic);
            XmlEntry::Type type = XmlEntry::None;
            switch (sev) {
            case CXDiagnostic_Warning:
                type = XmlEntry::Warning;
                break;
            case CXDiagnostic_Error:
            case CXDiagnostic_Fatal:
                type = XmlEntry::Error;
                break;
            default:
                break;
            }
            if (type != XmlEntry::None) {
                const unsigned rangeCount = clang_getDiagnosticNumRanges(diagnostic);
                bool ok = false;
                for (unsigned rangePos = 0; rangePos < rangeCount; ++rangePos) {
                    const CXSourceRange range = clang_getDiagnosticRange(diagnostic, rangePos);
                    const CXSourceLocation start = clang_getRangeStart(range);
                    const CXSourceLocation end = clang_getRangeEnd(range);

                    unsigned startOffset, endOffset;
                    clang_getSpellingLocation(start, 0, 0, 0, &startOffset);
                    clang_getSpellingLocation(end, 0, 0, 0, &endOffset);
                    if (!rangePos && !startOffset && !endOffset) {
                        // huh, range invalid? fall back to diag location
                        break;
                    } else {
                        unsigned int line, column;
                        clang_getPresumedLocation(start, 0, &line, &column);
                        const Location key(loc.fileId(), line, column);
                        xmlEntries[key] = XmlEntry(type, msg, endOffset - startOffset);
                        ok = true;
                        break;
                    }
                }
                if (!ok) {
                    unsigned line, column;
                    clang_getPresumedLocation(diagLoc, 0, &line, &column);
                    const Location key(loc.fileId(), line, column);
                    xmlEntries[key] = XmlEntry(type, msg);
                    // no length
                }
            }
            // logDirect(RTags::CompilationError, msg.constData());

            const unsigned fixItCount = clang_getDiagnosticNumFixIts(diagnostic);
            for (unsigned f=0; f<fixItCount; ++f) {
                CXSourceRange range;
                const CXStringScope stringScope = clang_getDiagnosticFixIt(diagnostic, f, &range);
                CXSourceLocation start = clang_getRangeStart(range);

                unsigned line, column;
                CXString file;
                clang_getPresumedLocation(start, &file, &line, &column);
                CXStringScope fileScope(file);

                const Location loc = createLocation(clang_getCString(file), line, column);
                if (mData->visited.value(loc.fileId())) {
                    unsigned int startOffset, endOffset;
                    CXSourceLocation end = clang_getRangeEnd(range);
                    clang_getSpellingLocation(start, 0, 0, 0, &startOffset);
                    clang_getSpellingLocation(end, 0, 0, 0, &endOffset);
                    const char *string = clang_getCString(stringScope);
                    error("Fixit for %s:%d:%d: Replace %d characters with [%s]", loc.path().constData(),
                          line, column, endOffset - startOffset, string);
                    XmlEntry &entry = xmlEntries[Location(loc.fileId(), line, column)];
                    entry.type = XmlEntry::Fixit;
                    if (entry.message.isEmpty()) {
                        entry.message = String::format<64>("did you mean '%s'?", string);
                    }
                    entry.length = endOffset - startOffset;
                    mData->fixIts[loc.fileId()].insert(FixIt(line, column, endOffset - startOffset, string));
                }
            }
        }

        clang_disposeDiagnostic(diagnostic);
    }

    mData->xmlDiagnostics = "<?xml version=\"1.0\" encoding=\"utf-8\"?><checkstyle>";
    if (!xmlEntries.isEmpty()) {
        Map<Location, XmlEntry>::const_iterator entry = xmlEntries.begin();
        const Map<Location, XmlEntry>::const_iterator end = xmlEntries.end();

        const char *severities[] = { "none", "warning", "error", "fixit" };

        uint32_t lastFileId = 0;
        while (entry != end) {
            const Location &loc = entry->first;
            const XmlEntry &xmlEntry = entry->second;
            if (loc.fileId() != lastFileId) {
                if (lastFileId)
                    mData->xmlDiagnostics += "</file>";
                lastFileId = loc.fileId();
                mData->xmlDiagnostics += String::format<128>("<file name=\"%s\">", loc.path().constData());
            }
            mData->xmlDiagnostics += String::format("<error line=\"%d\" column=\"%d\" %sseverity=\"%s\" message=\"%s\"/>",
                                                    loc.line(), loc.column(),
                                                    (xmlEntry.length <= 0 ? ""
                                                     : String::format<32>("length=\"%d\" ", xmlEntry.length).constData()),
                                                    severities[xmlEntry.type], xmlEscape(xmlEntry.message).constData());
            ++entry;
        }
        if (lastFileId)
            mData->xmlDiagnostics += "</file>";
    }

    for (Hash<uint32_t, bool>::const_iterator it = mData->visited.begin(); it != mData->visited.end(); ++it) {
        if (it->second) {
            const Map<Location, XmlEntry>::const_iterator x = xmlEntries.lower_bound(Location(it->first, 0, 0));
            if (x == xmlEntries.end() || x->first.fileId() != it->first) {
                const String fn = Location::path(it->first);
                mData->xmlDiagnostics += String::format("<file name=\"%s\"/>", fn.constData());
            }
        }
    }

    mData->xmlDiagnostics += "</checkstyle>";
    return true;
}
Example #18
0
CXChildVisitResult DumpThread::visit(const CXCursor &cursor)
{
    if (isAborted())
        return CXChildVisit_Break;
    const Location location = createLocation(cursor);
    if (!location.isNull()) {
        if (mQueryFlags & QueryMessage::DumpCheckIncludes) {
            checkIncludes(location, cursor);
            return CXChildVisit_Recurse;
        } else {
            Flags<Location::ToStringFlag> locationFlags;
            if (mQueryFlags & QueryMessage::NoColor)
                locationFlags |= Location::NoColor;

            CXSourceRange range = clang_getCursorExtent(cursor);
            CXSourceLocation rangeEnd = clang_getRangeEnd(range);
            unsigned int endLine, endColumn;
            clang_getPresumedLocation(rangeEnd, 0, &endLine, &endColumn);
            if (!(mQueryFlags & QueryMessage::DumpIncludeHeaders) && location.fileId() != mSource.fileId) {
                return CXChildVisit_Continue;
            }

            String message;
            message.reserve(256);

            if (!(mQueryFlags & QueryMessage::NoContext)) {
                message = location.context(locationFlags);
            }

            if (endLine == location.line()) {
                message += String::format<32>(" // %d-%d, %d: ", location.column(), endColumn, mIndentLevel);
            } else {
                message += String::format<32>(" // %d-%d:%d, %d: ", location.column(), endLine, endColumn, mIndentLevel);
            }
            message += RTags::cursorToString(cursor, RTags::AllCursorToStringFlags);
            message.append(" " + RTags::typeName(cursor));;
            if (clang_getCursorKind(cursor) == CXCursor_VarDecl) {
                const std::shared_ptr<RTags::Auto> autoResolved = RTags::resolveAuto(cursor);
                if (autoResolved && !clang_equalCursors(autoResolved->cursor, nullCursor)) {
                    message += "auto resolves to " + RTags::cursorToString(autoResolved->cursor, RTags::AllCursorToStringFlags);
                }
            }
            CXCursor ref = clang_getCursorReferenced(cursor);
            if (clang_equalCursors(ref, cursor)) {
                message.append("refs self");
            } else if (!clang_equalCursors(ref, nullCursor)) {
                message.append("refs ");
                message.append(RTags::cursorToString(ref, RTags::AllCursorToStringFlags));
            }

            CXCursor canonical = clang_getCanonicalCursor(cursor);
            if (!clang_equalCursors(canonical, cursor) && !clang_equalCursors(canonical, nullCursor)) {
                message.append("canonical ");
                message.append(RTags::cursorToString(canonical, RTags::AllCursorToStringFlags));
            }

            CXCursor specialized = clang_getSpecializedCursorTemplate(cursor);
            if (!clang_equalCursors(specialized, cursor) && !clang_equalCursors(specialized, nullCursor)) {
                message.append("specialized ");
                message.append(RTags::cursorToString(specialized, RTags::AllCursorToStringFlags));
            }

            writeToConnetion(message);
        }
    }
    ++mIndentLevel;
    clang_visitChildren(cursor, DumpThread::visitor, this);
    if (isAborted())
        return CXChildVisit_Break;
    --mIndentLevel;
    return CXChildVisit_Continue;
}
Example #19
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;
}