Exemple #1
0
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);
}
Exemple #3
0
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;
    }
Exemple #4
0
    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);*/
      }
    }
Exemple #7
0
token_set translation_unit::tokenize(source_range range)
{
    CXToken *tokens;
    unsigned size;
    clang_tokenize(tu, range.range, &tokens, &size);
    
    return { tu, tokens, size };
}
Exemple #8
0
 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);
}
Exemple #10
0
/// @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);
    }
Exemple #11
0
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;
    }
Exemple #12
0
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);
    }
Exemple #13
0
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);*/
      }
    }
Exemple #15
0
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;
}
Exemple #16
0
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;
}
Exemple #17
0
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);
  }
}
Exemple #18
0
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 );
}
Exemple #19
0
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));
   }
}