void SetUp() { llvm::SmallString<256> Dir; ASSERT_FALSE(llvm::sys::fs::createUniqueDirectory("libclang-test", Dir)); TestDir = Dir.str(); TUFlags = CXTranslationUnit_DetailedPreprocessingRecord | clang_defaultEditingTranslationUnitOptions(); Index = clang_createIndex(0, 0); }
int main(int argc, char *argv[]) { auto index = clang_createIndex(0, 0); auto options = clang_defaultEditingTranslationUnitOptions(); char const *args[] = { "-x", "c++", "-std=c++11" }; auto arg_count = sizeof( args ) / sizeof( *args ); filename = argv[1]; CXUnsavedFile *unsaved_files = NULL; auto unsaved_file_count = 0; tu = clang_parseTranslationUnit(index, filename.c_str(), args, arg_count, unsaved_files, unsaved_file_count, options ); if ( !tu ) { std::cout << "Translation Unit Parse Failed!\n"; return -1; } std::stringstream ss( argv[2] ); int line, col; ss >> line; ss.get(); ss >> col; std::cout << "Hello " << line << ":" << col << "\n"; auto file = clang_getFile( tu, filename.c_str() ); auto location = clang_getLocation( tu, file, line, col ); clang_visitChildren( clang_getTranslationUnitCursor( tu ), visitor, reinterpret_cast<CXClientData>(0) ); auto cursor = clang_getCursor( tu, location ); auto refcursor = clang_getCursorReferenced( cursor ); auto rrefcursor = clang_getCursorReferenced( refcursor ); auto arf = clang_getTypeKindSpelling( clang_getCursorType( cursor ).kind ); auto foo = clang_getCanonicalCursor( cursor ); auto semparent = clang_getCursorSemanticParent( cursor ); auto lexparent = clang_getCursorLexicalParent( cursor ); std::cout << cursor << "\n"; std::cout << refcursor << "\n"; std::cout << rrefcursor << "\n"; std::cout << clang_getCString(arf) << "\n"; std::cout << foo << "\n"; std::cout << "Parent: " << semparent << "\n"; std::cout << "LexParent: " << lexparent << "\n"; //clang_visitChildren( semparent, visitor, reinterpret_cast<CXClientData>(0) ); clang_disposeString( arf ); return 0; }
unsigned TranslationUnit::defaultEditingParseOptions() { return clang_defaultEditingTranslationUnitOptions() | CXTranslationUnit_Incomplete | CXTranslationUnit_PrecompiledPreamble | CXTranslationUnit_CacheCompletionResults #if CLANG_VERSION >= 30200 | CXTranslationUnit_IncludeBriefCommentsInCodeCompletion #endif // CLANG_VERSION >= 30200 ; }
static inline CXTranslationUnit CLANG_PARSE(const CXIndex &idx, const char *filename, char **args, int args_size, CXUnsavedFile *unsaved_file) { int unsaved_file_num = 0; if (unsaved_file) unsaved_file_num = 1; return clang_parseTranslationUnit(idx, filename, args, args_size, unsaved_file, unsaved_file_num, clang_defaultEditingTranslationUnitOptions()| CXTranslationUnit_PrecompiledPreamble| CXTranslationUnit_CXXPrecompiledPreamble| CXTranslationUnit_CacheCompletionResults); }
void Tokenizer::parse(OovStringRef fileName, OovStringRef buffer, size_t bufLen, char const * const clang_args[], size_t num_clang_args) { CLangAutoLock lock(mCLangLock, __LINE__, this); try { if(!mSourceFile) { // The clang_defaultCodeCompleteOptions() options are not for the parse // function, they are for the clang_codeCompleteAt func. unsigned options = clang_defaultEditingTranslationUnitOptions(); // This is required to allow go to definition to work with #include. options |= CXTranslationUnit_DetailedPreprocessingRecord; mSourceFilename = fileName; mContextIndex = clang_createIndex(1, 1); mTransUnit = clang_parseTranslationUnit(mContextIndex, fileName, clang_args, static_cast<int>(num_clang_args), 0, 0, options); } else { static CXUnsavedFile file; file.Filename = mSourceFilename.c_str(); file.Contents = buffer; file.Length = bufLen; unsigned options = clang_defaultReparseOptions(mTransUnit); int stat = clang_reparseTranslationUnit(mTransUnit, 1, &file, options); if(stat != 0) { clang_disposeTranslationUnit(mTransUnit); mTransUnit = nullptr; } } mSourceFile = clang_getFile(mTransUnit, fileName); } catch(...) { DUMP_PARSE_INT("Tokenizer::parse - CRASHED", 0); } }
int main(int argc, char **argv) { if (argc < 2) return 1; CXIndex index = clang_createIndex(1, 1); const char * const *args = 0; if (argc > 2) args = (const char *const *)&argv[2]; CXTranslationUnit unit = clang_parseTranslationUnit(index, argv[1], args, argc - 2, 0, 0, clang_defaultEditingTranslationUnitOptions()); if (unit) { int indent = 0; clang_visitChildren(clang_getTranslationUnitCursor(unit), visit, &indent); const unsigned int diagnosticCount = clang_getNumDiagnostics(unit); unsigned int i; for (i=0; i<diagnosticCount; ++i) { CXDiagnostic diagnostic = clang_getDiagnostic(unit, i); const unsigned int diagnosticOptions = (CXDiagnostic_DisplaySourceLocation| CXDiagnostic_DisplayColumn| CXDiagnostic_DisplaySourceRanges| CXDiagnostic_DisplayOption| CXDiagnostic_DisplayCategoryId| CXDiagnostic_DisplayCategoryName); CXString diagnosticText = clang_formatDiagnostic(diagnostic, diagnosticOptions); const char *cstr = clang_getCString(diagnosticText); if (cstr) printf("%s\n", cstr); clang_disposeString(diagnosticText); } clang_disposeTranslationUnit(unit); } clang_disposeIndex(index); return 0; }
void CompletionThread::process(Request *request) { // if (!request->unsaved.isEmpty()) { // int line = request->location.line(); // int pos = 0; // while (line > 1) { // int p = request->unsaved.indexOf('\n', pos); // if (p == -1) { // pos = -1; // break; // } // pos = p + 1; // --line; // } // if (pos != -1) { // int end = request->unsaved.indexOf('\n', pos); // if (end == -1) // end = request->unsaved.size(); // error("Completing at %s:%d:%d line: [%s]\n", // request->location.path().constData(), // request->location.line(), // request->location.column(), // request->unsaved.mid(pos, end - pos).constData()); // } // } StopWatch sw; int parseTime = 0; int reparseTime = 0; int completeTime = 0; int processTime = 0; SourceFile *&cache = mCacheMap[request->source.fileId]; if (cache && cache->source != request->source) { delete cache; cache = 0; } if (!cache) { cache = new SourceFile; mCacheList.append(cache); while (mCacheMap.size() > mCacheSize) { SourceFile *c = mCacheList.removeFirst(); mCacheMap.remove(c->source.fileId); delete c; } } else { mCacheList.moveToEnd(cache); } const bool sendDebug = testLog(LogLevel::Debug); if (cache->translationUnit && cache->source != request->source) { clang_disposeTranslationUnit(cache->translationUnit); cache->translationUnit = 0; cache->source = request->source; } else if (!cache->translationUnit) { cache->source = request->source; } const Path sourceFile = request->source.sourceFile(); CXUnsavedFile unsaved = { sourceFile.constData(), request->unsaved.constData(), static_cast<unsigned long>(request->unsaved.size()) }; size_t hash = 0; uint64_t lastModified = 0; if (request->unsaved.size()) { std::hash<String> h; hash = h(request->unsaved); } else { lastModified = sourceFile.lastModifiedMs(); } const auto &options = Server::instance()->options(); if (!cache->translationUnit) { cache->completionsMap.clear(); cache->completionsList.deleteAll(); sw.restart(); Flags<CXTranslationUnit_Flags> flags = static_cast<CXTranslationUnit_Flags>(clang_defaultEditingTranslationUnitOptions()); flags |= CXTranslationUnit_PrecompiledPreamble; flags |= CXTranslationUnit_CacheCompletionResults; flags |= CXTranslationUnit_SkipFunctionBodies; for (const auto &inc : options.includePaths) { request->source.includePaths << inc; } request->source.defines << options.defines; String clangLine; RTags::parseTranslationUnit(sourceFile, request->source.toCommandLine(Source::Default|Source::ExcludeDefaultArguments), cache->translationUnit, mIndex, &unsaved, request->unsaved.size() ? 1 : 0, flags, &clangLine); // error() << "PARSING" << clangLine; parseTime = sw.restart(); if (cache->translationUnit) { RTags::reparseTranslationUnit(cache->translationUnit, &unsaved, request->unsaved.size() ? 1 : 0); } reparseTime = sw.elapsed(); if (!cache->translationUnit) return; cache->unsavedHash = hash; cache->lastModified = lastModified; } else if (cache->unsavedHash != hash || cache->lastModified != lastModified) { cache->completionsMap.clear(); cache->completionsList.deleteAll(); cache->unsavedHash = hash; cache->lastModified = lastModified; } else if (!(request->flags & Refresh)) { const auto it = cache->completionsMap.find(request->location); if (it != cache->completionsMap.end()) { cache->completionsList.moveToEnd(it->second); error("Found completions (%d) in cache %s:%d:%d", it->second->candidates.size(), sourceFile.constData(), request->location.line(), request->location.column()); printCompletions(it->second->candidates, request); return; } } sw.restart(); const unsigned int completionFlags = (CXCodeComplete_IncludeMacros|CXCodeComplete_IncludeCodePatterns); CXCodeCompleteResults *results = clang_codeCompleteAt(cache->translationUnit, sourceFile.constData(), request->location.line(), request->location.column(), &unsaved, unsaved.Length ? 1 : 0, completionFlags); completeTime = sw.restart(); if (results) { std::vector<Completions::Candidate> nodes; nodes.reserve(results->NumResults); int nodeCount = 0; Map<Token, int> tokens; if (!request->unsaved.isEmpty()) { tokens = Token::tokenize(request->unsaved.constData(), request->unsaved.size()); // for (Map<Token, int>::const_iterator it = tokens.begin(); it != tokens.end(); ++it) { // error() << String(it->first.data, it->first.length) << it->second; // } } for (unsigned int i = 0; i < results->NumResults; ++i) { const CXCursorKind kind = results->Results[i].CursorKind; if (!(options.options & Server::CompletionsNoFilter) && kind == CXCursor_Destructor) continue; const CXCompletionString &string = results->Results[i].CompletionString; const CXAvailabilityKind availabilityKind = clang_getCompletionAvailability(string); if (!(options.options & Server::CompletionsNoFilter) && availabilityKind != CXAvailability_Available) continue; const int priority = clang_getCompletionPriority(string); if (size_t(nodeCount) == nodes.size()) nodes.emplace_back(); Completions::Candidate &node = nodes.back(); node.cursorKind = kind; node.priority = priority; node.signature.reserve(256); const int chunkCount = clang_getNumCompletionChunks(string); bool ok = true; for (int j=0; j<chunkCount; ++j) { const CXCompletionChunkKind chunkKind = clang_getCompletionChunkKind(string, j); if (chunkKind == CXCompletionChunk_TypedText) { node.completion = RTags::eatString(clang_getCompletionChunkText(string, j)); if (node.completion.size() > 8 && node.completion.startsWith("operator") && !isPartOfSymbol(node.completion.at(8))) { ok = false; break; } node.signature.append(node.completion); } else { node.signature.append(RTags::eatString(clang_getCompletionChunkText(string, j))); if (chunkKind == CXCompletionChunk_ResultType) node.signature.append(' '); } } if (ok) { int ws = node.completion.size() - 1; while (ws >= 0 && isspace(node.completion.at(ws))) --ws; if (ws >= 0) { node.completion.truncate(ws + 1); node.signature.replace("\n", ""); node.distance = tokens.value(Token(node.completion.constData(), node.completion.size()), -1); if (sendDebug) debug() << node.signature << node.priority << kind << node.distance << clang_getCompletionAvailability(string); ++nodeCount; continue; } } node.completion.clear(); node.signature.clear(); } if (nodeCount) { // Sort pointers instead of shuffling candidates around std::vector<Completions::Candidate*> nodesPtr; nodesPtr.reserve(nodeCount); for (auto& n : nodes) nodesPtr.push_back(&n); std::sort(nodesPtr.begin(), nodesPtr.end(), compareCompletionCandidates); Completions *&c = cache->completionsMap[request->location]; if (c) { cache->completionsList.moveToEnd(c); } else { enum { MaxCompletionCache = 10 }; // ### configurable? c = new Completions(request->location); cache->completionsList.append(c); while (cache->completionsMap.size() > MaxCompletionCache) { Completions *cc = cache->completionsList.takeFirst(); cache->completionsMap.remove(cc->location); delete cc; } } c->candidates.resize(nodeCount); for (int i=0; i<nodeCount; ++i) c->candidates[i] = std::move(*nodesPtr[i]); printCompletions(c->candidates, request); processTime = sw.elapsed(); warning("Processed %s, parse %d/%d, complete %d, process %d => %d completions (unsaved %d)", sourceFile.constData(), parseTime, reparseTime, completeTime, processTime, nodeCount, request->unsaved.size()); } else { printCompletions(List<Completions::Candidate>(), request); error() << "No completion results available" << request->location << results->NumResults; } clang_disposeCodeCompleteResults(results); } }
static void process_ac(int sock) { tpl_node *tn; struct msg_ac msg; wordexp_t flags; tn = msg_ac_node(&msg); tpl_load(tn, TPL_FD, sock); tpl_unpack(tn, 0); tpl_free(tn); struct CXUnsavedFile unsaved = { msg.filename, msg.buffer.addr, msg.buffer.sz }; change_dir(msg.filename); try_load_dotccode(&flags); str_t *partial = extract_partial(&msg); if (partial) msg.col -= partial->len; if (needs_reparsing(&flags, msg.filename)) { if (clang_tu) clang_disposeTranslationUnit(clang_tu); clang_tu = clang_parseTranslationUnit(clang_index, msg.filename, (char const * const *)flags.we_wordv, flags.we_wordc, &unsaved, 1, clang_defaultEditingTranslationUnitOptions()); if (last_filename) free(last_filename); if (last_wordexp.we_wordv) wordfree(&last_wordexp); last_filename = strdup(msg.filename); last_wordexp = flags; } // diag /* for (int i = 0, n = clang_getNumDiagnostics(clang_tu); i != n; ++i) { CXDiagnostic diag = clang_getDiagnostic(clang_tu, i); CXString string = clang_formatDiagnostic(diag, clang_defaultDiagnosticDisplayOptions()); fprintf(stderr, "%s\n", clang_getCString(string)); clang_disposeString(string); clang_disposeDiagnostic(diag); } */ CXCodeCompleteResults *results; results = clang_codeCompleteAt(clang_tu, msg.filename, msg.line, msg.col, &unsaved, 1, CXCodeComplete_IncludeMacros); free_msg_ac(&msg); // diag /* for (int i = 0, n = clang_codeCompleteGetNumDiagnostics(results); i != n; ++i) { CXDiagnostic diag = clang_codeCompleteGetDiagnostic(results, i); CXString string = clang_formatDiagnostic(diag, clang_defaultDiagnosticDisplayOptions()); fprintf(stderr, "%s\n", clang_getCString(string)); clang_disposeString(string); clang_disposeDiagnostic(diag); } */ struct msg_ac_response msg_r = { (partial) ? partial->len : 0, 0, 0 }; if (results) { struct make_ac_ctx ctx; str_t *fmt; init_make_ac_ctx(&ctx); msg_r.proposals_n = filter_out_cc_results(results->Results, results->NumResults, partial, &fmt); sort_cc_results(results->Results, msg_r.proposals_n); if (msg_r.proposals_n > MAX_AC_RESULTS) msg_r.proposals_n = MAX_AC_RESULTS; msg_r.proposals = malloc(sizeof(struct ac_proposal) * msg_r.proposals_n); int cur = 0; for (int i = 0; i < msg_r.proposals_n; ++i) { int added; added = make_ac_proposal(&ctx, &msg_r.proposals[cur], &results->Results[i], fmt); if (added) cur++; } msg_r.proposals_n = cur; free_make_ac_ctx(&ctx); str_free(fmt); } if (partial) str_free(partial); clang_disposeCodeCompleteResults(results); msg_ac_response_send(&msg_r, sock); free_msg_ac_response(&msg_r); }
CXTranslationUnit TUManager::parse(const std::string & filename, const std::vector<std::string> & flags) { CXTranslationUnit tu = translationUnits_[filename]; if (! tu) { // FIXME: needed ? // Note: the -cc1 argument indicates the compiler front-end, and // not the driver, should be run. The compiler front-end has // several additional Clang specific features which are not // exposed through the GCC compatible driver interface. // from: http://clang.llvm.org/get_started.html // const_cast<std::vector<std::string> &>(flags).push_back("-cc1"); std::size_t nbArgs = flags.size(); const char **argv = 0; if (nbArgs > 0) { argv = new const char *[nbArgs + 1]; argv[nbArgs] = 0; for (std::size_t i = 0; i < nbArgs; ++i) argv[i] = flags[i].c_str(); } tu = clang_parseTranslationUnit(index_, filename.c_str(), argv, nbArgs, 0, 0, clang_defaultEditingTranslationUnitOptions() | CXTranslationUnit_PrecompiledPreamble | CXTranslationUnit_CacheCompletionResults); delete [] argv; translationUnits_[filename] = tu; } if (! tu) { std::clog << "parsing \"" << filename << "\" failed." << std::endl; return 0; } // NOTE: Even at the first time the translation unit is reparsed, // because without this the completion is erroneous. // From the clang mailing list: // From: Douglas Gregor <*****@*****.**> // Subject: Re: Clang indexing library performance // Newsgroups: gmane.comp.compilers.clang.devel // ... // You want to use the "default editing options" when parsing the // translation unit // clang_defaultEditingTranslationUnitOptions() // and then reparse at least once. That will enable the various // code-completion optimizations that should bring this time down // significantly. if (clang_reparseTranslationUnit(tu, 0, 0, clang_defaultReparseOptions(tu))) { // a 'fatal' error occur (even a diagnostic is impossible) clang_disposeTranslationUnit(tu); translationUnits_[filename] = 0; } return tu; }
static void ide_clang_service_get_translation_unit_worker (EggTaskCache *cache, gconstpointer key, GTask *task, gpointer user_data) { g_autoptr(GTask) real_task = NULL; IdeClangService *self = user_data; IdeUnsavedFiles *unsaved_files; IdeBuildSystem *build_system; ParseRequest *request; IdeContext *context; const gchar *path; IdeFile *file = (IdeFile *)key; GFile *gfile; g_assert (IDE_IS_CLANG_SERVICE (self)); g_assert (IDE_IS_CLANG_SERVICE (self)); g_assert (IDE_IS_FILE (key)); g_assert (IDE_IS_FILE (file)); g_assert (G_IS_TASK (task)); context = ide_object_get_context (IDE_OBJECT (self)); unsaved_files = ide_context_get_unsaved_files (context); build_system = ide_context_get_build_system (context); gfile = ide_file_get_file (file); if (!gfile || !(path = g_file_get_path (gfile))) { g_task_return_new_error (task, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED, _("File must be saved locally to parse.")); return; } request = g_slice_new0 (ParseRequest); request->file = g_object_ref (file); request->index = self->index; request->source_filename = g_strdup (path); request->command_line_args = NULL; request->unsaved_files = ide_unsaved_files_to_array (unsaved_files); request->sequence = ide_unsaved_files_get_sequence (unsaved_files); /* * NOTE: * * I'm torn on this one. It requires a bunch of extra memory, but without it * we don't get information about macros. And since we need that to provide * quality highlighting, I'm going try try enabling it for now and see how * things go. */ request->options = (clang_defaultEditingTranslationUnitOptions () | CXTranslationUnit_DetailedPreprocessingRecord); real_task = g_task_new (self, g_task_get_cancellable (task), ide_clang_service_unit_completed_cb, g_object_ref (task)); g_task_set_task_data (real_task, request, parse_request_free); /* * Request the build flags necessary to build this module from the build system. */ IDE_TRACE_MSG ("Requesting build of translation unit"); ide_build_system_get_build_flags_async (build_system, file, g_task_get_cancellable (task), ide_clang_service__get_build_flags_cb, g_object_ref (real_task)); }