Example #1
0
 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);
 }
Example #2
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
      ;
}
Example #4
0
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);
}
Example #5
0
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);
        }
    }
Example #6
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;
}
Example #7
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);
    }
}
Example #8
0
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);
}
Example #9
0
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));
}