std::string libclang_vim::stringize_extent(CXCursor const& cursor) { auto const r = clang_getCursorExtent(cursor); if (clang_Range_isNull(r)) return ""; return "'start':{" + stringize_location(clang_getRangeStart(r)) + "},'end':{" + stringize_location(clang_getRangeEnd(r)) + "}"; }
void ast_json::record_extent(json_t& obj, CXSourceRange extent) { CXSourceLocation startlocation = clang_getRangeStart( extent ); CXSourceLocation endlocation = clang_getRangeEnd( extent ); // Get exact source locations unsigned int startline = 0, startcolumn = 0, startoffset = 0; unsigned int endline = 0, endcolumn = 0, endoffset = 0; clang_getSpellingLocation( startlocation, nullptr, &startline, &startcolumn, &startoffset ); clang_getSpellingLocation( endlocation, nullptr, &endline, &endcolumn, &endoffset ); // Record source location obj[node::START_LINE] = startline; obj[node::START_COLUMN] = startcolumn; obj[node::START_OFFSET] = startoffset; obj[node::END_LINE] = endline; obj[node::END_COLUMN] = endcolumn; obj[node::END_OFFSET] = endoffset; }
void Highlight::highlightBlock(const QString &text) { CXToken *tokens; unsigned tokenCount; clang_tokenize(cx_tu,range, &tokens, &tokenCount); if (tokenCount > 0) { CXCursor *cursors = NULL; cursors = (CXCursor *)calloc(sizeof(CXCursor), tokenCount); clang_annotateTokens(cx_tu, tokens, tokenCount, cursors); for (unsigned i=0 ; i<tokenCount ; i++) { CXSourceRange sr = clang_getTokenExtent(cx_tu, tokens[i]); unsigned start, end; CXSourceLocation s = clang_getRangeStart(sr); CXSourceLocation e = clang_getRangeEnd(sr); clang_getInstantiationLocation(s, 0, 0, 0, &start); clang_getInstantiationLocation(e, 0, 0, 0, &end); qDebug()<<"start:"<<start<<"end:"<<end; /* if(start >end) { int tmp = start; start = end; end = tmp; } */ switch (cursors[i].kind) { case CXCursor_FirstRef... CXCursor_LastRef: break; case CXCursor_MacroDefinition: break; case CXCursor_MacroInstantiation: break; case CXCursor_FirstDecl...CXCursor_LastDecl: break; case CXCursor_ObjCMessageExpr: break; case CXCursor_DeclRefExpr: break; case CXCursor_PreprocessingDirective: { } break; default: break; } /* if(cursors[i].kind == CXCursor_FunctionDecl) setFormat(start, end-start, m_formatSingleLineComment);*/ } }
std::string libclang_vim::stringize_range(CXSourceRange const& range) { if (clang_Range_isNull(range)) { return ""; } return "'range':{'start':{" + stringize_location(clang_getRangeStart(range)) + "},'end':{" + stringize_location(clang_getRangeEnd(range)) + "}},"; }
CXChildVisitResult DumpThread::visitor(CXCursor cursor, CXCursor, CXClientData userData) { DumpThread *that = reinterpret_cast<DumpThread*>(userData); assert(that); CXSourceLocation location = clang_getCursorLocation(cursor); if (!clang_equalLocations(location, nullLocation)) { CXString file; unsigned line, col; clang_getPresumedLocation(location, &file, &line, &col); Path path = RTags::eatString(file); if (!path.isEmpty()) { uint32_t &fileId = that->mFiles[path]; if (!fileId) { const Path resolved = path.resolved(); fileId = Location::insertFile(resolved); that->mFiles[path] = that->mFiles[resolved] = fileId; } if (that->mQueryFlags & QueryMessage::DumpIncludeHeaders || fileId == that->mSource.fileId) { const Location loc(fileId, line, col); String message; message.reserve(256); if (!(that->mQueryFlags & QueryMessage::NoContext)) message += loc.context(); CXSourceRange range = clang_getCursorExtent(cursor); CXSourceLocation rangeEnd = clang_getRangeEnd(range); unsigned endLine, endColumn; clang_getPresumedLocation(rangeEnd, 0, &endLine, &endColumn); if (endLine == line) { message += String::format<32>(" // %d-%d, %d: ", col, endColumn, that->mIndentLevel); } else { message += String::format<32>(" // %d-%d:%d, %d: ", col, endLine, endColumn, that->mIndentLevel); } message += RTags::cursorToString(cursor, RTags::AllCursorToStringFlags); message.append(" " + RTags::typeName(cursor) + " "); 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)); } that->writeToConnetion(message); } } } ++that->mIndentLevel; clang_visitChildren(cursor, DumpThread::visitor, userData); --that->mIndentLevel; return CXChildVisit_Continue; }
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; } } } } } } }
void PrintDiagnostic(CXDiagnostic Diagnostic) { FILE *out = stderr; CXFile file; CXString Msg; unsigned display_opts = CXDiagnostic_DisplaySourceLocation | CXDiagnostic_DisplayColumn | CXDiagnostic_DisplaySourceRanges; unsigned i, num_fixits; if (clang_getDiagnosticSeverity(Diagnostic) == CXDiagnostic_Ignored) return; Msg = clang_formatDiagnostic(Diagnostic, display_opts); fprintf(stderr, "%s\n", clang_getCString(Msg)); clang_disposeString(Msg); clang_getInstantiationLocation(clang_getDiagnosticLocation(Diagnostic), &file, 0, 0, 0); if (!file) return; num_fixits = clang_getDiagnosticNumFixIts(Diagnostic); for (i = 0; i != num_fixits; ++i) { CXSourceRange range; CXString insertion_text = clang_getDiagnosticFixIt(Diagnostic, i, &range); CXSourceLocation start = clang_getRangeStart(range); CXSourceLocation end = clang_getRangeEnd(range); unsigned start_line, start_column, end_line, end_column; CXFile start_file, end_file; clang_getInstantiationLocation(start, &start_file, &start_line, &start_column, 0); clang_getInstantiationLocation(end, &end_file, &end_line, &end_column, 0); if (clang_equalLocations(start, end)) { /* Insertion. */ if (start_file == file) fprintf(out, "FIX-IT: Insert \"%s\" at %d:%d\n", clang_getCString(insertion_text), start_line, start_column); } else if (strcmp(clang_getCString(insertion_text), "") == 0) { /* Removal. */ if (start_file == file && end_file == file) { fprintf(out, "FIX-IT: Remove "); PrintExtent(out, start_line, start_column, end_line, end_column); fprintf(out, "\n"); } } else { /* Replacement. */ if (start_file == end_file) { fprintf(out, "FIX-IT: Replace "); PrintExtent(out, start_line, start_column, end_line, end_column); fprintf(out, " with \"%s\"\n", clang_getCString(insertion_text)); } break; } clang_disposeString(insertion_text); } }
static void PrintCursorExtent(CXCursor C) { CXSourceRange extent = clang_getCursorExtent(C); CXFile begin_file, end_file; unsigned begin_line, begin_column, end_line, end_column; clang_getInstantiationLocation(clang_getRangeStart(extent), &begin_file, &begin_line, &begin_column, 0); clang_getInstantiationLocation(clang_getRangeEnd(extent), &end_file, &end_line, &end_column, 0); if (!begin_file || !end_file) return; printf(" Extent="); PrintExtent(stdout, begin_line, begin_column, end_line, end_column); }
static CXChildVisitResult visitTranslationUnit(CXCursor cursor, CXCursor parent, CXClientData client_data) { visitTranslationUnitData *data = static_cast<visitTranslationUnitData*>(client_data); CXSourceRange range = clang_getCursorExtent(cursor); CXSourceLocation startLoc = clang_getRangeStart(range); CXSourceLocation endLoc = clang_getRangeEnd(range); CXFile file; unsigned startOffset; unsigned endOffset; clang_getSpellingLocation(startLoc, &file, nullptr, nullptr, &startOffset); clang_getSpellingLocation(endLoc, &file, nullptr, nullptr, &endOffset); // Use the smallest cursor that surrounds the desired location. unsigned size = endOffset - startOffset; if(clangFilesEqual(file, data->mFile) && startOffset < data->mDesiredOffset && endOffset > data->mDesiredOffset) { if(size < data->mSize) { data->mCursor = cursor; data->mSize = size; fprintf(sLog.mFp, "GOOD:\n "); } } CXStringDisposer sp = clang_getCursorSpelling(cursor); CXStringDisposer kind = clang_getCursorKindSpelling(cursor.kind); std::string fn; if(file) { CXStringDisposer s = clang_getFileName(file); fn = s; } fprintf(sLog.mFp, "%s %s off %d size %d des offset %d file %s\n", kind.c_str(), sp.c_str(), startOffset, size, data->mDesiredOffset, fn.c_str()); DUMP_PARSE("visitTU", cursor); // clang_visitChildren(cursor, ::visitTranslationUnit, client_data); // return CXChildVisit_Continue; return CXChildVisit_Recurse; }
void TokenRange::tokenize(CXTranslationUnit transUnit) { CXCursor cursor = clang_getTranslationUnitCursor(transUnit); CXSourceRange range = clang_getCursorExtent(cursor); CXToken *tokens = 0; unsigned int numTokens = 0; clang_tokenize(transUnit, range, &tokens, &numTokens); resize(numTokens); if(numTokens > 0) { for (size_t i = 0; i < numTokens-1; i++) { at(i).setKind(clang_getTokenKind(tokens[i])); CXSourceRange tokRange = clang_getTokenExtent(transUnit, tokens[i]); clang_getExpansionLocation(clang_getRangeStart(tokRange), NULL, NULL, NULL, &at(i).mStartOffset); clang_getExpansionLocation(clang_getRangeEnd(tokRange), NULL, NULL, NULL, &at(i).mEndOffset); } } clang_disposeTokens(transUnit, tokens, numTokens); }
static void printCursor(CXCursor cursor) { CXFile file; unsigned int off, line, col; CXSourceLocation location = clang_getCursorLocation(cursor); clang_getSpellingLocation(location, &file, &line, &col, &off); CXString fileName = clang_getFileName(file); const char *fileNameCStr = clang_getCString(fileName); if (fileNameCStr) { CXSourceRange range = clang_getCursorExtent(cursor); unsigned int start, end; clang_getSpellingLocation(clang_getRangeStart(range), 0, 0, 0, &start); clang_getSpellingLocation(clang_getRangeEnd(range), 0, 0, 0, &end); printf("%s:%d:%d (%d, %d-%d) ", fileNameCStr, line, col, off, start, end); } clang_disposeString(fileName); printString("kind", clang_getCursorKindSpelling(clang_getCursorKind(cursor))); printString("display name", clang_getCursorDisplayName(cursor)); printString("usr", clang_getCursorUSR(cursor)); if (clang_isCursorDefinition(cursor)) printf("definition "); printf("\n"); }
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 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; }
Range::Range( const CXSourceRange &range ) { start_ = Location( clang_getRangeStart( range ) ); end_ = Location( clang_getRangeEnd( range ) ); }
void printTreeRecursive(struct treeNode* node, CXTranslationUnit cxtup) { depth++; if(node->modified == 0) { CXSourceRange range = clang_getCursorExtent(node->cursor); CXSourceLocation rstart = clang_getRangeStart(range); if(clang_Location_isFromMainFile(rstart) != 0) { enum CXCursorKind cursorkind = clang_getCursorKind(node->cursor); if(depth == 1 && cursorkind != CXCursor_MacroExpansion) { nodenum++; if(cursorkind == CXCursor_StructDecl) { CXToken* currTokens; unsigned int numCurrTokens; clang_tokenize(cxtup, range, &currTokens, &numCurrTokens); CXToken token = currTokens[numCurrTokens-1]; CXString tokenstring = clang_getTokenSpelling(cxtup, token); char* tokenstr = clang_getCString(tokenstring); clang_disposeTokens(cxtup, currTokens, numCurrTokens); //printf("\ntoken: %s\n", tokenstr); if(strcmp(tokenstr, ";")) { clang_disposeString(tokenstring); // Print nothing, do nothing. } else { clang_disposeString(tokenstring); goto PRINT; } } else { PRINT: 1+1; CXToken* tokens; unsigned int numTokens; clang_tokenize(cxtup, range, &tokens, &numTokens); CXString tokenstring; CXSourceRange tokenrange; unsigned* startcol = malloc(sizeof(unsigned)); unsigned* startline = malloc(sizeof(unsigned)); unsigned* endcol = malloc(sizeof(unsigned)); unsigned* endline = malloc(sizeof(unsigned)); for(int i = 0; i<numTokens; i++) { tokenrange = clang_getTokenExtent(cxtup, tokens[i]); tokenstring = clang_getTokenSpelling(cxtup, tokens[i]); CXSourceLocation currend = clang_getRangeEnd(tokenrange); clang_getFileLocation(currend, NULL, endline, endcol, NULL); if(prevcol != 0) { CXSourceLocation currstart = clang_getRangeStart(tokenrange); clang_getFileLocation(currstart, NULL, startline, startcol, NULL); //printf("L%u-%u, C%u-%u", *startline, prevline, *startcol, prevcol); int startl = *startline; int startc = *startcol; for(int i = 0; i < startl-prevline; i++) { printf("\n"); //printf("*startline-prevline = %u, i = %u, prevline = %u\n", start-prevline, i, prevline); } if(startc-prevcol >= 0) { for(int i = 0; i < startc-prevcol; i++) { printf(" "); } } else { for(int i = 1; i < startc; i++) { printf(" "); } } } char* tstr = clang_getCString(tokenstring); /*if(i == 0 && !strcmp(tstr, lastPrintedToken)) { // Do nothing, print nothing. } else {*/ printf("%s", tstr); //} prevline = *endline; prevcol = *endcol; char* str = clang_getCString(tokenstring); strcpy(lastPrintedToken, str); clang_disposeString(tokenstring); } //printf("%i\n", lastPrintedToken); //printf("\n"); clang_disposeTokens(cxtup, tokens, numTokens); free(startcol); free(startline); free(endcol); free(endline); } } } } else if(depth == 1) { //printf("Modified node detected."); if(node->validcursor == false) { //Print modified //printf("%s\n", node->newContent); } else { struct treeNode** nodes = malloc((node->modified) * sizeof(struct treeNode)); //printf("%i\n", sizeof(nodes)) nodes[node->modified-1] = NULL; //printf("nodes[node->modified-1]: %i\n", nodes[node->modified-1]); struct treeNode* next = NULL; int nextnode = 0; int smallestcol = INT_MAX; int smallestline = INT_MAX; int cscol = INT_MIN; int csline = INT_MIN; struct treeListNode* currnode = node->modifiedNodes; CXSourceRange srange; CXSourceLocation sloc; bool first = true; while(nodes[(node->modified)-1] == NULL) { while(currnode != NULL) { if(currnode->node->startline == -1) { srange = clang_getCursorExtent(currnode->node->cursor); sloc = clang_getRangeStart(srange); clang_getFileLocation(sloc, NULL, &(currnode->node->startline), &(currnode->node->startcol), NULL); //printf("Calculated node %i: startline: %i, startcol: %i\n", currnode->node, currnode->node->startline, currnode->node->startcol); } //printf("\ncurrnode->node: %i, nextnode: %i\nnstartline: %i, smallestline: %i ,csline: %i\nnstartcol: %i, smallestcol: %i, cscol: %i\n", currnode->node, nextnode, currnode->node->startline, smallestline, csline, currnode->node->startcol, smallestcol, cscol); if(currnode->node->startline < smallestline) { //printf("\n1\, %i < %i", currnode->node->startline, smallestline); if((currnode->node->startline > csline) || (first == true)) { //printf("\n2, %i > %i", currnode->node->startline); smallestline = currnode->node->startline; smallestcol = currnode->node->startcol; csline = currnode->node->startline; cscol = currnode->node->startcol; next = currnode->node; } } else if(currnode->node->startline == smallestline) { //printf("3\n"); if(currnode->node->startcol < smallestcol) { //printf("4\n"); if((currnode->node->startcol > cscol) || (first == true)) { //printf("5\n"); smallestline = currnode->node->startline; smallestcol = currnode->node->startcol; csline = currnode->node->startline; cscol = currnode->node->startcol; next = currnode->node; } } } //printf("\n6\n"); //printf("currnode->node: %i, nextnode: %i\nnstartline: %i, smallestline: %i ,csline: %i\nnstartcol: %i, smallestcol: %i, cscol: %i\n", currnode->node, nextnode, currnode->node->startline, smallestline, csline, currnode->node->startcol, smallestcol, cscol); currnode = currnode->next; } first = false; //printf("%i ", nodes[nextnode]); //printf("%i\n", next); nodes[nextnode] = next; nextnode++; smallestcol = INT_MAX; smallestline = INT_MAX; currnode = node->modifiedNodes; } for(int i = 0; i <= 1; i++) { //printf("nodenum: %i, nstartline: %i, nstartcol: %i\n", i, nodes[i]->startline, nodes[i]->startcol); } CXSourceRange range = clang_getCursorExtent(node->cursor); CXToken* tokens; unsigned int numTokens; int numNodes = nextnode; nextnode = 0; clang_tokenize(cxtup, range, &tokens, &numTokens); for(int i = 0; i<numTokens; i++) { CXSourceRange tokenrange = clang_getTokenExtent(cxtup, tokens[i]); CXString tokenstring = clang_getTokenSpelling(cxtup, tokens[i]); unsigned startline; unsigned startcol; unsigned endline; unsigned endcol; CXSourceLocation currend = clang_getRangeEnd(tokenrange); clang_getFileLocation(currend, NULL, &endline, &endcol, NULL); if(prevcol != 0) { CXSourceLocation currstart = clang_getRangeStart(tokenrange); clang_getFileLocation(currstart, NULL, &startline, &startcol, NULL); //printf("L%u-%u, C%u-%u", *startline, prevline, *startcol, prevcol); int startl = startline; int startc = startcol; for(int i = 0; i < startl-prevline; i++) { printf("\n"); //printf("*startline-prevline = %u, i = %u, prevline = %u\n", start-prevline, i, prevline); } if(startc-prevcol >= 0) { for(int i = 0; i < startc-prevcol; i++) { printf(" "); } } else { for(int i = 0; i < startc; i++) { printf(" "); } } } char* tstr = clang_getCString(tokenstring); if(i == 0 && !strcmp(tstr, lastPrintedToken)) { // Do nothing, print nothing. } else { //printf("nextstartline: %i, startline: %i\n", nodes[nextnode]->startline, startline); if((nextnode < numNodes) && (nodes[nextnode]->startline == startline) && (nodes[nextnode]->startcol == startcol)) { int* nodenext = &(nodes[nextnode]->cursor); if(nodenext == NULL) { printf("%s\n", nodes[nextnode]->newContent); nextnode++; } else { printf("%s", nodes[nextnode]->newContent); prevline = endline; prevcol = endcol; nextnode++; } } else { printf("%s", tstr); prevline = endline; prevcol = endcol; } } //printf("%i\n", sizeof(nodes)); char* str = clang_getCString(tokenstring); strcpy(lastPrintedToken, str); clang_disposeString(tokenstring); } clang_disposeTokens(cxtup, tokens, numTokens); free(nodes); } } if(node->children != NULL) { struct treeListNode* childlist = node->children; while(childlist != NULL) { printTreeRecursive(childlist->node, cxtup); childlist = childlist->next; } } depth--; }
SourceLocation getEnd() const { return getSourceLocation(clang_getRangeEnd(m_range)); }
source_location source_range::end() { return { clang_getRangeEnd(range) }; }
void TokenizeSource(CXTranslationUnit tu) { CXSourceRange range = clang_getCursorExtent( clang_getTranslationUnitCursor(tu) ); CXToken *tokens; unsigned int token_count; clang_tokenize( tu, range, &tokens, &token_count ); //CXCursor cursors[ token_count ]; //clang_annotateTokens( tu, tokens, token_count, cursors ); auto cursors = my_annotateTokens( tu, tokens, token_count ); for ( auto t = 0u; t < token_count; ++t ) { auto tkind = clang_getTokenKind(tokens[t] ); auto tspelling = tkind == CXToken_Identifier ? CursorKindSpelling( cursors[ t ] ) : TokenKindSpelling( tkind ); auto textent = clang_getTokenExtent( tu, tokens[t] ); auto tstartloc = clang_getRangeStart( textent ); auto tendloc = clang_getRangeEnd( textent ); auto tokspell = clang_getTokenSpelling( tu, tokens[ t ] ); std::cout << "TokenSpelling: " << tokspell << "\n"; std::cout << "Cursor: " << cursors[ t ] << "\n"; // if ( !( cursors[t].kind >= CXCursor_FirstInvalid && // cursors[t].kind <= CXCursor_LastInvalid ) ) { // auto rr = clang_getCursorExtent( cursors[ t ] ); // std::cout << "Range: " << rr << "\n"; // } // std::cout << clang_getCursorDisplayName( cursors[ t ] ) << "\n"; // std::cout << "USR: "******"\n"; unsigned int startoffset, endoffset; clang_getSpellingLocation( tstartloc, nullptr, nullptr, nullptr, &startoffset ); clang_getSpellingLocation( tendloc, nullptr, nullptr, nullptr, &endoffset ); // TODO: testing this hack for int -> identifier instead of keyword // but this loses const to an identifier also! fvck! if ( tspelling == "Keyword" ) { auto type = clang_getCursorType( cursors[ t ] ); auto typekind = type.kind; CXString typespelling; if ( cursors[t].kind == CXCursor_FunctionDecl || cursors[t].kind == CXCursor_CXXMethod ) { type = clang_getResultType( type ); typekind = type.kind; typespelling = clang_getTypeSpelling( type ); } else typespelling = clang_getTypeSpelling( type ); // std::cout << "Type = " << type << " kind: " << typekind << "\n"; // std::cout << clang_getCString(typespelling) << " <-> " << clang_getCString(tokspell) << "\n"; // std::cout << " Const? " << clang_isConstQualifiedType( type ) << "\n"; if ( (( typekind >= CXType_FirstBuiltin && typekind <= CXType_LastBuiltin ) && ( std::string(clang_getCString(typespelling)) == std::string(clang_getCString(tokspell) ) )) || // ( cursors[t].kind == CXCursor_VarDecl ) || ( cursors[t].kind == CXCursor_ParmDecl ) ) tspelling = "Identifier"; } //if ( tspelling != "Punctuation" ) std::cout << startoffset << ":" << endoffset << " @ " << tspelling << "\n"; clang_disposeString( tokspell ); } std::cout << "\n" << end_pattern << "\n"; clang_disposeTokens( tu, tokens, token_count ); }
std::ostream& operator<<( std::ostream& os, CXSourceRange range ) { auto beg = clang_getRangeStart( range ); auto end = clang_getRangeEnd( range ); return os << beg << " -> " << end << "\n"; }
void TextEdit::slotReparse() { //connect(this,SIGNAL(textChanged()), this,SLOT(slotReparse())); QTextCursor tc = textCursor(); tc.select(QTextCursor::WordUnderCursor); QString prefix = tc.selectedText(); completionList->clear(); qDebug()<<prefix; //clang_disposeTranslationUnit(cx_tu); struct CXUnsavedFile unsaved_file; unsaved_file.Filename = "/tmp/a.m"; unsaved_file.Contents = strdup(this->toPlainText().toStdString().c_str()); unsaved_file.Length = this->toPlainText().length(); clang_reparseTranslationUnit( cx_tu, 1, &unsaved_file, CXTranslationUnit_PrecompiledPreamble); CXFile file = clang_getFile(cx_tu, unsaved_file.Filename); CXSourceLocation start = clang_getLocationForOffset(cx_tu, file, 0); CXSourceLocation end = clang_getLocationForOffset(cx_tu, file, this->toPlainText().length()); CXSourceRange range= clang_getRange(start,end); CXToken *tokens; unsigned tokenCount; clang_tokenize(cx_tu,range, &tokens, &tokenCount); if (tokenCount > 0) { CXCursor *cursors = NULL; cursors = (CXCursor *)calloc(sizeof(CXCursor), tokenCount); clang_annotateTokens(cx_tu, tokens, tokenCount, cursors); for (unsigned i=0 ; i<tokenCount ; i++) { CXSourceRange sr = clang_getTokenExtent(cx_tu, tokens[i]); unsigned start, end; CXSourceLocation s = clang_getRangeStart(sr); CXSourceLocation e = clang_getRangeEnd(sr); clang_getInstantiationLocation(s, 0, 0, 0, &start); clang_getInstantiationLocation(e, 0, 0, 0, &end); qDebug()<<"start:"<<start<<"end:"<<end; /* if(start >end) { int tmp = start; start = end; end = tmp; } */ switch (cursors[i].kind) { case CXCursor_FirstRef... CXCursor_LastRef: break; case CXCursor_MacroDefinition: break; case CXCursor_MacroInstantiation: break; case CXCursor_FirstDecl...CXCursor_LastDecl: break; case CXCursor_ObjCMessageExpr: break; case CXCursor_DeclRefExpr: break; case CXCursor_PreprocessingDirective: { } break; default: break; } /* if(cursors[i].kind == CXCursor_FunctionDecl) setFormat(start, end-start, m_formatSingleLineComment);*/ } }
String cursorToString(CXCursor cursor, unsigned flags) { const CXCursorKind kind = clang_getCursorKind(cursor); String ret; ret.reserve(256); ret += eatString(clang_getCursorKindSpelling(kind)); if (clang_isInvalid(kind)) return ret; switch (RTags::cursorType(kind)) { case Reference: ret += " r"; break; case Cursor: ret += " c"; break; case Other: ret += " o"; break; case Include: ret += " i"; break; } const String name = eatString(clang_getCursorDisplayName(cursor)); const String other = eatString(clang_getCursorSpelling(cursor)); if (!name.isEmpty()) ret += " " + name; if (other != name && !other.isEmpty()) ret += " " + other; if (clang_isCursorDefinition(cursor)) ret += " def"; if (flags & IncludeUSR) ret += " " + eatString(clang_getCursorUSR(cursor)); CXFile file; unsigned off, line, col; //presumedLine, presumedCol, instantiationLoc, expansionLoc; CXSourceLocation location = clang_getCursorLocation(cursor); clang_getSpellingLocation(location, &file, &line, &col, &off); // clang_getPresumedLocation(location, 0, &presumedLine, &presumedCol); // clang_getInstantiationLocation(location, 0, 0, 0, &instantiationLoc); // clang_getExpansionLocation(location, 0, 0, 0, &expansionLoc); const Str fileName(clang_getFileName(file)); if (fileName.data() && *fileName.data()) { ret += ' '; ret += fileName.data(); ret += ','; ret += String::number(off); if (flags & IncludeRange) { ret += " ("; 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); ret += String::number(start); ret += '-'; ret += String::number(end); ret += ')'; } // if (presumedLine != line || presumedCol != col) // ret += String::snprintf<32>("presumed: %d:%d", presumedLine, presumedCol); // if (instantiationLoc != off) // ret += String::snprintf<32>("instantiation: %d", instantiationLoc); // if (expansionLoc != off) // ret += String::snprintf<32>("expansion: %d", expansionLoc); } return ret; }
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(); }
Range::Range(CXCursor cursor) : range(clang_getCursorExtent(cursor)) , start(clang_getRangeStart(range)) , end(clang_getRangeEnd(range)) {}
void PrintDiagnostic(CXDiagnostic Diagnostic) { FILE *out = stderr; CXFile file; CXString text; unsigned display_opts = CXDiagnostic_DisplaySourceLocation | CXDiagnostic_DisplayColumn | CXDiagnostic_DisplaySourceRanges; unsigned i, num_fixits; clang_displayDiagnostic(Diagnostic, out, display_opts); if (clang_getDiagnosticSeverity(Diagnostic) == CXDiagnostic_Ignored) return; clang_getInstantiationLocation(clang_getDiagnosticLocation(Diagnostic), &file, 0, 0, 0); if (!file) return; num_fixits = clang_getDiagnosticNumFixIts(Diagnostic); for (i = 0; i != num_fixits; ++i) { switch (clang_getDiagnosticFixItKind(Diagnostic, i)) { case CXFixIt_Insertion: { CXSourceLocation insertion_loc; CXFile insertion_file; unsigned insertion_line, insertion_column; text = clang_getDiagnosticFixItInsertion(Diagnostic, i, &insertion_loc); clang_getInstantiationLocation(insertion_loc, &insertion_file, &insertion_line, &insertion_column, 0); if (insertion_file == file) fprintf(out, "FIX-IT: Insert \"%s\" at %d:%d\n", clang_getCString(text), insertion_line, insertion_column); clang_disposeString(text); break; } case CXFixIt_Removal: { CXFile start_file, end_file; unsigned start_line, start_column, end_line, end_column; CXSourceRange remove_range = clang_getDiagnosticFixItRemoval(Diagnostic, i); clang_getInstantiationLocation(clang_getRangeStart(remove_range), &start_file, &start_line, &start_column, 0); clang_getInstantiationLocation(clang_getRangeEnd(remove_range), &end_file, &end_line, &end_column, 0); if (start_file == file && end_file == file) { fprintf(out, "FIX-IT: Remove "); PrintExtent(out, start_line, start_column, end_line, end_column); fprintf(out, "\n"); } break; } case CXFixIt_Replacement: { CXFile start_file, end_file; unsigned start_line, start_column, end_line, end_column; CXSourceRange remove_range; text = clang_getDiagnosticFixItReplacement(Diagnostic, i,&remove_range); clang_getInstantiationLocation(clang_getRangeStart(remove_range), &start_file, &start_line, &start_column, 0); clang_getInstantiationLocation(clang_getRangeEnd(remove_range), &end_file, &end_line, &end_column, 0); if (start_file == end_file) { fprintf(out, "FIX-IT: Replace "); PrintExtent(out, start_line, start_column, end_line, end_column); fprintf(out, " with \"%s\"\n", clang_getCString(text)); } clang_disposeString(text); break; } } } }
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; }
int perform_token_annotation(int argc, const char **argv) { const char *input = argv[1]; char *filename = 0; unsigned line, second_line; unsigned column, second_column; CXIndex CIdx; CXTranslationUnit TU = 0; int errorCode; struct CXUnsavedFile *unsaved_files = 0; int num_unsaved_files = 0; CXToken *tokens; unsigned num_tokens; CXSourceRange range; CXSourceLocation startLoc, endLoc; CXFile file = 0; CXCursor *cursors = 0; unsigned i; input += strlen("-test-annotate-tokens="); if ((errorCode = parse_file_line_column(input, &filename, &line, &column, &second_line, &second_column))) return errorCode; if (parse_remapped_files(argc, argv, 2, &unsaved_files, &num_unsaved_files)) return -1; CIdx = clang_createIndex(0, 1); TU = clang_createTranslationUnitFromSourceFile(CIdx, argv[argc - 1], argc - num_unsaved_files - 3, argv + num_unsaved_files + 2, num_unsaved_files, unsaved_files); if (!TU) { fprintf(stderr, "unable to parse input\n"); clang_disposeIndex(CIdx); free(filename); free_remapped_files(unsaved_files, num_unsaved_files); return -1; } errorCode = 0; file = clang_getFile(TU, filename); if (!file) { fprintf(stderr, "file %s is not in this translation unit\n", filename); errorCode = -1; goto teardown; } startLoc = clang_getLocation(TU, file, line, column); if (clang_equalLocations(clang_getNullLocation(), startLoc)) { fprintf(stderr, "invalid source location %s:%d:%d\n", filename, line, column); errorCode = -1; goto teardown; } endLoc = clang_getLocation(TU, file, second_line, second_column); if (clang_equalLocations(clang_getNullLocation(), endLoc)) { fprintf(stderr, "invalid source location %s:%d:%d\n", filename, second_line, second_column); errorCode = -1; goto teardown; } range = clang_getRange(startLoc, endLoc); clang_tokenize(TU, range, &tokens, &num_tokens); cursors = (CXCursor *)malloc(num_tokens * sizeof(CXCursor)); clang_annotateTokens(TU, tokens, num_tokens, cursors); for (i = 0; i != num_tokens; ++i) { const char *kind = "<unknown>"; CXString spelling = clang_getTokenSpelling(TU, tokens[i]); CXSourceRange extent = clang_getTokenExtent(TU, tokens[i]); unsigned start_line, start_column, end_line, end_column; switch (clang_getTokenKind(tokens[i])) { case CXToken_Punctuation: kind = "Punctuation"; break; case CXToken_Keyword: kind = "Keyword"; break; case CXToken_Identifier: kind = "Identifier"; break; case CXToken_Literal: kind = "Literal"; break; case CXToken_Comment: kind = "Comment"; break; } clang_getInstantiationLocation(clang_getRangeStart(extent), 0, &start_line, &start_column, 0); clang_getInstantiationLocation(clang_getRangeEnd(extent), 0, &end_line, &end_column, 0); printf("%s: \"%s\" ", kind, clang_getCString(spelling)); PrintExtent(stdout, start_line, start_column, end_line, end_column); if (!clang_isInvalid(cursors[i].kind)) { printf(" "); PrintCursor(cursors[i]); } printf("\n"); } free(cursors); teardown: PrintDiagnostics(TU); clang_disposeTranslationUnit(TU); clang_disposeIndex(CIdx); free(filename); free_remapped_files(unsaved_files, num_unsaved_files); return errorCode; }
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; } }
SourceLocation SourceRange::GetEnd() const { return clang_getRangeEnd(sourceRange_); }
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 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; }