Example #1
0
void logDirect(int level, const String &out)
{
    std::lock_guard<std::mutex> lock(sOutputsMutex);
    if (sOutputs.isEmpty()) {
        printf("%s\n", out.constData());
    } else {
        for (Set<LogOutput*>::const_iterator it = sOutputs.begin(); it != sOutputs.end(); ++it) {
            LogOutput *output = *it;
            if (output->testLog(level)) {
                output->log(out.constData(), out.size());
            }
        }
    }
}
Example #2
0
static inline String xmlEscape(const String& xml)
{
    if (xml.isEmpty())
        return xml;

    std::ostringstream strm;
    const char* ch = xml.constData();
    bool done = false;
    for (;;) {
        switch (*ch) {
        case '\0':
            done = true;
            break;
        case '"':
            strm << "\\\"";
            break;
        case '<':
            strm << "&lt;";
            break;
        case '>':
            strm << "&gt;";
            break;
        case '&':
            strm << "&amp;";
            break;
        default:
            strm << *ch;
            break;
        }
        if (done)
            break;
        ++ch;
    }
    return strm.str();
}
Example #3
0
static void sigHandler(int signal)
{
    // this is not really allowed in signal handlers but will mostly work
    const String trace = Rct::backtrace();
    if (ClangIndexer::serverOpts() & Server::SuspendRPOnCrash) {
        int seconds = 2;
        printf("@CRASH@Caught signal %d\n%s@CRASH@", signal, trace.constData());
        while (true) {
            printf("@CRASH@rp crashed, waiting for debugger pid: %d@CRASH@", getpid());
            fflush(stdout);
            sleep(seconds);
            if (seconds < 32)
                seconds *= 2;
        }
    }
    fprintf(stderr, "Caught signal %d\n%s\n", signal, trace.constData());
    fflush(stderr);
    ::closelog();
    _exit(1);
}
Example #4
0
static inline String sha1(const String& input)
{
    unsigned char digest[SHA_DIGEST_LENGTH];

    SHA_CTX ctx;
    SHA1_Init(&ctx);
    SHA1_Update(&ctx, input.constData(), input.size());
    SHA1_Final(digest, &ctx);

    return String(reinterpret_cast<char*>(&digest[0]), SHA_DIGEST_LENGTH);
}
Example #5
0
static inline String base64(const String& input)
{
#ifdef OS_Darwin
    String result;
    SecTransformRef transform = SecEncodeTransformCreate(kSecBase64Encoding, 0);
    CFDataRef sourceData = CFDataCreate(kCFAllocatorDefault,
                                        reinterpret_cast<const UInt8*>(input.constData()),
                                        input.size());
    SecTransformSetAttribute(transform, kSecTransformInputAttributeName, sourceData, 0);
    CFDataRef encodedData = static_cast<CFDataRef>(SecTransformExecute(transform, 0));
    const long len = CFDataGetLength(encodedData);
    if (len > 0) {
        result.resize(len);
        CFDataGetBytes(encodedData, CFRangeMake(0, len), reinterpret_cast<UInt8*>(result.data()));
    }
    CFRelease(encodedData);
    CFRelease(transform);
    CFRelease(sourceData);
#else
    BIO *base64_filter = BIO_new(BIO_f_base64());
    BIO_set_flags(base64_filter, BIO_FLAGS_BASE64_NO_NL);

    BIO *bio = BIO_new(BIO_s_mem());
    BIO_set_flags(bio, BIO_FLAGS_BASE64_NO_NL);

    bio = BIO_push(base64_filter, bio);

    BIO_write(bio, input.constData(), input.size());

    BIO_flush(bio);

    char *new_data;

    const long bytes_written = BIO_get_mem_data(bio, &new_data);

    String result(new_data, bytes_written);
    BIO_free_all(bio);
#endif

    return result;
}
Example #6
0
void Client::onNewMessage(Message *message, Connection *)
{
    if (message->messageId() == ResponseMessage::MessageId) {
        const String response = static_cast<ResponseMessage*>(message)->data();
        if (!response.isEmpty()) {
            error("%s", response.constData());
            fflush(stdout);
        }
    } else {
        error("Unexpected message: %d", message->messageId());
    }
}
Example #7
0
String Location::key(unsigned flags) const
{
    if (isNull())
        return String();
    int extra = 0;
    const int off = offset();
    int line = 0, col = 0;
    if (flags & Location::Padded) {
        extra = 7;
    } else if (flags & Location::ShowLineNumbers && convertOffset(line, col)) {
        extra = RTags::digits(line) + RTags::digits(col) + 3;
    } else {
        flags &= ~Location::ShowLineNumbers;
        extra = RTags::digits(off) + 1;
    }
    String ctx;
    if (flags & Location::ShowContext) {
        ctx += '\t';
        ctx += context();
        extra += ctx.size();
    }

    const Path p = path();

    String ret(p.size() + extra, '0');

    if (flags & Location::Padded) {
        snprintf(ret.data(), ret.size() + extra + 1, "%s,%06d%s", p.constData(),
                 off, ctx.constData());
    } else if (flags & Location::ShowLineNumbers) {
        snprintf(ret.data(), ret.size() + extra + 1, "%s:%d:%d:%s", p.constData(),
                 line, col, ctx.constData());
    } else {
        snprintf(ret.data(), ret.size() + extra + 1, "%s,%d%s", p.constData(),
                 off, ctx.constData());
    }
    return ret;
}
Example #8
0
static inline Path checkEntry(const Entry *entries, const Path &path, const Path &home)
{
    for (int i=0; entries[i].name; ++i) {
        Path p = findAncestor(path, entries[i].name, entries[i].flags);
        if ((p.isEmpty() || p == home) && (entries[i].flags & Wildcard)) {
            const int len = strlen(entries[i].name);
            if (entries[i].name[len - 1] == '*') {
                const String name(entries[i].name, len - 1);
                p = findAncestor(path, name.constData(), entries[i].flags & ~Wildcard);
            }
        }
        if (!p.isEmpty() && p != home) {
            return p;
        }
    }
    return Path();
}
Example #9
0
CompilerVersion::SharedPtr CompilerVersion::version(plast::CompilerType type, int32_t major, const String& target)
{
    const auto v = std::find_if(sVersionsByKey.begin(), sVersionsByKey.end(),
                                [&target, major, type](const std::pair<plast::CompilerKey, WeakPtr> &val) {
                                    return (type == val.first.type
                                            && major == val.first.major
                                            && Rct::wildCmp(val.first.target.constData(), target.constData()));
                                });
    if (v == sVersionsByKey.end()) {
        return SharedPtr();
    }
    return v->second.lock();
}
Example #10
0
int StatusJob::execute()
{
    auto match = [this](const char *name) {
        return !strncasecmp(query.constData(), name, query.size());
    };
    bool matched = false;
    const char *alternatives = "fileids|watchedpaths|dependencies|cursors|symbols|targets|symbolnames|sources|jobs|info|compilers|headererrors|memory";

    if (match("fileids")) {
        matched = true;
        if (!write(delimiter) || !write("fileids") || !write(delimiter))
            return 1;
        const Hash<uint32_t, Path> paths = Location::idsToPaths();
        for (Hash<uint32_t, Path>::const_iterator it = paths.begin(); it != paths.end(); ++it) {
            if (!write<256>("  %u: %s", it->first, it->second.constData()))
                return 1;
        }
        if (isAborted())
            return 1;
    }

    if (match("headererrors")) {
        matched = true;
        if (!write(delimiter) || !write("headererrors") || !write(delimiter))
            return 1;
        for (auto err : Server::instance()->jobScheduler()->headerErrors()) {
            if (!write(Location::path(err)))
                return 1;
        }
        if (isAborted())
            return 1;
    }

    if (query.isEmpty() || match("info")) {
        matched = true;
        if (!write(delimiter) || !write("info") || !write(delimiter))
            return 1;
        String out;
        Log log(&out);
#ifdef NDEBUG
        out << "Running a release build\n";
#else
        out << "Running a debug build\n";
#endif
        const Server::Options &opt = Server::instance()->options();
        out << "socketFile" << opt.socketFile << '\n'
            << "dataDir" << opt.dataDir << '\n'
            << "options" << opt.options
            << "jobCount" << opt.jobCount << '\n'
            << "rpVisitFileTimeout" << opt.rpVisitFileTimeout << '\n'
            << "rpIndexDataMessageTimeout" << opt.rpIndexDataMessageTimeout << '\n'
            << "rpConnectTimeout" << opt.rpConnectTimeout << '\n'
            << "rpConnectTimeout" << opt.rpConnectTimeout << '\n'
            << "threadStackSize" << opt.threadStackSize << '\n'
            << "defaultArguments" << opt.defaultArguments << '\n'
            << "includePaths" << opt.includePaths << '\n'
            << "defines" << opt.defines << '\n'
            << "ignoredCompilers" << opt.ignoredCompilers;
        write(out);
    }


    std::shared_ptr<Project> proj = project();
    if (!proj) {
        if (!matched)
            write(alternatives);
        return matched ? 0 : 1;
    }

    if (query.isEmpty() || match("watchedpaths")) {
        matched = true;
        if (!write(delimiter) || !write("watchedpaths") || !write(delimiter))
            return 1;
        Hash<Path, Flags<Project::WatchMode> > watched = proj->watchedPaths();
        auto watchModeToString = [](Flags<Project::WatchMode> mode) {
            List<String> ret;
            if (mode & Project::Watch_FileManager)
                ret << "filemanager";
            if (mode & Project::Watch_SourceFile)
                ret << "source";
            if (mode & Project::Watch_Dependency)
                ret << "dependency";
            if (mode & Project::Watch_CompilationDatabase)
                ret << "compilationdatabase";
            return String::join(ret, '|');
        };
        for (const auto &it : watched) {
            if (!write<256>("  %s (%s)", it.first.constData(), watchModeToString(it.second).constData())) {
                return 1;
            }
        }
    }

    const Dependencies &deps = proj->dependencies();
    if (query.isEmpty() || match("dependencies")) {
        matched = true;
        if (!write(delimiter) || !write("dependencies") || !write(delimiter))
            return 1;

        for (auto it : deps) {
            write(proj->dumpDependencies(it.first));
        }
        if (isAborted())
            return 1;
    }

    if (query.isEmpty() || match("symbols") || match("cursors")) {
        matched = true;
        write(delimiter);
        write("symbols");
        write(delimiter);

        for (const auto &dep : deps) {
            auto symbols = proj->openSymbols(dep.first);
            if (!symbols)
                continue;
            const int count = symbols->count();
            for (int i=0; i<count; ++i) {
                const Location loc = symbols->keyAt(i);
                const Symbol c = symbols->valueAt(i);
                write(loc);
                write(c);
                write("------------------------");
                if (isAborted())
                    return 1;
            }
        }
    }

    if (query.isEmpty() || match("targets")) {
        matched = true;
        write(delimiter);
        write("targets");
        write(delimiter);
        for (const auto &dep : deps) {
            auto targets = proj->openTargets(dep.first);
            if (!targets)
                continue;
            const int count = targets->count();
            for (int i=0; i<count; ++i) {
                const String usr = targets->keyAt(i);
                write<128>("  %s", usr.constData());
                for (const auto &t : proj->findByUsr(usr, dep.first, Project::ArgDependsOn)) {
                    write<1024>("      %s\t%s", t.location.toString(locationToStringFlags()).constData(),
                                t.kindSpelling().constData());
                }
                for (const auto &location : targets->valueAt(i)) {
                    write<1024>("    %s", location.toString(locationToStringFlags()).constData());
                }
                write("------------------------");
                if (isAborted())
                    return 1;
            }
        }
    }

    if (query.isEmpty() || match("symbolnames")) {
        matched = true;
        write(delimiter);
        write("symbolnames");
        write(delimiter);
        for (const auto &dep : deps) {
            auto symNames = proj->openSymbolNames(dep.first);
            if (!symNames)
                continue;
            const int count = symNames->count();
            for (int i=0; i<count; ++i) {
                write<128>("  %s", symNames->keyAt(i).constData());
                for (const Location &loc : symNames->valueAt(i)) {
                    write<1024>("    %s", loc.toString().constData());
                }
                write("------------------------");
                if (isAborted())
                    return 1;
            }
        }
    }

    if (query.isEmpty() || match("sources")) {
        matched = true;
        const Sources &map = proj->sources();
        if (!write(delimiter) || !write("sources") || !write(delimiter))
            return 1;
        for (Sources::const_iterator it = map.begin(); it != map.end(); ++it) {
            if (!write<512>("  %s: %s", it->second.sourceFile().constData(), it->second.toString().constData()))
                return 1;
        }
    }

    if (query.isEmpty() || match("jobs")) {
        matched = true;
        if (!write(delimiter) || !write("jobs") || !write(delimiter))
            return 1;
        Server::instance()->dumpJobs(connection());
    }

    if (query.isEmpty() || match("compilers")) {
        matched = true;
        if (!write(delimiter) || !write("compilers") || !write(delimiter))
            return 1;
        Source source;
        for (const Path &compiler : CompilerManager::compilers()) {
            source.compilerId = Location::insertFile(compiler);
            source.defines.clear();
            source.includePaths.clear();
            CompilerManager::applyToSource(source, true, true);
            write(compiler);
            write("  Defines:");
            for (const auto &it : source.defines)
                write<512>("    %s", it.toString().constData());
            write("  Includepaths:");
            for (const auto &it : source.includePaths)
                write<512>("    %s", it.toString().constData());
            write("");
        }
    }

    if (query.isEmpty() || match("memory")) {
        write(proj->estimateMemory());
        matched = true;
    }


    if (!matched) {
        write<256>("rc -s %s", alternatives);
        return 1;
    } else {
        return 0;
    }
}
Example #11
0
CXChildVisitResult ClangIndexer::indexVisitor(CXCursor cursor, CXCursor parent, CXClientData data)
{
    ClangIndexer *indexer = static_cast<ClangIndexer*>(data);
    // error() << "indexVisitor" << cursor;
    // FILE *f = fopen("/tmp/clangindex.log", "a");
    // String str;
    // Log(&str) << cursor;
    // fwrite(str.constData(), 1, str.size(), f);
    // fwrite("\n", 1, 1, f);
    // fclose(f);
    const LastCursorUpdater updater(indexer->mLastCursor, cursor);

    const CXCursorKind kind = clang_getCursorKind(cursor);
    const RTags::CursorType type = RTags::cursorType(kind);
    if (type == RTags::Other)
        return CXChildVisit_Recurse;

    bool blocked = false;

    Location loc = indexer->createLocation(cursor, &blocked);
    if (blocked) {
        // error() << "blocked" << cursor;
        ++indexer->mBlocked;
        return CXChildVisit_Continue;
    } else if (loc.isNull()) {
        // error() << "Got null" << cursor;
        return CXChildVisit_Recurse;
    }
    ++indexer->mAllowed;
    if (indexer->mLogFile) {
        String out;
        Log(&out) << cursor;
        fwrite(out.constData(), 1, out.size(), indexer->mLogFile);
        fwrite("\n", 1, 1, indexer->mLogFile);
    }

    if (testLog(VerboseDebug)) {
        Log log(VerboseDebug);
        log << cursor;
        CXCursor ref = clang_getCursorReferenced(cursor);
        if (!clang_isInvalid(clang_getCursorKind(ref)) && !clang_equalCursors(ref, cursor)) {
            log << "refs" << ref;
        }
    }
    switch (type) {
    case RTags::Cursor:
        indexer->handleCursor(cursor, kind, loc);
        break;
    case RTags::Include:
        indexer->handleInclude(cursor, kind, loc);
        break;
    case RTags::Reference:
        switch (kind) {
        case CXCursor_OverloadedDeclRef: {
            const int count = clang_getNumOverloadedDecls(cursor);
            for (int i=0; i<count; ++i) {
                const CXCursor ref = clang_getOverloadedDecl(cursor, i);
                indexer->handleReference(cursor, kind, loc, ref, parent);
            }
            break; }
        case CXCursor_CXXDeleteExpr:
            indexer->handleReference(cursor, kind, loc, findDestructorForDelete(cursor), parent);
            break;
        case CXCursor_CallExpr: {
            // uglehack, see rtags/tests/nestedClassConstructorCallUgleHack/
            const CXCursor ref = clang_getCursorReferenced(cursor);
            if (clang_getCursorKind(ref) == CXCursor_Constructor
                && clang_getCursorKind(indexer->mLastCursor) == CXCursor_TypeRef
                && clang_getCursorKind(parent) != CXCursor_VarDecl) {
                loc = indexer->createLocation(indexer->mLastCursor);
                indexer->handleReference(indexer->mLastCursor, kind, loc, ref, parent);
            } else {
                indexer->handleReference(cursor, kind, loc, ref, parent);
            }
            break; }
        default:
            indexer->handleReference(cursor, kind, loc, clang_getCursorReferenced(cursor), parent);
            break;
        }
        break;
    case RTags::Other:
        assert(0);
        break;
    }
    return CXChildVisit_Recurse;
}
Example #12
0
bool ClangIndexer::exec(const String &data)
{
    Deserializer deserializer(data);
    uint16_t protocolVersion;
    deserializer >> protocolVersion;
    if (protocolVersion != RTags::DatabaseVersion) {
        error("Wrong protocol %d vs %d", protocolVersion, RTags::DatabaseVersion);
        return false;
    }
    String serverFile;
    uint32_t flags;
    uint32_t connectTimeout;
    extern bool suspendOnSigSegv;
    Hash<uint32_t, Path> blockedFiles;

    deserializer >> serverFile;
    deserializer >> mProject;
    deserializer >> mSource;
    deserializer >> mSourceFile;
    deserializer >> flags;
    deserializer >> mVisitFileTimeout;
    deserializer >> mIndexerMessageTimeout;
    deserializer >> connectTimeout;
    deserializer >> suspendOnSigSegv;
    deserializer >> mUnsavedFiles;
    uint32_t dirtySize;
    deserializer >> dirtySize;
    const uint64_t parseTime = Rct::currentTimeMs();

    while (dirtySize-- > 0) {
        Path dirty;
        deserializer >> dirty;
        if (!mUnsavedFiles.contains(dirty)) {
            mUnsavedFiles[dirty] = dirty.readAll();
        }
    }

    deserializer >> blockedFiles;
    if (mSourceFile.isEmpty()) {
        error("No sourcefile");
        return false;
    }
    if (!mSource.fileId) {
        error("Bad fileId");
        return false;
    }

    if (mProject.isEmpty()) {
        error("No project");
        return false;
    }

    Location::init(blockedFiles);
    Location::set(mSourceFile, mSource.fileId);
    if (!mConnection.connectUnix(serverFile, connectTimeout)) {
        error("Failed to connect to rdm on %s (%dms timeout)", serverFile.constData(), connectTimeout);
        return false;
    }
    // mLogFile = fopen(String::format("/tmp/%s", mSourceFile.fileName()).constData(), "w");
    mData.reset(new IndexData(flags));
    mData->parseTime = parseTime;
    mData->key = mSource.key();
    mData->pid = getpid();

    assert(mConnection.isConnected());
    mData->visited[mSource.fileId] = true;
    parse() && visit() && diagnose();
    mData->message = mSourceFile.toTilde();
    if (!mClangUnit)
        mData->message += " error";
    mData->message += String::format<16>(" in %dms. ", mTimer.elapsed());
    if (mClangUnit) {
        const char *format = "(%d syms, %d symNames, %d deps, %d of %d files, cursors: %d of %d, %d queried) (%d/%dms)";
        mData->message += String::format<128>(format, mData->symbols.size(), mData->symbolNames.size(),
                                              mData->dependencies.size(), mIndexed, mData->visited.size(), mAllowed,
                                              mAllowed + mBlocked, mFileIdsQueried,
                                              mParseDuration, mVisitDuration);
    } else if (mData->dependencies.size()) {
        mData->message += String::format<16>("(%d deps)", mData->dependencies.size());
    }
    if (mData->flags & IndexerJob::Dirty)
        mData->message += " (dirty)";
    const IndexerMessage msg(mProject, mData);
    ++mFileIdsQueried;
    // FILE *f = fopen("/tmp/clangindex.log", "a");
    // fprintf(f, "Writing indexer message %d\n", mData->symbols.size());

    // if (Path::exists(String("/tmp/") + Location::path(source.fileId).fileName())) {
    //     error() << "Detected problem... crashing" << Location::path(source.fileId).fileName();
    //     Path::rm(String("/tmp/") + Location::path(source.fileId).fileName());
    //     sleep(1);
    //     abort();
    // }
    StopWatch sw;
    if (!mConnection.send(msg)) {
        error() << "Couldn't send IndexerMessage" << mSourceFile;
        return false;
    }
    mConnection.finished().connect(std::bind(&EventLoop::quit, EventLoop::eventLoop()));
    if (EventLoop::eventLoop()->exec(mIndexerMessageTimeout) == EventLoop::Timeout) {
        error() << "Couldn't send IndexerMessage (2)" << mSourceFile;
        return false;
    }
    if (getenv("RDM_DEBUG_INDEXERMESSAGE"))
        error() << "Send took" << sw.elapsed() << "for" << mSourceFile;
    // error() << "Must have gotten a finished" << mSourceFile;
    // fprintf(f, "Wrote indexer message %d\n", mData->symbols.size());
    // fclose(f);

    return true;
}
Example #13
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 #14
0
String Symbol::toString(Flags<ToStringFlag> cursorInfoFlags,
                        Flags<Location::ToStringFlag> locationToStringFlags,
                        const std::shared_ptr<Project> &project) const
{
    auto properties = [this]()
    {
        List<String> ret;
        if (isDefinition())
            ret << "Definition";
        if (isContainer())
            ret << "Container";
        if ((flags & PureVirtualMethod) == PureVirtualMethod) {
            ret << "Pure Virtual";
        } else if (flags & VirtualMethod) {
            ret << "Virtual";
        }

        if (flags & ConstMethod) {
            ret << "Const";
        } else if (flags & StaticMethod) {
            ret << "Static";
        }

        if (flags & Variadic)
            ret << "Variadic";
        if (flags & Auto)
            ret << "Auto";
        if (flags & AutoRef)
            ret << "AutoRef";

        if (flags & MacroExpansion)
            ret << "MacroExpansion";
        if (flags & TemplateSpecialization)
            ret << "TemplateSpecialization";

        if (ret.isEmpty())
            return String();
        String joined = String::join(ret, ' ');
        joined += '\n';
        return joined;
    };

    List<String> bases;
    if (project) {
        extern String findSymbolNameByUsr(const std::shared_ptr<Project> &, const String &, const Location &location);
        for (const auto &base : baseClasses) {
            const String symbolName = findSymbolNameByUsr(project, base, location);
            if (!symbolName.isEmpty()) {
                bases << symbolName;
            }
        }
    } else {
        bases = baseClasses;
    }

    auto printTypeName = [this]() {
        String str;
        if (!typeName.isEmpty()) {
            str = typeName;
        } else if (type != CXType_Invalid) {
            str = RTags::eatString(clang_getTypeKindSpelling(type));
        } else {
            return String();
        }
        return String::format<128>("Type: %s\n", str.constData());
    };

    String ret = String::format<1024>("SymbolName: %s\n"
                                      "Kind: %s\n"
                                      "%s" // type
                                      "SymbolLength: %u\n"
                                      "%s" // range
                                      "%s" // enumValue
                                      "%s" // linkage
                                      "%s" // properties
                                      "%s" // usr
                                      "%s" // sizeof
                                      "%s" // fieldoffset
                                      "%s" // baseclasses
                                      "%s" // briefComment
                                      "%s", // xmlComment
                                      symbolName.constData(),
                                      kindSpelling().constData(),
                                      printTypeName().constData(),
                                      symbolLength,
                                      startLine != -1 ? String::format<32>("Range: %d:%d-%d:%d\n", startLine, startColumn, endLine, endColumn).constData() : "",
#if CINDEX_VERSION_MINOR > 1
                                      kind == CXCursor_EnumConstantDecl ? String::format<32>("Enum Value: %lld\n", enumValue).constData() :
#endif
                                      "",
                                      linkageSpelling(linkage),
                                      properties().constData(),
                                      usr.isEmpty() ? "" : String::format<64>("Usr: %s\n", usr.constData()).constData(),
                                      size > 0 ? String::format<16>("sizeof: %d\n", size).constData() : "",
                                      fieldOffset >= 0 ? String::format<32>("field offset (bits/bytes): %d/%d\n", fieldOffset, fieldOffset / 8).constData() : "",
                                      alignment >= 0 ? String::format<32>("alignment (bytes): %d\n", alignment).constData() : "",
                                      bases.isEmpty() ? "" : String::format<64>("BaseClasses: %s\n", String::join(bases, ", ").constData()).constData(),
                                      briefComment.isEmpty() ? "" : String::format<1024>("Brief comment: %s\n", briefComment.constData()).constData(),
                                      xmlComment.isEmpty() ? "" : String::format<16384>("Xml comment: %s\n", xmlComment.constData()).constData());
    if (!(cursorInfoFlags & IgnoreTargets) && project) {
        extern Set<Symbol> findTargets(const std::shared_ptr<Project> &, const Symbol &);
        auto targets = findTargets(project, *this);
        if (targets.size()) {
            ret.append("Targets:\n");
            auto best = RTags::bestTarget(targets);
            ret.append(String::format<128>("    %s\n", best.location.toString(locationToStringFlags).constData()));

            for (const auto &tit : targets) {
                if (tit.location != best.location)
                    ret.append(String::format<128>("    %s\n", tit.location.toString(locationToStringFlags).constData()));
            }
        }
    }

    if (!(cursorInfoFlags & IgnoreReferences) && project && !isReference()) {
        extern Set<Symbol> findCallers(const std::shared_ptr<Project> &, const Symbol &);
        auto references = findCallers(project, *this);
        if (references.size()) {
            ret.append("References:\n");
            for (const auto &r : references) {
                ret.append(String::format<128>("    %s\n", r.location.toString(locationToStringFlags).constData()));
            }
        }
    }

    return ret;
}