void ClangParser::switchToFile(const char *fileName) { if (p->tu) { delete[] p->cursors; clang_disposeTokens(p->tu,p->tokens,p->numTokens); p->tokens = 0; p->numTokens = 0; p->cursors = 0; QFileInfo fi(fileName); CXFile f = clang_getFile(p->tu, fileName); uint *pIndex=p->fileMapping.find(fileName); if (pIndex && *pIndex<p->numFiles) { uint i=*pIndex; //printf("switchToFile %s: len=%ld\n",fileName,p->ufs[i].Length); CXSourceLocation fileBegin = clang_getLocationForOffset(p->tu, f, 0); CXSourceLocation fileEnd = clang_getLocationForOffset(p->tu, f, p->ufs[i].Length); CXSourceRange fileRange = clang_getRange(fileBegin, fileEnd); clang_tokenize(p->tu,fileRange,&p->tokens,&p->numTokens); p->cursors=new CXCursor[p->numTokens]; clang_annotateTokens(p->tu,p->tokens,p->numTokens,p->cursors); p->curLine = 1; p->curToken = 0; } else { err("clang: Failed to find input file %s in mapping\n",fileName); } } }
void ast_json::record_tokens( json_t& obj, CXCursor cursor, CXTranslationUnit translation_unit) { // Get source code extent of node CXSourceRange extent = clang_getCursorExtent(cursor); // Tokenize node's contents CXToken *tokens; unsigned int nTokens; clang_tokenize(translation_unit, extent, &tokens, &nTokens); // JSONize every token for (unsigned i = 0; i < nTokens; i++) { const CXToken& token = tokens[i]; json_t jsontoken; record_token(jsontoken, token, translation_unit); obj.add(jsontoken); } // Release tokens clang_disposeTokens(translation_unit, tokens, nTokens); }
static CXCursor getCursorUsingTokens(CXTranslationUnit tu, CXCursor cursor, unsigned int desiredOffset) { // The following does not return a more definitive cursor. // For example, if a compound statement is returned, this does not find // any variables in the statement. CXSourceRange range = clang_getCursorExtent(cursor); CXToken *tokens; unsigned numTokens; clang_tokenize(tu, range, &tokens, &numTokens); unsigned int closestOffset = 0; for(unsigned int i=0; i<numTokens; i++) { CXSourceLocation loc = clang_getTokenLocation(tu, tokens[i]); unsigned int offset; CXFile file; clang_getSpellingLocation(loc, &file, nullptr, nullptr, &offset); if(offset < desiredOffset && offset > closestOffset) { closestOffset = offset; cursor = clang_getCursor(tu, loc); } } clang_disposeTokens(tu, tokens, numTokens); return cursor; }
std::string tokenize_as_vimson(char const* const* args, size_t const argc) { CXIndex index = clang_createIndex(/*excludeDeclsFromPCH*/ 1, /*displayDiagnostics*/0); translation_unit = clang_parseTranslationUnit(index, file_name.c_str(), args, argc, NULL, 0, CXTranslationUnit_Incomplete); if (translation_unit == NULL) { clang_disposeIndex(index); return "{}"; } auto file_range = get_range_whole_file(); if (clang_Range_isNull(file_range)) { clang_disposeTranslationUnit(translation_unit); clang_disposeIndex(index); return "{}"; } CXToken *tokens_; unsigned int num_tokens; clang_tokenize(translation_unit, file_range, &tokens_, &num_tokens); std::vector<CXToken> tokens(tokens_, tokens_ + num_tokens); auto result = make_vimson_from_tokens(tokens); clang_disposeTokens(translation_unit, tokens_, num_tokens); clang_disposeTranslationUnit(translation_unit); clang_disposeIndex(index); return result; }
void Html_File::write_html(void) { cur_line_ = 1; cur_column_ = 1; CXFile file = clang_getFile(tu_file_->tu(), source_filename_.c_str()); CXSourceRange range = clang_getRange(clang_getLocationForOffset(tu_file_->tu(), file, 0), clang_getLocationForOffset(tu_file_->tu(), file, tu_file_->length())); CXToken *tokens; unsigned num; clang_tokenize(tu_file_->tu(), range, &tokens, &num); FILE* f = fopen(html_filename_.c_str(), "w"); if (f) { write_header(f); for (unsigned i = 0; i < num; ++i) write_comment_split(f, file, tokens[i]); fprintf(f, "</pre></div></div></body></html>"); fclose(f); } else std::cerr << "error: could not create file: " << html_filename_.c_str() << "\n"; clang_disposeTokens(tu_file_->tu(), tokens, num); }
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);*/ } }
token_set translation_unit::tokenize(source_range range) { CXToken *tokens; unsigned size; clang_tokenize(tu, range.range, &tokens, &size); return { tu, tokens, size }; }
token_pack(translation_unit const &tu, source_range_t const &range) : tu_{ tu } , range_{ range } { unsigned num{}; clang_tokenize(tu_.impl, range_, &data_, &num); size_ = num; }
HighlightingInformations TranslationUnit::highlightingInformationsInRange(const SourceRange &range) const { CXToken *cxTokens = 0; uint cxTokensCount = 0; auto translationUnit = cxTranslationUnit(); clang_tokenize(translationUnit, range, &cxTokens, &cxTokensCount); return HighlightingInformations(translationUnit, cxTokens, cxTokensCount); }
/// @todo - this is a duplicate of a function in ParseBase.cpp void appendCursorTokenString(CXCursor cursor, std::string &str) { CXSourceRange range = clang_getCursorExtent(cursor); CXToken *tokens = 0; unsigned int nTokens = 0; CXTranslationUnit tu = clang_Cursor_getTranslationUnit(cursor); clang_tokenize(tu, range, &tokens, &nTokens); for (size_t i = 0; i < nTokens; i++) { CXTokenKind kind = clang_getTokenKind(tokens[i]); if(kind != CXToken_Comment) { if(str.length() != 0) str += " "; CXStringDisposer spelling = clang_getTokenSpelling(tu, tokens[i]); str += spelling; } } clang_disposeTokens(tu, tokens, nTokens); }
std::string getFirstNonCommentToken(CXCursor cursor) { CXSourceRange range = clang_getCursorExtent(cursor); CXToken *tokens = 0; unsigned int nTokens = 0; CXTranslationUnit tu = clang_Cursor_getTranslationUnit(cursor); clang_tokenize(tu, range, &tokens, &nTokens); std::string str; for (size_t i = 0; i < nTokens; i++) { CXTokenKind kind = clang_getTokenKind(tokens[i]); if(kind != CXToken_Comment) { CXStringDisposer spelling = clang_getTokenSpelling(tu, tokens[i]); str += spelling; break; } } clang_disposeTokens(tu, tokens, nTokens); return str; }
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); }
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--; }
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);*/ } }
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; }
enum CXChildVisitResult visit_program(CXCursor cursor, CXCursor parent, CXClientData data){ json_t* program = (json_t*)data; json_t* js = NULL; enum CXChildVisitResult ret = CXChildVisit_Continue; switch (clang_getCursorKind(cursor)) { case CXCursor_FunctionDecl: case CXCursor_VarDecl: js = json_object(); json_object_set_new(js, "name", render_string(clang_getCursorSpelling(cursor))); json_object_set_new(js, "display_name", render_string(clang_getCursorDisplayName(cursor))); json_object_set_new(js, "type", render_type(clang_getCursorType(cursor))); if (clang_getCursorKind(cursor) == CXCursor_FunctionDecl) { json_object_set_new(js, "argument_names", json_array()); json_object_set_new(js, "kind", json_string("function")); } else { json_object_set_new(js, "kind", json_string("variable")); } switch (clang_getCursorLinkage(cursor)) { case CXLinkage_Internal: json_object_set_new(js, "linkage", json_string("static")); break; case CXLinkage_UniqueExternal: json_object_set_new(js, "linkage", json_string("anonymous")); break; case CXLinkage_External: break; default: json_object_set_new(js, "linkage", json_string("unknown")); } clang_visitChildren(cursor, visit_object, (CXClientData)js); break; case CXCursor_StructDecl: case CXCursor_UnionDecl: js = json_object(); json_object_set_new(js, "kind", json_string(clang_getCursorKind(cursor) == CXCursor_UnionDecl ? "union" : "struct")); json_object_set_new(js, "name", render_string(clang_getCursorSpelling(cursor))); json_object_set_new(js, "fields", json_array()); clang_visitChildren(cursor, visit_structure, (CXClientData)js); ret = CXChildVisit_Recurse; break; case CXCursor_EnumDecl: js = json_object(); json_object_set_new(js, "kind", json_string("enum")); json_object_set_new(js, "name", render_string(clang_getCursorSpelling(cursor))); json_object_set_new(js, "values", json_array()); clang_visitChildren(cursor, visit_enum, (CXClientData)js); break; case CXCursor_TypedefDecl: js = json_object(); json_object_set_new(js, "kind", json_string("typedef")); json_object_set_new(js, "name", render_string(clang_getCursorSpelling(cursor))); json_object_set_new(js, "type", render_type(clang_getTypedefDeclUnderlyingType(cursor))); ret = CXChildVisit_Recurse; break; case CXCursor_FieldDecl: break; case CXCursor_MacroDefinition: js = json_object(); json_object_set_new(js, "kind", json_string("macro")); { CXToken* tokens; unsigned ntokens, i; CXString name = clang_getCursorSpelling(cursor); char value_buf[1024] = ""; json_object_set_new(js, "name", render_string(clang_getCursorSpelling(cursor))); clang_tokenize(TU, clang_getCursorExtent(cursor), &tokens, &ntokens); for (i=0; i<ntokens; i++) { CXString str = clang_getTokenSpelling(TU, tokens[i]); CXTokenKind tkind = clang_getTokenKind(tokens[i]); if (i == 0 && !strcmp(clang_getCString(name), clang_getCString(str))) { // macro name } else if (i == ntokens - 1 && tkind == CXToken_Punctuation && !strcmp("#", clang_getCString(str))) { // weird clang terminator thingy } else if (tkind == CXToken_Comment) { // comment } else { if (strlen(value_buf) > 0) { strncat(value_buf, " ", sizeof(value_buf) - strlen(value_buf) - 1); } strncat(value_buf, clang_getCString(str), sizeof(value_buf) - strlen(value_buf) - 1); } clang_disposeString(str); } clang_disposeTokens(TU, tokens, ntokens); if (strlen(value_buf) > 0) { long int intval; double dblval; char* endptr_int; char* endptr_dbl; intval = strtol(value_buf, &endptr_int, 0); dblval = strtod(value_buf, &endptr_dbl); if (endptr_int[0] == 0 || (endptr_int[1] == 0 && strchr("UuLl", endptr_int[0]) != NULL)) { json_object_set_new(js, "value", json_integer(intval)); } else if (endptr_dbl[0] == 0 || (endptr_dbl[1] == 0 && strchr("fF", endptr_dbl[0]) != NULL)) { json_object_set_new(js, "value", json_real(dblval)); } else { json_object_set_new(js, "value", json_string(value_buf)); } } } break; /* case CXCursor_PreprocessingDirective: case CXCursor_MacroExpansion: js = json_object(); json_object_set_new(js, "kind", json_string("macro")); json_object_set_new(js, "name", render_string(clang_getCursorSpelling(cursor))); putstring(clang_getCursorSpelling(cursor)); putstring(clang_getCursorDisplayName(cursor)); printf("%d\n", clang_getEnumConstantDeclValue(cursor)); ret = CXChildVisit_Recurse; */ default: js = json_object(); json_object_set_new(js, "name", render_string(clang_getCursorSpelling(cursor))); json_object_set_new(js, "type", render_type(clang_getCursorType(cursor))); json_object_set_new(js, "kind", json_string("wtf")); json_object_set_new(js, "wtf", render_string(clang_getCursorKindSpelling(clang_getCursorKind(cursor)))); } if (js) { json_t* str; if (!json_object_get(program, "")) json_object_set_new(program, "", json_array()); str = render_string(clang_getCursorUSR(cursor)); if (strlen(json_string_value(str)) == 0) { json_decref(str); json_array_append_new(json_object_get(program, ""), js); } else { json_object_set_with_key_new(program, render_string(clang_getCursorUSR(cursor)), js); } } return ret; }
void ClangParser::start(const char *fileName,QStrList &filesInTranslationUnit) { static bool clangAssistedParsing = Config_getBool("CLANG_ASSISTED_PARSING"); static QStrList &includePath = Config_getList("INCLUDE_PATH"); static QStrList clangOptions = Config_getList("CLANG_OPTIONS"); if (!clangAssistedParsing) return; //printf("ClangParser::start(%s)\n",fileName); p->fileName = fileName; p->index = clang_createIndex(0, 0); p->curLine = 1; p->curToken = 0; char **argv = (char**)malloc(sizeof(char*)*(4+Doxygen::inputPaths.count()+includePath.count()+clangOptions.count())); QDictIterator<void> di(Doxygen::inputPaths); int argc=0; // add include paths for input files for (di.toFirst();di.current();++di,++argc) { QCString inc = QCString("-I")+di.currentKey(); argv[argc]=strdup(inc.data()); //printf("argv[%d]=%s\n",argc,argv[argc]); } // add external include paths for (uint i=0;i<includePath.count();i++) { QCString inc = QCString("-I")+includePath.at(i); argv[argc++]=strdup(inc.data()); } // user specified options for (uint i=0;i<clangOptions.count();i++) { argv[argc++]=strdup(clangOptions.at(i)); } // extra options argv[argc++]=strdup("-ferror-limit=0"); argv[argc++]=strdup("-x"); // Since we can be presented with a .h file that can contain C/C++ or // Objective C code and we need to configure the parser before knowing this, // we use the source file to detected the language. Detection will fail if you // pass a bunch of .h files containing ObjC code, and no sources :-( SrcLangExt lang = getLanguageFromFileName(fileName); if (lang==SrcLangExt_ObjC || p->detectedLang!=ClangParser::Private::Detected_Cpp) { QCString fn = fileName; if (p->detectedLang==ClangParser::Private::Detected_Cpp && (fn.right(4).lower()==".cpp" || fn.right(4).lower()==".cxx" || fn.right(3).lower()==".cc" || fn.right(2).lower()==".c")) { // fall back to C/C++ once we see an extension that indicates this p->detectedLang = ClangParser::Private::Detected_Cpp; } else if (fn.right(3).lower()==".mm") // switch to Objective C++ { p->detectedLang = ClangParser::Private::Detected_ObjCpp; } else if (fn.right(2).lower()==".m") // switch to Objective C { p->detectedLang = ClangParser::Private::Detected_ObjC; } } switch(p->detectedLang) { case ClangParser::Private::Detected_Cpp: argv[argc++]=strdup("c++"); break; case ClangParser::Private::Detected_ObjC: argv[argc++]=strdup("objective-c"); break; case ClangParser::Private::Detected_ObjCpp: argv[argc++]=strdup("objective-c++"); break; } // provide the input and and its dependencies as unsaved files so we can // pass the filtered versions argv[argc++]=strdup(fileName); static bool filterSourceFiles = Config_getBool("FILTER_SOURCE_FILES"); //printf("source %s ----------\n%s\n-------------\n\n", // fileName,p->source.data()); uint numUnsavedFiles = filesInTranslationUnit.count()+1; p->numFiles = numUnsavedFiles; p->sources = new QCString[numUnsavedFiles]; p->ufs = new CXUnsavedFile[numUnsavedFiles]; p->sources[0] = detab(fileToString(fileName,filterSourceFiles,TRUE)); p->ufs[0].Filename = strdup(fileName); p->ufs[0].Contents = p->sources[0].data(); p->ufs[0].Length = p->sources[0].length(); QStrListIterator it(filesInTranslationUnit); uint i=1; for (it.toFirst();it.current() && i<numUnsavedFiles;++it,i++) { p->fileMapping.insert(it.current(),new uint(i)); p->sources[i] = detab(fileToString(it.current(),filterSourceFiles,TRUE)); p->ufs[i].Filename = strdup(it.current()); p->ufs[i].Contents = p->sources[i].data(); p->ufs[i].Length = p->sources[i].length(); } // let libclang do the actual parsing p->tu = clang_parseTranslationUnit(p->index, 0, argv, argc, p->ufs, numUnsavedFiles, CXTranslationUnit_DetailedPreprocessingRecord); // free arguments for (int i=0;i<argc;++i) { free(argv[i]); } free(argv); if (p->tu) { // filter out any includes not found by the clang parser determineInputFilesInSameTu(filesInTranslationUnit); // show any warnings that the compiler produced for (uint i=0, n=clang_getNumDiagnostics(p->tu); i!=n; ++i) { CXDiagnostic diag = clang_getDiagnostic(p->tu, i); CXString string = clang_formatDiagnostic(diag, clang_defaultDiagnosticDisplayOptions()); err("%s [clang]\n",clang_getCString(string)); clang_disposeString(string); clang_disposeDiagnostic(diag); } // create a source range for the given file QFileInfo fi(fileName); CXFile f = clang_getFile(p->tu, fileName); CXSourceLocation fileBegin = clang_getLocationForOffset(p->tu, f, 0); CXSourceLocation fileEnd = clang_getLocationForOffset(p->tu, f, p->ufs[0].Length); CXSourceRange fileRange = clang_getRange(fileBegin, fileEnd); // produce a token stream for the file clang_tokenize(p->tu,fileRange,&p->tokens,&p->numTokens); // produce cursors for each token in the stream p->cursors=new CXCursor[p->numTokens]; clang_annotateTokens(p->tu,p->tokens,p->numTokens,p->cursors); } else { p->tokens = 0; p->numTokens = 0; p->cursors = 0; err("clang: Failed to parse translation unit %s\n",fileName); } }
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 ); }
void ClangParser::start(const char *fileName,QStrList &filesInTranslationUnit) { static bool clangAssistedParsing = Config_getBool(CLANG_ASSISTED_PARSING); static QStrList &includePath = Config_getList(INCLUDE_PATH); static QStrList clangOptions = Config_getList(CLANG_OPTIONS); static QCString clangCompileDatabase = Config_getList(CLANG_COMPILATION_DATABASE_PATH); if (!clangAssistedParsing) return; //printf("ClangParser::start(%s)\n",fileName); p->fileName = fileName; p->index = clang_createIndex(0, 0); p->curLine = 1; p->curToken = 0; QDictIterator<void> di(Doxygen::inputPaths); int argc=0; std::string error; // load a clang compilation database (https://clang.llvm.org/docs/JSONCompilationDatabase.html) // this only needs to be loaded once, and could be refactored to a higher level function static std::unique_ptr<clang::tooling::CompilationDatabase> db = clang::tooling::CompilationDatabase::loadFromDirectory(clangCompileDatabase.data(), error); int clang_option_len = 0; std::vector<clang::tooling::CompileCommand> command; if (strcmp(clangCompileDatabase, "0") != 0) { if (db == nullptr) { // user specified a path, but DB file was not found err("%s using clang compilation database path of: \"%s\"\n", error.c_str(), clangCompileDatabase.data()); } else { // check if the file we are parsing is in the DB command = db->getCompileCommands(fileName); if (!command.empty() ) { // it's possible to have multiple entries for the same file, so use the last entry clang_option_len = command[command.size()-1].CommandLine.size(); } } } char **argv = (char**)malloc(sizeof(char*)*(4+Doxygen::inputPaths.count()+includePath.count()+clangOptions.count()+clang_option_len)); if (!command.empty() ) { std::vector<std::string> options = command[command.size()-1].CommandLine; // copy each compiler option used from the database. Skip the first which is compiler exe. for (auto option = options.begin()+1; option != options.end(); option++) { argv[argc++] = strdup(option->c_str()); } // this extra addition to argv is accounted for as we are skipping the first entry in argv[argc++]=strdup("-w"); // finally, turn off warnings. } else { // add include paths for input files for (di.toFirst();di.current();++di,++argc) { QCString inc = QCString("-I")+di.currentKey(); argv[argc]=strdup(inc.data()); //printf("argv[%d]=%s\n",argc,argv[argc]); } // add external include paths for (uint i=0;i<includePath.count();i++) { QCString inc = QCString("-I")+includePath.at(i); argv[argc++]=strdup(inc.data()); } // user specified options for (uint i=0;i<clangOptions.count();i++) { argv[argc++]=strdup(clangOptions.at(i)); } // extra options argv[argc++]=strdup("-ferror-limit=0"); argv[argc++]=strdup("-x"); // Since we can be presented with a .h file that can contain C/C++ or // Objective C code and we need to configure the parser before knowing this, // we use the source file to detected the language. Detection will fail if you // pass a bunch of .h files containing ObjC code, and no sources :-( SrcLangExt lang = getLanguageFromFileName(fileName); if (lang==SrcLangExt_ObjC || p->detectedLang!=ClangParser::Private::Detected_Cpp) { QCString fn = fileName; if (p->detectedLang==ClangParser::Private::Detected_Cpp && (fn.right(4).lower()==".cpp" || fn.right(4).lower()==".cxx" || fn.right(3).lower()==".cc" || fn.right(2).lower()==".c")) { // fall back to C/C++ once we see an extension that indicates this p->detectedLang = ClangParser::Private::Detected_Cpp; } else if (fn.right(3).lower()==".mm") // switch to Objective C++ { p->detectedLang = ClangParser::Private::Detected_ObjCpp; } else if (fn.right(2).lower()==".m") // switch to Objective C { p->detectedLang = ClangParser::Private::Detected_ObjC; } } switch(p->detectedLang) { case ClangParser::Private::Detected_Cpp: argv[argc++]=strdup("c++"); break; case ClangParser::Private::Detected_ObjC: argv[argc++]=strdup("objective-c"); break; case ClangParser::Private::Detected_ObjCpp: argv[argc++]=strdup("objective-c++"); break; } // provide the input and and its dependencies as unsaved files so we can // pass the filtered versions argv[argc++]=strdup(fileName); } static bool filterSourceFiles = Config_getBool(FILTER_SOURCE_FILES); //printf("source %s ----------\n%s\n-------------\n\n", // fileName,p->source.data()); uint numUnsavedFiles = filesInTranslationUnit.count()+1; p->numFiles = numUnsavedFiles; p->sources = new QCString[numUnsavedFiles]; p->ufs = new CXUnsavedFile[numUnsavedFiles]; p->sources[0] = detab(fileToString(fileName,filterSourceFiles,TRUE)); p->ufs[0].Filename = strdup(fileName); p->ufs[0].Contents = p->sources[0].data(); p->ufs[0].Length = p->sources[0].length(); QStrListIterator it(filesInTranslationUnit); uint i=1; for (it.toFirst();it.current() && i<numUnsavedFiles;++it,i++) { p->fileMapping.insert(it.current(),new uint(i)); p->sources[i] = detab(fileToString(it.current(),filterSourceFiles,TRUE)); p->ufs[i].Filename = strdup(it.current()); p->ufs[i].Contents = p->sources[i].data(); p->ufs[i].Length = p->sources[i].length(); } // let libclang do the actual parsing p->tu = clang_parseTranslationUnit(p->index, 0, argv, argc, p->ufs, numUnsavedFiles, CXTranslationUnit_DetailedPreprocessingRecord); // free arguments for (int i=0;i<argc;++i) { free(argv[i]); } free(argv); if (p->tu) { // filter out any includes not found by the clang parser determineInputFilesInSameTu(filesInTranslationUnit); // show any warnings that the compiler produced for (uint i=0, n=clang_getNumDiagnostics(p->tu); i!=n; ++i) { CXDiagnostic diag = clang_getDiagnostic(p->tu, i); CXString string = clang_formatDiagnostic(diag, clang_defaultDiagnosticDisplayOptions()); err("%s [clang]\n",clang_getCString(string)); clang_disposeString(string); clang_disposeDiagnostic(diag); } // create a source range for the given file QFileInfo fi(fileName); CXFile f = clang_getFile(p->tu, fileName); CXSourceLocation fileBegin = clang_getLocationForOffset(p->tu, f, 0); CXSourceLocation fileEnd = clang_getLocationForOffset(p->tu, f, p->ufs[0].Length); CXSourceRange fileRange = clang_getRange(fileBegin, fileEnd); // produce a token stream for the file clang_tokenize(p->tu,fileRange,&p->tokens,&p->numTokens); // produce cursors for each token in the stream p->cursors=new CXCursor[p->numTokens]; clang_annotateTokens(p->tu,p->tokens,p->numTokens,p->cursors); } else { p->tokens = 0; p->numTokens = 0; p->cursors = 0; err("clang: Failed to parse translation unit %s\n",fileName); } }
void ClangParser::start(const QString &fileName, QStringList &includeFiles) { static QStringList includePath = Config::getList("include-path"); static QStringList clangFlags = Config::getList("clang-flags"); p->fileName = fileName; p->index = clang_createIndex(0, 0); p->curLine = 1; p->curToken = 0; char **argv = (char **)malloc(sizeof(char *) * (4 + Doxy_Globals::inputPaths.count() + includePath.count() + clangFlags.count())); int argc = 0; // add include paths for input files for (auto item : Doxy_Globals::inputPaths) { QString inc = "-I" + item; argv[argc] = strdup(inc.toUtf8()); ++argc; } // add external include paths for (uint i = 0; i < includePath.count(); i++) { QString inc = "-I" + includePath.at(i); argv[argc++] = strdup(inc.toUtf8()); } // user specified options for (uint i = 0; i < clangFlags.count(); i++) { argv[argc++] = strdup(clangFlags.at(i).toUtf8()); } // extra options argv[argc++] = strdup("-ferror-limit=0"); argv[argc++] = strdup("-x"); // Since we can be presented with an .h file that can contain C, C++, or Objective C, // we need to configure the parser before knowing this. // Use the source file to detected the language. Detection will fail if you // pass a bunch of .h files containing ObjC code and no source SrcLangExt lang = getLanguageFromFileName(fileName); if (lang == SrcLangExt_ObjC || p->detectedLang != ClangParser::Private::Detected_Cpp) { QString fn = fileName; if (p->detectedLang == ClangParser::Private::Detected_Cpp && (fn.right(4).toLower() == ".cpp" || fn.right(4).toLower() == ".cxx" || fn.right(3).toLower() == ".cc" || fn.right(2).toLower() == ".c")) { // fall back to C/C++ once we see an extension that indicates this p->detectedLang = ClangParser::Private::Detected_Cpp; } else if (fn.right(3).toLower() == ".mm") { // switch to Objective C++ p->detectedLang = ClangParser::Private::Detected_ObjCpp; } else if (fn.right(2).toLower() == ".m") { // switch to Objective C p->detectedLang = ClangParser::Private::Detected_ObjC; } } switch (p->detectedLang) { case ClangParser::Private::Detected_Cpp: argv[argc++] = strdup("c++"); break; case ClangParser::Private::Detected_ObjC: argv[argc++] = strdup("objective-c"); break; case ClangParser::Private::Detected_ObjCpp: argv[argc++] = strdup("objective-c++"); break; } // provide the input and and its dependencies as unsaved files so we can pass the filtered versions static bool filterSourceFiles = Config::getBool("filter-source-files"); argv[argc++] = strdup(fileName.toUtf8()); uint numUnsavedFiles = includeFiles.count() + 1; p->numFiles = numUnsavedFiles; p->sources = new QByteArray[numUnsavedFiles]; p->ufs = new CXUnsavedFile[numUnsavedFiles]; p->sources[0] = detab(fileToString(fileName, filterSourceFiles, true)).toUtf8(); p->ufs[0].Filename = strdup(fileName.toUtf8()); p->ufs[0].Contents = p->sources[0].constData(); p->ufs[0].Length = p->sources[0].length(); // uint i = 1; for (auto item : includeFiles) { p->fileMapping.insert(item, i); p->sources[i] = detab(fileToString(item, filterSourceFiles, true)).toUtf8(); p->ufs[i].Filename = strdup(item.toUtf8()); p->ufs[i].Contents = p->sources[i].constData(); p->ufs[i].Length = p->sources[i].length(); i++; } // let libclang do the actual parsing CXErrorCode errorCode = clang_parseTranslationUnit2(p->index, 0, argv, argc, 0, 0, CXTranslationUnit_DetailedPreprocessingRecord, &(p->tu) ); // free arguments for (int i = 0; i < argc; ++i) { free(argv[i]); } free(argv); if (p->tu) { // filter out any includes not found by the clang parser determineInputFiles(includeFiles); // show any warnings the compiler produced uint n = clang_getNumDiagnostics(p->tu); for (uint i = 0; i != n; ++i) { CXDiagnostic diag = clang_getDiagnostic(p->tu, i); CXString string = clang_formatDiagnostic(diag, clang_defaultDiagnosticDisplayOptions()); err("Clang parser warning -- %s\n", clang_getCString(string)); clang_disposeString(string); clang_disposeDiagnostic(diag); } // create a source range for the given file QFileInfo fi(fileName); CXFile f = clang_getFile(p->tu, fileName.toUtf8()); CXSourceLocation fileBegin = clang_getLocationForOffset(p->tu, f, 0); CXSourceLocation fileEnd = clang_getLocationForOffset(p->tu, f, p->ufs[0].Length); CXSourceRange fileRange = clang_getRange(fileBegin, fileEnd); // produce a token stream for the file clang_tokenize(p->tu, fileRange, &p->tokens, &p->numTokens); // produce cursors for each token in the stream p->cursors = new CXCursor[p->numTokens]; clang_annotateTokens(p->tu, p->tokens, p->numTokens, p->cursors); } else { p->tokens = 0; p->numTokens = 0; p->cursors = 0; err("Clang failed to parse translation unit -- %s\n", qPrintable(fileName)); } }