void IndexerJob::addOverriddenCursors(const CXCursor& cursor, const Location& location, List<CursorInfo*>& infos) { CXCursor *overridden; unsigned count; clang_getOverriddenCursors(cursor, &overridden, &count); if (!overridden) return; for (unsigned i=0; i<count; ++i) { Location loc = createLocation(overridden[i], 0); CursorInfo &o = mData->symbols[loc]; //error() << "adding overridden (1) " << location << " to " << o; o.references.insert(location); List<CursorInfo*>::const_iterator inf = infos.begin(); const List<CursorInfo*>::const_iterator infend = infos.end(); while (inf != infend) { //error() << "adding overridden (2) " << loc << " to " << *(*inf); (*inf)->references.insert(loc); ++inf; } infos.append(&o); addOverriddenCursors(overridden[i], loc, infos); infos.removeLast(); } clang_disposeOverriddenCursors(overridden); }
void IndexerJob::nestedClassConstructorCallUgleHack(const CXCursor &parent, CursorInfo &info, CXCursorKind refKind, const Location &refLoc) { if (refKind == CXCursor_Constructor && clang_getCursorKind(mLastCursor) == CXCursor_TypeRef && clang_getCursorKind(parent) == CXCursor_CXXFunctionalCastExpr) { const CXStringScope str = clang_getCursorSpelling(mLastCursor); int start = -1; const char *cstr = str.data(); int idx = 0; while (cstr[idx]) { if (start == -1 && cstr[idx] == ' ') { start = idx; } ++idx; } if (start != -1) { // error() << "Changed symbolLength from" << info.symbolLength << "to" << (idx - start - 1) << "for dude reffing" << refLoc; info.symbolLength = idx - start - 1; } RTags::Filter in; in.kinds.insert(CXCursor_TypeRef); const List<CXCursor> typeRefs = RTags::children(parent, in); for (int i=0; i<typeRefs.size(); ++i) { const Location loc = createLocation(typeRefs.at(i)); // error() << "Added" << refLoc << "to targets for" << typeRefs.at(i); mData->symbols[loc].targets.insert(refLoc); } } }
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> } } }
Node* SparrowGeneralFixture::createDatatypeNode(StringRef name, CompilationContext* ctx) { Nest_NodeRange fields{nullptr, nullptr}; auto res = Feather_mkClass(createLocation(), name, fields); if (ctx) Nest_setContext(res, ctx); return res; }
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; }
NestGeneralFixture::NestGeneralFixture() { // Initialize the Nest module getNestModule()->initFun(); // Create the backend object and register it // NOLINTNEXTLINE(cppcoreguidelines-owning-memory) backend_.reset(new BackendMock); int backendIdx = Nest_registerBackend(backend_.get()); REQUIRE(backendIdx == 0); // Initialize the compiler Nest_createBackend("unittest_app"); globalContext_ = Nest_getRootContext(); // Set up some compiler settings Nest_compilerSettings()->noColors_ = true; g_LocationGen = [this]() -> Nest::Location { return createLocation(); }; FeatherNodeFactory::instance().init(); }
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; }
bool IndexerJob::diagnose(int build, int *errorCount) { if (errorCount) *errorCount = 0; if (!mUnits.at(build).second) { abort(); return false; } List<String> compilationErrors; const unsigned diagnosticCount = clang_getNumDiagnostics(mUnits.at(build).second); const unsigned options = Server::instance()->options().options; for (unsigned i=0; i<diagnosticCount; ++i) { CXDiagnostic diagnostic = clang_getDiagnostic(mUnits.at(build).second, i); int logLevel = INT_MAX; const CXDiagnosticSeverity severity = clang_getDiagnosticSeverity(diagnostic); switch (severity) { case CXDiagnostic_Fatal: case CXDiagnostic_Error: if (errorCount) ++*errorCount; logLevel = Error; break; case CXDiagnostic_Warning: logLevel = Warning; break; case CXDiagnostic_Note: logLevel = Debug; break; case CXDiagnostic_Ignored: break; } const unsigned diagnosticOptions = (CXDiagnostic_DisplaySourceLocation| CXDiagnostic_DisplayColumn| CXDiagnostic_DisplaySourceRanges| CXDiagnostic_DisplayOption| CXDiagnostic_DisplayCategoryId| CXDiagnostic_DisplayCategoryName); const uint32_t fileId = createLocation(clang_getDiagnosticLocation(diagnostic), 0).fileId(); if (mVisitedFiles.contains(fileId)) { const String text = RTags::eatString(clang_formatDiagnostic(diagnostic, diagnosticOptions)); if (testLog(logLevel) || testLog(CompilationError)) { log(logLevel, "%s: %s => %s", mSourceInformation.sourceFile.constData(), mClangLines.at(build).constData(), text.constData()); compilationErrors.append(text); } const unsigned fixItCount = clang_getDiagnosticNumFixIts(diagnostic); RegExp rx; if (options & Server::IgnorePrintfFixits) { rx = "^%[A-Za-z0-9]\\+$"; } for (unsigned f=0; f<fixItCount; ++f) { CXSourceRange range; const String string = RTags::eatString(clang_getDiagnosticFixIt(diagnostic, f, &range)); unsigned startOffset; CXFile file; clang_getSpellingLocation(clang_getRangeStart(range), &file, 0, 0, &startOffset); unsigned endOffset; clang_getSpellingLocation(clang_getRangeEnd(range), 0, 0, 0, &endOffset); const Location loc(file, startOffset); if (options & Server::IgnorePrintfFixits && rx.indexIn(string) == 0) { error("Ignored fixit for %s: Replace %d-%d with [%s]", loc.path().constData(), startOffset, endOffset, string.constData()); } else { error("Fixit for %s: Replace %d-%d with [%s]", loc.path().constData(), startOffset, endOffset, string.constData()); compilationErrors.append(String::format<128>("Fixit for %s: Replace %d-%d with [%s]", loc.path().constData(), startOffset, endOffset, string.constData())); mData->fixIts[loc.fileId()].insert(FixIt(startOffset, endOffset, string)); } } } clang_disposeDiagnostic(diagnostic); } if (testLog(CompilationError)) sendDiagnostics(compilationErrors); return !isAborted(); }
bool IndexerJob::handleCursor(const CXCursor &cursor, CXCursorKind kind, const Location &location) { CursorInfo &info = mData->symbols[location]; if (!info.symbolLength || !RTags::isCursor(info.kind)) { CXStringScope name = clang_getCursorSpelling(cursor); const char *cstr = name.data(); info.symbolLength = cstr ? strlen(cstr) : 0; info.type = clang_getCursorType(cursor).kind; if (!info.symbolLength) { // this is for these constructs: // typedef struct { // int a; // } foobar; // // We end up not getting a spelling for the cursor switch (kind) { case CXCursor_ClassDecl: info.symbolLength = 5; info.symbolName = "class"; break; case CXCursor_UnionDecl: info.symbolLength = 5; info.symbolName = "union"; break; case CXCursor_StructDecl: info.symbolLength = 6; info.symbolName = "struct"; break; default: mData->symbols.remove(location); return false; } } else { info.symbolName = addNamePermutations(cursor, location); } CXSourceRange range = clang_getCursorExtent(cursor); unsigned start, end; clang_getSpellingLocation(clang_getRangeStart(range), 0, 0, 0, &start); clang_getSpellingLocation(clang_getRangeEnd(range), 0, 0, 0, &end); info.start = start; info.end = end; if (kind == CXCursor_EnumConstantDecl) { #if CLANG_VERSION_MINOR > 1 info.enumValue = clang_getEnumConstantDeclValue(cursor); #else info.definition = clang_isCursorDefinition(cursor); #endif } else{ info.definition = clang_isCursorDefinition(cursor); } info.kind = kind; const String usr = RTags::eatString(clang_getCursorUSR(cursor)); if (!usr.isEmpty()) mData->usrMap[usr].insert(location); switch (info.kind) { case CXCursor_Constructor: case CXCursor_Destructor: { Location parentLocation = createLocation(clang_getCursorSemanticParent(cursor)); // consider doing this for only declaration/inline definition since // declaration and definition should know of one another if (parentLocation.isValid()) { CursorInfo &parent = mData->symbols[parentLocation]; parent.references.insert(location); info.references.insert(parentLocation); } break; } case CXCursor_CXXMethod: { List<CursorInfo*> infos; infos.append(&info); addOverriddenCursors(cursor, location, infos); break; } default: break; } } return true; }
void IndexerJob::handleReference(const CXCursor &cursor, CXCursorKind kind, const Location &location, const CXCursor &ref, const CXCursor &parent) { const CXCursorKind refKind = clang_getCursorKind(ref); if (clang_isInvalid(refKind)) { superclassTemplateMemberFunctionUgleHack(cursor, kind, location, ref, parent); return; } bool isOperator = false; if (kind == CXCursor_CallExpr && (refKind == CXCursor_CXXMethod || refKind == CXCursor_ConversionFunction || refKind == CXCursor_FunctionDecl || refKind == CXCursor_FunctionTemplate)) { // these are bullshit, for this construct: // foo.bar(); // the position of the cursor is at the foo, not the bar. // They are not interesting for followLocation, renameSymbol or find // references so we toss them. // For functions it can be the position of the namespace. // E.g. Foo::bar(); cursor is on Foo // For constructors they happen to be the only thing we have that // actually refs the constructor and not the class so we have to keep // them for that. return; } switch (refKind) { case CXCursor_Constructor: if (isImplicit(ref)) return; break; case CXCursor_CXXMethod: case CXCursor_FunctionDecl: case CXCursor_FunctionTemplate: { CXStringScope scope = clang_getCursorDisplayName(ref); const char *data = scope.data(); if (data) { const int len = strlen(data); if (len > 8 && !strncmp(data, "operator", 8) && !isalnum(data[8]) && data[8] != '_') { if (isImplicit(ref)) return; // eat implicit operator calls isOperator = true; } } break; } default: break; } const Location reffedLoc = createLocation(ref, 0); if (!reffedLoc.isValid()) return; CursorInfo &refInfo = mData->symbols[reffedLoc]; if (!refInfo.symbolLength && !handleCursor(ref, refKind, reffedLoc)) return; refInfo.references.insert(location); CursorInfo &info = mData->symbols[location]; info.targets.insert(reffedLoc); // We need the new cursor to replace the symbolLength. This is important // in the following case: // struct R { R(const &r); ... } // R foo(); // ... // R r = foo(); // The first cursor on foo() will be a reference to the copy constructor and // this cursor will have a symbolLength of 1. Thus you won't be able to jump // to foo from the o. This is fixed by making sure the newer target, if // better, gets to decide on the symbolLength // The !isCursor is var decls and field decls where we set up a target even // if they're not considered references if (!RTags::isCursor(info.kind) && (!info.symbolLength || info.bestTarget(mData->symbols).kind == refKind)) { CXSourceRange range = clang_getCursorExtent(cursor); unsigned start, end; clang_getSpellingLocation(clang_getRangeStart(range), 0, 0, 0, &start); clang_getSpellingLocation(clang_getRangeEnd(range), 0, 0, 0, &end); info.start = start; info.end = end; info.definition = false; info.kind = kind; info.symbolLength = isOperator ? end - start : refInfo.symbolLength; info.symbolName = refInfo.symbolName; info.type = clang_getCursorType(cursor).kind; switch (kind) { case CXCursor_CallExpr: nestedClassConstructorCallUgleHack(parent, info, refKind, reffedLoc); // see rtags/tests/nestedClassConstructorCallUgleHack/ break; default: break; } } Set<Location> &val = mData->references[location]; val.insert(reffedLoc); }
bool ClangIndexer::handleCursor(const CXCursor &cursor, CXCursorKind kind, const Location &location) { // error() << "Got a cursor" << cursor; std::shared_ptr<CursorInfo> &info = mData->symbols[location]; if (!info) info = std::make_shared<CursorInfo>(); if (!info->symbolLength) { // if (mLogFile) { // String out; // Log(&out) << cursor << a; // fwrite(out.constData(), 1, out.size(), mLogFile); // fwrite("\n", 1, 1, mLogFile); // } CXStringScope name = clang_getCursorSpelling(cursor); const char *cstr = name.data(); info->symbolLength = cstr ? strlen(cstr) : 0; info->type = clang_getCursorType(cursor).kind; if (!info->symbolLength) { // this is for these constructs: // typedef struct { // int a; // } foobar; // // We end up not getting a spelling for the cursor switch (kind) { case CXCursor_ClassDecl: info->symbolLength = 5; info->symbolName = "class"; break; case CXCursor_UnionDecl: info->symbolLength = 5; info->symbolName = "union"; break; case CXCursor_StructDecl: info->symbolLength = 6; info->symbolName = "struct"; break; default: mData->symbols.remove(location); return false; } } else { info->symbolName = addNamePermutations(cursor, location); } CXSourceRange range = clang_getCursorExtent(cursor); CXSourceLocation rangeStart = clang_getRangeStart(range); CXSourceLocation rangeEnd = clang_getRangeEnd(range); unsigned startLine, startColumn, endLine, endColumn; clang_getPresumedLocation(rangeStart, 0, &startLine, &startColumn); clang_getPresumedLocation(rangeEnd, 0, &endLine, &endColumn); info->startLine = startLine; info->startColumn = startColumn; info->endLine = endLine; info->endColumn = endColumn; if (kind == CXCursor_EnumConstantDecl) { #if CINDEX_VERSION_MINOR > 1 info->enumValue = clang_getEnumConstantDeclValue(cursor); #else info->definition = 1; #endif } else { info->definition = clang_isCursorDefinition(cursor); } info->kind = kind; // apparently some function decls will give a different usr for // their definition and their declaration. Using the canonical // cursor's usr allows us to join them. Check JSClassRelease in // JavaScriptCore for an example. const String usr = RTags::eatString(clang_getCursorUSR(clang_getCanonicalCursor(cursor))); if (!usr.isEmpty()) mData->usrMap[usr].insert(location); switch (info->kind) { case CXCursor_Constructor: case CXCursor_Destructor: { Location parentLocation = createLocation(clang_getCursorSemanticParent(cursor)); // consider doing this for only declaration/inline definition since // declaration and definition should know of one another if (parentLocation.isValid()) { std::shared_ptr<CursorInfo> &parent = mData->symbols[parentLocation]; if (!parent) parent = std::make_shared<CursorInfo>(); parent->references.insert(location); info->references.insert(parentLocation); } break; } case CXCursor_CXXMethod: { List<CursorInfo*> infos; infos.append(info.get()); addOverriddenCursors(cursor, location, infos); break; } default: break; } } return true; }
void ClangIndexer::handleReference(const CXCursor &cursor, CXCursorKind kind, const Location &location, const CXCursor &ref, const CXCursor &parent) { const CXCursorKind refKind = clang_getCursorKind(ref); if (clang_isInvalid(refKind)) { superclassTemplateMemberFunctionUgleHack(cursor, kind, location, ref, parent); return; } bool isOperator = false; if (kind == CXCursor_CallExpr && (refKind == CXCursor_CXXMethod || refKind == CXCursor_ConversionFunction || refKind == CXCursor_FunctionDecl || refKind == CXCursor_FunctionTemplate)) { // these are bullshit, for this construct: // foo.bar(); // the position of the cursor is at the foo, not the bar. // They are not interesting for followLocation, renameSymbol or find // references so we toss them. // For functions it can be the position of the namespace. // E.g. Foo::bar(); cursor is on Foo // For constructors they happen to be the only thing we have that // actually refs the constructor and not the class so we have to keep // them for that. return; } switch (refKind) { case CXCursor_Constructor: if (isImplicit(ref)) return; break; case CXCursor_CXXMethod: case CXCursor_FunctionDecl: case CXCursor_FunctionTemplate: { CXStringScope scope = clang_getCursorDisplayName(ref); const char *data = scope.data(); if (data) { const int len = strlen(data); if (len > 8 && !strncmp(data, "operator", 8) && !isalnum(data[8]) && data[8] != '_') { if (isImplicit(ref)) return; // eat implicit operator calls isOperator = true; } } break; } default: break; } const Location reffedLoc = createLocation(ref); if (!reffedLoc.isValid()) { if (kind == CXCursor_ObjCMessageExpr) { mData->pendingReferenceMap[RTags::eatString(clang_getCursorUSR(clang_getCanonicalCursor(ref)))].insert(location); // insert it, we'll hook up the target and references later handleCursor(cursor, kind, location); } return; } std::shared_ptr<CursorInfo> &refInfo = mData->symbols[reffedLoc]; if ((!refInfo || !refInfo->symbolLength) && !handleCursor(ref, refKind, reffedLoc)) return; refInfo->references.insert(location); std::shared_ptr<CursorInfo> &info = mData->symbols[location]; if (!info) info = std::make_shared<CursorInfo>(); info->targets.insert(reffedLoc); // We need the new cursor to replace the symbolLength. This is important // in the following case: // struct R { R(const &r); ... } // R foo(); // ... // R r = foo(); // The first cursor on foo() will be a reference to the copy constructor and // this cursor will have a symbolLength of 1. Thus you won't be able to jump // to foo from the o. This is fixed by making sure the newer target, if // better, gets to decide on the symbolLength // The !isCursor is var decls and field decls where we set up a target even // if they're not considered references if (!RTags::isCursor(info->kind) && (!info->symbolLength || info->bestTarget(mData->symbols)->kind == refKind)) { CXSourceRange range = clang_getCursorExtent(cursor); CXSourceLocation rangeStart = clang_getRangeStart(range); CXSourceLocation rangeEnd = clang_getRangeEnd(range); unsigned startLine, startColumn, endLine, endColumn; clang_getPresumedLocation(rangeStart, 0, &startLine, &startColumn); clang_getPresumedLocation(rangeEnd, 0, &endLine, &endColumn); info->startLine = startLine; info->startColumn = startColumn; info->endLine = endLine; info->endColumn = endColumn; info->definition = false; info->kind = kind; if (isOperator) { unsigned start, end; clang_getSpellingLocation(rangeStart, 0, 0, 0, &start); clang_getSpellingLocation(rangeEnd, 0, 0, 0, &end); info->symbolLength = end - start; } else { info->symbolLength = refInfo->symbolLength; } info->symbolName = refInfo->symbolName; info->type = clang_getCursorType(cursor).kind; } }
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; }
Node* SparrowGeneralFixture::createSimpleConcept(StringRef name, CompilationContext* ctx) { auto res = SprFrontend::mkSprConcept(createLocation(), name, StringRef("x"), nullptr, nullptr); if (ctx) Nest_setContext(res, ctx); return res; }