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); } } }
highlight_group(clang::translation_unit const &trans_unit, clang::token_pack &tokens) { auto &tu(trans_unit.impl); std::vector<CXCursor> cursors(tokens.size()); clang_annotateTokens(tu, tokens.begin(), tokens.size(), cursors.data()); auto cursor(cursors.cbegin()); for(auto token(tokens.cbegin()); token != tokens.cend(); ++token, ++cursor) { CXTokenKind const kind{ clang_getTokenKind(*token) }; clang::string const spell{ clang_getTokenSpelling(tu, *token) }; auto const loc(clang_getTokenLocation(tu, *token)); CXFile file{}; unsigned line{}, column{}, offset{}; clang_getFileLocation(loc, &file, &line, &column, &offset); auto const cur(*cursor); auto const cursor_kind(cur.kind); auto const cursor_type(clang_getCursorType(cur).kind); auto const mapped(clang::token::map_token_kind(kind, cursor_kind, cursor_type)); if(mapped.size()) { //std::cout << spell.c_str() << " : " << mapped << std::endl; emplace_back(mapped, line, column, spell.c_str()); } else { /* std::cout << "unmapped: " << spell.c_str() << std::endl; */ } } }
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);*/ } }
HighlightingInformations::HighlightingInformations(CXTranslationUnit cxTranslationUnit, CXToken *tokens, uint tokensCount) : cxTranslationUnit(cxTranslationUnit), cxToken(tokens), cxTokenCount(tokensCount) { cxCursor.resize(tokensCount); clang_annotateTokens(cxTranslationUnit, cxToken, cxTokenCount, cxCursor.data()); }
void token_set::annotate() { std::vector<CXCursor> curs; curs.resize(size); clang_annotateTokens(tu, tokens, size, curs.data()); cursors.clear(); for(auto cur : curs) cursors.push_back({ cur }); }
SourceRangeContainer FollowSymbol::followSymbol(CXTranslationUnit tu, const Cursor &fullCursor, uint line, uint column) { std::unique_ptr<Tokens> tokens(new Tokens(fullCursor)); if (!tokens->tokenCount) tokens.reset(new Tokens(tu)); if (!tokens->tokenCount) return SourceRangeContainer(); QVector<CXCursor> cursors(static_cast<int>(tokens->tokenCount)); clang_annotateTokens(tu, tokens->data, tokens->tokenCount, cursors.data()); int tokenIndex = getTokenIndex(tu, *tokens, line, column); QTC_ASSERT(tokenIndex >= 0, return SourceRangeContainer()); const Utf8String tokenSpelling = ClangString( clang_getTokenSpelling(tu, tokens->data[tokenIndex])); if (tokenSpelling.isEmpty()) return SourceRangeContainer(); Cursor cursor{cursors[tokenIndex]}; if (cursor.kind() == CXCursor_InclusionDirective) { CXFile file = clang_getIncludedFile(cursors[tokenIndex]); const ClangString filename(clang_getFileName(file)); const SourceLocation loc(tu, filename, 1, 1); return SourceRange(loc, loc); } // For definitions we can always find a declaration in current TU if (cursor.isDefinition()) return extractMatchingTokenRange(cursor.canonical(), tokenSpelling); if (!cursor.isDeclaration()) { // This is the symbol usage // We want to return definition cursor = cursor.referenced(); if (cursor.isNull() || !cursor.isDefinition()) { // We can't find definition in this TU return SourceRangeContainer(); } return extractMatchingTokenRange(cursor, tokenSpelling); } cursor = cursor.definition(); // If we are able to find a definition in current TU if (!cursor.isNull()) return extractMatchingTokenRange(cursor, tokenSpelling); return SourceRangeContainer(); }
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 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); } }
int perform_token_annotation(int argc, const char **argv) { const char *input = argv[1]; char *filename = 0; unsigned line, second_line; unsigned column, second_column; CXIndex CIdx; CXTranslationUnit TU = 0; int errorCode; struct CXUnsavedFile *unsaved_files = 0; int num_unsaved_files = 0; CXToken *tokens; unsigned num_tokens; CXSourceRange range; CXSourceLocation startLoc, endLoc; CXFile file = 0; CXCursor *cursors = 0; unsigned i; input += strlen("-test-annotate-tokens="); if ((errorCode = parse_file_line_column(input, &filename, &line, &column, &second_line, &second_column))) return errorCode; if (parse_remapped_files(argc, argv, 2, &unsaved_files, &num_unsaved_files)) return -1; CIdx = clang_createIndex(0, 1); TU = clang_createTranslationUnitFromSourceFile(CIdx, argv[argc - 1], argc - num_unsaved_files - 3, argv + num_unsaved_files + 2, num_unsaved_files, unsaved_files); if (!TU) { fprintf(stderr, "unable to parse input\n"); clang_disposeIndex(CIdx); free(filename); free_remapped_files(unsaved_files, num_unsaved_files); return -1; } errorCode = 0; file = clang_getFile(TU, filename); if (!file) { fprintf(stderr, "file %s is not in this translation unit\n", filename); errorCode = -1; goto teardown; } startLoc = clang_getLocation(TU, file, line, column); if (clang_equalLocations(clang_getNullLocation(), startLoc)) { fprintf(stderr, "invalid source location %s:%d:%d\n", filename, line, column); errorCode = -1; goto teardown; } endLoc = clang_getLocation(TU, file, second_line, second_column); if (clang_equalLocations(clang_getNullLocation(), endLoc)) { fprintf(stderr, "invalid source location %s:%d:%d\n", filename, second_line, second_column); errorCode = -1; goto teardown; } range = clang_getRange(startLoc, endLoc); clang_tokenize(TU, range, &tokens, &num_tokens); cursors = (CXCursor *)malloc(num_tokens * sizeof(CXCursor)); clang_annotateTokens(TU, tokens, num_tokens, cursors); for (i = 0; i != num_tokens; ++i) { const char *kind = "<unknown>"; CXString spelling = clang_getTokenSpelling(TU, tokens[i]); CXSourceRange extent = clang_getTokenExtent(TU, tokens[i]); unsigned start_line, start_column, end_line, end_column; switch (clang_getTokenKind(tokens[i])) { case CXToken_Punctuation: kind = "Punctuation"; break; case CXToken_Keyword: kind = "Keyword"; break; case CXToken_Identifier: kind = "Identifier"; break; case CXToken_Literal: kind = "Literal"; break; case CXToken_Comment: kind = "Comment"; break; } clang_getInstantiationLocation(clang_getRangeStart(extent), 0, &start_line, &start_column, 0); clang_getInstantiationLocation(clang_getRangeEnd(extent), 0, &end_line, &end_column, 0); printf("%s: \"%s\" ", kind, clang_getCString(spelling)); PrintExtent(stdout, start_line, start_column, end_line, end_column); if (!clang_isInvalid(cursors[i].kind)) { printf(" "); PrintCursor(cursors[i]); } printf("\n"); } free(cursors); teardown: PrintDiagnostics(TU); clang_disposeTranslationUnit(TU); clang_disposeIndex(CIdx); free(filename); free_remapped_files(unsaved_files, num_unsaved_files); return errorCode; }
void 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);*/ } }
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)); } }