Beispiel #1
0
int main(int argc, char *argv[]) 
{
  CXIndex Index = clang_createIndex(0, 0);
  
  CXTranslationUnit TU;
  
  TU = clang_parseTranslationUnit(Index, 0, 
                                  (const char**)argv, argc, 
                                  0, 0, CXTranslationUnit_None);
  
        
  CXCodeCompleteResults *results = clang_codeCompleteAt(TU, argv[1], 20, 7, NULL, 0, clang_defaultCodeCompleteOptions());
      
     
  unsigned i;
  for(i =0; i<results->NumResults; i++)
    {
      printf("%s",results->Results[i].CompletionString);
    }
   
    
  //            clang_disposeString(String);
  
  clang_disposeCodeCompleteResults(results);
  clang_disposeTranslationUnit(TU);
  clang_disposeIndex(Index);
 
  return 0;
}
CXCodeCompleteResults* completion_codeCompleteAt(completion_Session *session, int line, int column)
{
    struct CXUnsavedFile unsaved_files = __get_CXUnsavedFile(session);
    
    return clang_codeCompleteAt(session->cx_tu,
                                session->src_filename,
                                line,
                                column,
                                &unsaved_files,
                                1,
                                session->CompleteAtOptions);
}
Beispiel #3
0
ClangCodeCompleteResults CodeCompleter::complete(uint line,
                                                 uint column,
                                                 CXUnsavedFile *unsavedFiles,
                                                 unsigned unsavedFileCount)
{
    return clang_codeCompleteAt(translationUnit.cxTranslationUnitWithoutReparsing(),
                                translationUnit.filePath().constData(),
                                line,
                                column,
                                unsavedFiles,
                                unsavedFileCount,
                                defaultOptions());
}
Beispiel #4
0
ClangCodeCompleteResults CodeCompleter::completeHelper(uint line, uint column)
{
    const Utf8String nativeFilePath = FilePath::toNativeSeparators(translationUnit.filePath());
    UnsavedFilesShallowArguments unsaved = unsavedFiles.shallowArguments();

    return clang_codeCompleteAt(translationUnit.cxTranslationUnit(),
                                nativeFilePath.constData(),
                                line,
                                column,
                                unsaved.data(),
                                unsaved.count(),
                                defaultOptions());
}
QVector<CodeCompletion> CodeCompleter::complete(uint line, uint column)
{
    ClangCodeCompleteResults completeResults(clang_codeCompleteAt(translationUnit.cxTranslationUnit(),
                                                                  translationUnit.filePath().constData(),
                                                                  line,
                                                                  column,
                                                                  translationUnit.cxUnsavedFiles(),
                                                                  translationUnit.unsavedFilesCount(),
                                                                  CXCodeComplete_IncludeMacros | CXCodeComplete_IncludeCodePatterns));

    CodeCompletionsExtractor extractor(completeResults.data());

    return extractor.extractAll();
}
Beispiel #6
0
ClangCodeCompleteResults CodeCompleter::complete(uint line,
        uint column,
        CXUnsavedFile *unsavedFiles,
        unsigned unsavedFileCount)
{
    const auto options = CXCodeComplete_IncludeMacros | CXCodeComplete_IncludeCodePatterns;

    return clang_codeCompleteAt(translationUnit.cxTranslationUnitWithoutReparsing(),
                                translationUnit.filePath().constData(),
                                line,
                                column,
                                unsavedFiles,
                                unsavedFileCount,
                                options);
}
Beispiel #7
0
struct cc_result* 
cc_result_new(CXTranslationUnit tu, struct cc_trie* tp, struct cc_resultcache* cache, const char* filename, unsigned int line, unsigned int col, struct CXUnsavedFile* unsaved_files, unsigned int num_unsaved_files) {
  unsigned int i;
  CXCodeCompleteResults* result = clang_codeCompleteAt(tu, filename, line, col, unsaved_files, num_unsaved_files, _COMPLETE_OPTIONS);
  struct cc_result* rp = (struct cc_result*)malloc(sizeof(*rp));

  cc_trie_clear(tp);
  rp->result = result;
  rp->ref_cache = cache;
  rp->ref_tp = tp;

  for(i=0; i<result->NumResults; i++) {
    _insert(rp, i);
  }
  return rp;
}
Beispiel #8
0
OovStringVec Tokenizer::codeComplete(size_t offset)
    {
    CLangAutoLock lock(mCLangLock, __LINE__, this);
    OovStringVec strs;
    unsigned options = 0;
// This gets more than we want.
//    unsigned options = clang_defaultCodeCompleteOptions();
    unsigned int line;
    unsigned int column;
    getLineColumn(offset, line, column);
    CXCodeCompleteResults *results = clang_codeCompleteAt(mTransUnit,
            mSourceFilename.getStr(), line, column,
            nullptr, 0, options);
    if(results)
        {
        clang_sortCodeCompletionResults(&results->Results[0], results->NumResults);
        for(size_t ri=0; ri<results->NumResults /*&& ri < 50*/; ri++)
            {
            OovString str;
            CXCompletionString compStr = results->Results[ri].CompletionString;
            size_t numChunks = clang_getNumCompletionChunks(compStr);
            for(size_t ci=0; ci<numChunks && ci < 30; ci++)
                {
                CXCompletionChunkKind chunkKind = clang_getCompletionChunkKind(compStr, ci);
                // We will discard return values from functions, so the first
                // chunk returned will be the identifier or function name.  Function
                // arguments will be returned after a space, so they can be
                // discarded easily.
                if(chunkKind == CXCompletionChunk_TypedText || str.length())
                    {
                    std::string chunkStr = getDisposedString(clang_getCompletionChunkText(compStr, ci));
                    if(str.length() != 0)
                    str += ' ';
                    str += chunkStr;
                    }
                }
            strs.push_back(str);
            }
        clang_disposeCodeCompleteResults(results);
        }
    return strs;
    }
std::vector< CompletionData > TranslationUnit::CandidatesForLocation(
  const std::string &filename,
  int line,
  int column,
  const std::vector< UnsavedFile > &unsaved_files ) {
  unique_lock< mutex > lock( clang_access_mutex_ );

  if ( !clang_translation_unit_ ) {
    return std::vector< CompletionData >();
  }

  std::vector< CXUnsavedFile > cxunsaved_files =
    ToCXUnsavedFiles( unsaved_files );
  const CXUnsavedFile *unsaved = cxunsaved_files.empty()
                                 ? nullptr : &cxunsaved_files[ 0 ];

  // codeCompleteAt reparses the TU if the underlying source file has changed on
  // disk since the last time the TU was updated and there are no unsaved files.
  // If there are unsaved files, then codeCompleteAt will parse the in-memory
  // file contents we are giving it. In short, it is NEVER a good idea to call
  // clang_reparseTranslationUnit right before a call to clang_codeCompleteAt.
  // This only makes clang reparse the whole file TWICE, which has a huge impact
  // on latency. At the time of writing, it seems that most users of libclang
  // in the open-source world don't realize this (I checked). Some don't even
  // call reparse*, but parse* which is even less efficient.

  CodeCompleteResultsWrap results(
    clang_codeCompleteAt( clang_translation_unit_,
                          filename.c_str(),
                          line,
                          column,
                          const_cast<CXUnsavedFile *>( unsaved ),
                          cxunsaved_files.size(),
                          CompletionOptions() ),
    clang_disposeCodeCompleteResults );

  std::vector< CompletionData > candidates = ToCompletionDataVector(
                                               results.get() );
  return candidates;
}
Beispiel #10
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);
    }
}
void CompletionJob::execute()
{
    CXUnsavedFile unsavedFile = { mUnsaved.isEmpty() ? 0 : mPath.constData(),
                                  mUnsaved.isEmpty() ? 0 : mUnsaved.constData(),
                                  static_cast<unsigned long>(mUnsaved.size()) };

    CXCodeCompleteResults *results = clang_codeCompleteAt(mUnit, mPath.constData(), mLine, mColumn,
                                                          &unsavedFile, mUnsaved.isEmpty() ? 0 : 1,
                                                          CXCodeComplete_IncludeMacros
                                                          | CXCodeComplete_IncludeCodePatterns);

    if (results) {
        CompletionNode *nodes = new CompletionNode[results->NumResults];
        int nodeCount = 0;
        Map<Token, int> tokens;
        if (!mUnsaved.isEmpty()) {
            tokenize(mUnsaved.constData(), mUnsaved.size(), tokens);
            // for (Map<Token, int>::const_iterator it = tokens.begin(); it != tokens.end(); ++it) {
            //     error() << ByteArray(it->first.data, it->first.length) << it->second;
            // }
        }
        for (unsigned i = 0; i < results->NumResults; ++i) {
            const CXCursorKind kind = results->Results[i].CursorKind;
            if (kind == CXCursor_Destructor)
                continue;

            const CXCompletionString &string = results->Results[i].CompletionString;
            const CXAvailabilityKind availabilityKind = clang_getCompletionAvailability(string);
            if (availabilityKind != CXAvailability_Available)
                continue;

            const int priority = clang_getCompletionPriority(string);
            if (priority >= 75)
                continue;

            CompletionNode &node = nodes[nodeCount];
            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);
                    ++nodeCount;
                    continue;
                }
            }
            node.completion.clear();
            node.signature.clear();
        }
        if (nodeCount) {
            qsort(nodes, nodeCount, sizeof(CompletionNode), compareCompletionNode);
            write<128>("`%s %s", nodes[0].completion.constData(), nodes[0].signature.constData());
            for (int i=1; i<nodeCount; ++i) {
                write<128>("%s %s", nodes[i].completion.constData(), nodes[i].signature.constData());
            }
        }

        delete[] nodes;

        //processDiagnostics(results);

        clang_disposeCodeCompleteResults(results);
        shared_ptr<Project> proj = project();
        if (proj)
            proj->addToCache(mPath, mArgs, mIndex, mUnit);
    }
    mFinished(mPath);
}
void ClangWorkerThread::ProcessRequest(ThreadRequest* request)
{
    // Send start event
    PostEvent(wxEVT_CLANG_PCH_CACHE_STARTED, "");

    ClangThreadRequest* task = dynamic_cast<ClangThreadRequest*>(request);
    wxASSERT_MSG(task, "ClangWorkerThread: NULL task");

    {
        // A bit of optimization
        wxCriticalSectionLocker locker(m_criticalSection);
        if(task->GetContext() == CTX_CachePCH && m_cache.Contains(task->GetFileName())) {
            // Nothing to be done here
            PostEvent(wxEVT_CLANG_PCH_CACHE_ENDED, task->GetFileName());
            return;
        }
    }

    CL_DEBUG(wxT("==========> [ ClangPchMakerThread ] ProcessRequest started: %s"), task->GetFileName().c_str());
    CL_DEBUG(wxT("ClangWorkerThread:: processing request %d"), (int)task->GetContext());

    ClangCacheEntry cacheEntry = findEntry(task->GetFileName());
    CXTranslationUnit TU = cacheEntry.TU;
    CL_DEBUG(wxT("ClangWorkerThread:: found cached TU: %p"), (void*)TU);

    bool reparseRequired = true;
    if(!TU) {

        // First time creating the TU
        TU = DoCreateTU(task->GetIndex(), task, true);
        reparseRequired = false;
        cacheEntry.lastReparse = time(NULL);
        cacheEntry.TU = TU;
        cacheEntry.sourceFile = task->GetFileName();
    }

    if(!TU) {
        CL_DEBUG(wxT("Failed to parse Translation UNIT..."));
        PostEvent(wxEVT_CLANG_TU_CREATE_ERROR, task->GetFileName());
        return;
    }

    if(reparseRequired && task->GetContext() == ::CTX_ReparseTU) {
        DoSetStatusMsg(wxString::Format(wxT("clang: re-parsing file %s..."), task->GetFileName().c_str()));

        // We need to reparse the TU
        CL_DEBUG(wxT("Calling clang_reparseTranslationUnit... [CTX_ReparseTU]"));
        if(clang_reparseTranslationUnit(TU, 0, NULL, clang_defaultReparseOptions(TU)) == 0) {
            CL_DEBUG(wxT("Calling clang_reparseTranslationUnit... done [CTX_ReparseTU]"));
            cacheEntry.lastReparse = time(NULL);

        } else {

            CL_DEBUG(wxT("An error occured during reparsing of the TU for file %s. TU: %p"),
                     task->GetFileName().c_str(),
                     (void*)TU);

            // The only thing that left to be done here, is to dispose the TU
            clang_disposeTranslationUnit(TU);
            PostEvent(wxEVT_CLANG_TU_CREATE_ERROR, task->GetFileName());

            return;
        }
    }

    // Construct a cache-returner class
    // which makes sure that the TU is cached
    // when we leave the current scope
    CacheReturner cr(this, cacheEntry);

    // Prepare the 'End' event
    wxCommandEvent eEnd(wxEVT_CLANG_PCH_CACHE_ENDED);
    ClangThreadReply* reply = new ClangThreadReply;
    reply->context = task->GetContext();
    reply->filterWord = task->GetFilterWord();
    reply->filename = task->GetFileName().c_str();
    reply->results = NULL;

    wxFileName realFileName(reply->filename);
    if(realFileName.GetFullName().StartsWith(CODELITE_CLANG_FILE_PREFIX)) {
        realFileName.SetFullName(realFileName.GetFullName().Mid(strlen(CODELITE_CLANG_FILE_PREFIX)));
    }
    reply->filename = realFileName.GetFullPath();

    if(task->GetContext() == CTX_CodeCompletion || task->GetContext() == CTX_WordCompletion ||
       task->GetContext() == CTX_Calltip) {
        CL_DEBUG(wxT("Calling clang_codeCompleteAt..."));

        ClangThreadRequest::List_t usList = task->GetModifiedBuffers();
        usList.push_back(std::make_pair(task->GetFileName(), task->GetDirtyBuffer()));
        ClangUnsavedFiles usf(usList);

        CL_DEBUG(wxT("Location: %s:%u:%u"), task->GetFileName().c_str(), task->GetLine(), task->GetColumn());
        reply->results = clang_codeCompleteAt(TU,
                                              cstr(task->GetFileName()),
                                              task->GetLine(),
                                              task->GetColumn(),
                                              usf.GetUnsavedFiles(),
                                              usf.GetCount(),
                                              clang_defaultCodeCompleteOptions()
#if HAS_LIBCLANG_BRIEFCOMMENTS
                                                  |
                                                  CXCodeComplete_IncludeBriefComments
#endif
                                              );

        cacheEntry.lastReparse = time(NULL);

        CL_DEBUG(wxT("Calling clang_codeCompleteAt... done"));
        wxString displayTip;
        bool hasErrors(false);
        if(reply->results) {
            unsigned maxErrorToDisplay = 10;
            std::set<wxString> errorMessages;
            unsigned errorCount = clang_codeCompleteGetNumDiagnostics(reply->results);
            // Collect all errors / fatal errors and report them back to user
            for(unsigned i = 0; i < errorCount; i++) {
                CXDiagnostic diag = clang_codeCompleteGetDiagnostic(reply->results, i);
                CXDiagnosticSeverity severity = clang_getDiagnosticSeverity(diag);
                if(!hasErrors) {
                    hasErrors = (severity == CXDiagnostic_Error || severity == CXDiagnostic_Fatal);
                }

                if(severity == CXDiagnostic_Error || severity == CXDiagnostic_Fatal || severity == CXDiagnostic_Note) {
                    CXString diagStr = clang_getDiagnosticSpelling(diag);
                    wxString wxDiagString = wxString(clang_getCString(diagStr), wxConvUTF8);

                    // Collect up to 10 error messages
                    // and dont collect the same error twice
                    if(errorMessages.find(wxDiagString) == errorMessages.end() &&
                       errorMessages.size() <= maxErrorToDisplay) {
                        errorMessages.insert(wxDiagString);
                        displayTip << wxDiagString.c_str() << wxT("\n");
                    }

                    clang_disposeString(diagStr);
                }
                clang_disposeDiagnostic(diag);
            }

            CL_DEBUG(wxT("Found %u matches"), reply->results->NumResults);
            ClangUtils::printCompletionDiagnostics(reply->results);
        }

        if(!displayTip.IsEmpty() && hasErrors) {
            // Send back the error messages
            reply->errorMessage << "clang: " << displayTip;
            reply->errorMessage.RemoveLast();
            
            // Free the results
            clang_disposeCodeCompleteResults(reply->results);
            reply->results = NULL;
        }

        // Send the event
        eEnd.SetClientData(reply);
        EventNotifier::Get()->AddPendingEvent(eEnd);

    } else if(task->GetContext() == CTX_GotoDecl || task->GetContext() == CTX_GotoImpl) {

        // Check to see if the file was modified since it was last reparsed
        // If it does, we need to re-parse it again
        wxFileName fnSource(cacheEntry.sourceFile);
        time_t fileModificationTime = fnSource.GetModificationTime().GetTicks();
        time_t lastReparseTime = cacheEntry.lastReparse;

        if(fileModificationTime > lastReparseTime) {

            // The file needs to be re-parsed
            DoSetStatusMsg(wxString::Format(wxT("clang: re-parsing file %s...\n"), cacheEntry.sourceFile));

            // Try reparsing the TU
            ClangThreadRequest::List_t usList = task->GetModifiedBuffers();
            usList.push_back(std::make_pair(task->GetFileName(), task->GetDirtyBuffer()));
            ClangUnsavedFiles usf(usList);

            if(clang_reparseTranslationUnit(
                   TU, usf.GetCount(), usf.GetUnsavedFiles(), clang_defaultReparseOptions(TU)) != 0) {
                // Failed to reparse
                cr.SetCancelled(true); // cancel the re-caching of the TU

                DoSetStatusMsg(
                    wxString::Format("clang: clang_reparseTranslationUnit '%s' failed\n", cacheEntry.sourceFile));

                clang_disposeTranslationUnit(TU);
                wxDELETE(reply);
                PostEvent(wxEVT_CLANG_TU_CREATE_ERROR, task->GetFileName());
                return;
            }

            DoSetStatusMsg(
                wxString::Format("clang: clang_reparseTranslationUnit '%s' - done\n", cacheEntry.sourceFile));
            // Update the 'lastReparse' field
            cacheEntry.lastReparse = time(NULL);
        }

        bool success = DoGotoDefinition(TU, task, reply);
        if(success) {
            eEnd.SetClientData(reply);
            EventNotifier::Get()->AddPendingEvent(eEnd);

        } else {
            DoSetStatusMsg(wxT("clang: no matches were found"));
            CL_DEBUG(wxT("Clang Goto Decl/Impl: could not find a cursor matching for position %s:%d:%d"),
                     task->GetFileName().c_str(),
                     (int)task->GetLine(),
                     (int)task->GetColumn());

            // Failed, delete the 'reply' allocatd earlier
            wxDELETE(reply);
            PostEvent(wxEVT_CLANG_TU_CREATE_ERROR, task->GetFileName());
        }
    } else {

        wxDELETE(reply);
        PostEvent(wxEVT_CLANG_PCH_CACHE_ENDED, task->GetFileName());
    }
}
Beispiel #13
0
code_complete_results translation_unit::codeCompleteAt(const std::string& filename, unsigned line, unsigned column, const std::vector<unsaved_file>& unsaved)
{
    auto unsaved_files = convert_unsaved_files(unsaved);
    auto options = clang_defaultCodeCompleteOptions();
    return { clang_codeCompleteAt(tu, filename.c_str(), line, column, unsaved_files.data(), unsaved_files.size(), options) };
}
Beispiel #14
0
void Irony::complete(const std::string &file,
                     unsigned line,
                     unsigned col,
                     const std::vector<std::string> &flags,
                     const std::vector<CXUnsavedFile> &unsavedFiles) {
  CXTranslationUnit tu = tuManager_.getOrCreateTU(file, flags, unsavedFiles);

  if (tu == nullptr) {
    std::cout << "nil\n";
    return;
  }

  if (CXCodeCompleteResults *completions =
          clang_codeCompleteAt(tu,
                               file.c_str(),
                               line,
                               col,
                               const_cast<CXUnsavedFile *>(unsavedFiles.data()),
                               unsavedFiles.size(),
                               (clang_defaultCodeCompleteOptions() &
                                ~CXCodeComplete_IncludeCodePatterns)
#if HAS_BRIEF_COMMENTS_IN_COMPLETION
                                   |
                                   CXCodeComplete_IncludeBriefComments
#endif
                               )) {

    if (debug_) {
      unsigned numDiags = clang_codeCompleteGetNumDiagnostics(completions);
      std::clog << "debug: complete: " << numDiags << " diagnostic(s)\n";
      for (unsigned i = 0; i < numDiags; ++i) {
        CXDiagnostic diagnostic =
            clang_codeCompleteGetDiagnostic(completions, i);
        CXString s = clang_formatDiagnostic(
            diagnostic, clang_defaultDiagnosticDisplayOptions());

        std::clog << clang_getCString(s) << std::endl;
        clang_disposeString(s);
        clang_disposeDiagnostic(diagnostic);
      }
    }

    clang_sortCodeCompletionResults(completions->Results,
                                    completions->NumResults);

    std::cout << "(\n";

    // re-use the same buffers to avoid unnecessary allocations
    std::string typedtext, brief, resultType, prototype, postCompCar;
    std::vector<unsigned> postCompCdr;

    for (unsigned i = 0; i < completions->NumResults; ++i) {
      CXCompletionResult candidate = completions->Results[i];
      CXAvailabilityKind availability =
          clang_getCompletionAvailability(candidate.CompletionString);

      unsigned priority =
          clang_getCompletionPriority(candidate.CompletionString);
      unsigned annotationStart = 0;
      bool typedTextSet = false;

      if (availability == CXAvailability_NotAccessible ||
          availability == CXAvailability_NotAvailable) {
        continue;
      }

      typedtext.clear();
      brief.clear();
      resultType.clear();
      prototype.clear();
      postCompCar.clear();
      postCompCdr.clear();

      for (CompletionChunk chunk(candidate.CompletionString); chunk.hasNext();
           chunk.next()) {
        char ch = 0;

        auto chunkKind = chunk.kind();

        switch (chunkKind) {
        case CXCompletionChunk_ResultType:
          resultType = chunk.text();
          break;

        case CXCompletionChunk_TypedText:
        case CXCompletionChunk_Text:
        case CXCompletionChunk_Placeholder:
        case CXCompletionChunk_Informative:
        case CXCompletionChunk_CurrentParameter:
          prototype += chunk.text();
          break;

        case CXCompletionChunk_LeftParen:       ch = '(';  break;
        case CXCompletionChunk_RightParen:      ch = ')';  break;
        case CXCompletionChunk_LeftBracket:     ch = '[';  break;
        case CXCompletionChunk_RightBracket:    ch = ']';  break;
        case CXCompletionChunk_LeftBrace:       ch = '{';  break;
        case CXCompletionChunk_RightBrace:      ch = '}';  break;
        case CXCompletionChunk_LeftAngle:       ch = '<';  break;
        case CXCompletionChunk_RightAngle:      ch = '>';  break;
        case CXCompletionChunk_Comma:           ch = ',';  break;
        case CXCompletionChunk_Colon:           ch = ':';  break;
        case CXCompletionChunk_SemiColon:       ch = ';';  break;
        case CXCompletionChunk_Equal:           ch = '=';  break;
        case CXCompletionChunk_HorizontalSpace: ch = ' ';  break;
        case CXCompletionChunk_VerticalSpace:   ch = '\n'; break;

        case CXCompletionChunk_Optional:
          // ignored for now
          break;
        }

        if (ch != 0) {
          prototype += ch;
          // commas look better followed by a space
          if (ch == ',') {
            prototype += ' ';
          }
        }

        if (typedTextSet) {
          if (ch != 0) {
            postCompCar += ch;
            if (ch == ',') {
              postCompCar += ' ';
            }
          } else if (chunkKind == CXCompletionChunk_Text ||
                     chunkKind == CXCompletionChunk_TypedText) {
            postCompCar += chunk.text();
          } else if (chunkKind == CXCompletionChunk_Placeholder ||
                     chunkKind == CXCompletionChunk_CurrentParameter) {
            postCompCdr.push_back(postCompCar.size());
            postCompCar += chunk.text();
            postCompCdr.push_back(postCompCar.size());
          }
        }

        // Consider only the first typed text. The CXCompletionChunk_TypedText
        // doc suggests that exactly one typed text will be given but at least
        // in Objective-C it seems that more than one can appear, see:
        // https://github.com/Sarcasm/irony-mode/pull/78#issuecomment-37115538
        if (chunkKind == CXCompletionChunk_TypedText && !typedTextSet) {
          typedtext = chunk.text();
          // annotation is what comes after the typedtext
          annotationStart = prototype.size();
          typedTextSet = true;
        }
      }

#if HAS_BRIEF_COMMENTS_IN_COMPLETION
      brief = cxStringToStd(
          clang_getCompletionBriefComment(candidate.CompletionString));
#endif

      // see irony-completion.el#irony-completion-candidates
      std::cout << '(' << support::quoted(typedtext)  //
                << ' ' << priority                    //
                << ' ' << support::quoted(resultType) //
                << ' ' << support::quoted(brief)      //
                << ' ' << support::quoted(prototype)  //
                << ' ' << annotationStart             //
                << " (" << support::quoted(postCompCar);
      for (unsigned index : postCompCdr)
        std::cout << ' ' << index;
      std::cout << ")"
                << ")\n";
    }

    clang_disposeCodeCompleteResults(completions);
    std::cout << ")\n";
  }
}
    completion_list translation_unit::complete_at(uint32_t row, uint32_t col) {
        completion_list ret;
        CXCodeCompleteResults *res;

        if (mCxUnsaved) {
            res = clang_codeCompleteAt(mUnit, mName.c_str(), row, col, mCxUnsaved, 1, 0);
        }
        else
            res = clang_codeCompleteAt(mUnit, mName.c_str(), row, col, nullptr, 0, 0);

        for (uint32_t i = 0; i < res->NumResults; ++i) {
            // skip all private members
            if (clang_getCompletionAvailability(res->Results[i].CompletionString) == CXAvailability_NotAccessible)
                continue;

            // number of completion chunks for the current result
            completion_result r;
            uint32_t nChunks = clang_getNumCompletionChunks(res->Results[i].CompletionString);

            // function to handle a single chunk
            auto handle_chunk = [&](CXCompletionChunkKind k, uint32_t num) {
                CXString txt = clang_getCompletionChunkText(res->Results[i].CompletionString, num);
                switch (k) {
                    case CXCompletionChunk_ResultType:
                        r.return_type = cx2std(txt);
                        break;
                    case CXCompletionChunk_TypedText:
                        r.name = cx2std(txt);
                        break;
                    case CXCompletionChunk_Placeholder:
                        r.args.push_back(cx2std(txt));
                        break;
                    case CXCompletionChunk_Optional:
                    case CXCompletionChunk_LeftParen:
                    case CXCompletionChunk_RightParen:
                    case CXCompletionChunk_RightBracket:
                    case CXCompletionChunk_LeftBracket:
                    case CXCompletionChunk_LeftBrace:
                    case CXCompletionChunk_RightBrace:
                    case CXCompletionChunk_RightAngle:
                    case CXCompletionChunk_LeftAngle:
                    case CXCompletionChunk_Comma:
                    case CXCompletionChunk_Colon:
                    case CXCompletionChunk_SemiColon:
                    case CXCompletionChunk_Equal:
                    case CXCompletionChunk_Informative:
                    case CXCompletionChunk_HorizontalSpace:
                        break;
                    default:
                        break;
                }
            };

            for (uint32_t k = 0; k < nChunks; ++k) {
                handle_chunk(clang_getCompletionChunkKind(res->Results[i].CompletionString, k), k);
            }

            // fill additional info and append to result set
            r.brief = cx2std(clang_getCompletionBriefComment(res->Results[i].CompletionString));
            r.priority = clang_getCompletionPriority(res->Results[i].CompletionString);
            r.type = cursor2completion(res->Results[i].CursorKind);

            // @todo: once clang forwards the CXCursor of a completion result, we should get
            //        the full documentation for each entry

            ret.push_back(r);
        }

        clang_disposeCodeCompleteResults(res);
        return ret;
    }
Beispiel #16
0
void CompletionJob::execute()
{
    StopWatch timer;
    CXUnsavedFile unsavedFile = { mUnsaved.isEmpty() ? 0 : mPath.constData(),
                                  mUnsaved.isEmpty() ? 0 : mUnsaved.constData(),
                                  static_cast<unsigned long>(mUnsaved.size()) };
    if (!mUnit) {
        String clangLine;
        RTags::parseTranslationUnit(mPath, mArgs, mUnit, Server::instance()->clangIndex(), clangLine,
                                    0, 0, &unsavedFile, 1);
        mParseCount = 1;
        if (!mUnit) {
            error() << "Failed to parse" << mPath << "Can't complete";
            return;
        }
    }
    // error() << "Completing" << mPath << mParseCount;
    assert(mParseCount >= 1 && mParseCount <= 2);
    if (mParseCount == 1) {
        RTags::reparseTranslationUnit(mUnit, &unsavedFile, 1);
        if (!mUnit) {
            mFinished(mPath, id());
            return;
        } else {
            ++mParseCount;
        }
    }

    CXCodeCompleteResults *results = clang_codeCompleteAt(mUnit, mPath.constData(), mLine, mColumn,
                                                          &unsavedFile, mUnsaved.isEmpty() ? 0 : 1,
                                                          CXCodeComplete_IncludeMacros
                                                          | CXCodeComplete_IncludeCodePatterns);
    if (results) {
        CompletionNode *nodes = new CompletionNode[results->NumResults];
        int nodeCount = 0;
        Map<Token, int> tokens;
        if (!mUnsaved.isEmpty()) {
            tokenize(mUnsaved.constData(), mUnsaved.size(), tokens);
            // 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 i = 0; i < results->NumResults; ++i) {
            const CXCursorKind kind = results->Results[i].CursorKind;
            if (kind == CXCursor_Destructor)
                continue;

            const CXCompletionString &string = results->Results[i].CompletionString;
            const CXAvailabilityKind availabilityKind = clang_getCompletionAvailability(string);
            if (availabilityKind != CXAvailability_Available)
                continue;

            const int priority = clang_getCompletionPriority(string);
            if (priority >= 75)
                continue;

            CompletionNode &node = nodes[nodeCount];
            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);
                    ++nodeCount;
                    continue;
                }
            }
            node.completion.clear();
            node.signature.clear();
        }
        if (nodeCount) {
            if (nodeCount > SendThreshold) {
                write("`");
            } else {
                qsort(nodes, nodeCount, sizeof(CompletionNode), compareCompletionNode);
                if (mType == Stream) {
                    write<128>("`%s %s", nodes[0].completion.constData(), nodes[0].signature.constData());
                } else {
                    write<128>("%s %s", nodes[0].completion.constData(), nodes[0].signature.constData());
                }
                for (int i=1; i<nodeCount; ++i) {
                    write<128>("%s %s", nodes[i].completion.constData(), nodes[i].signature.constData());
                }
            }
        }

        warning() << "Wrote" << ((nodeCount > SendThreshold) ? -1 : nodeCount) << "completions for"
                  << String::format<128>("%s:%d:%d", mPath.constData(), mLine, mColumn)
                  << "in" << timer.elapsed() << "ms" << mArgs;
        // const unsigned diagnosticCount = clang_getNumDiagnostics(mUnit);
        // for (unsigned i=0; i<diagnosticCount; ++i) {
        //     CXDiagnostic diagnostic = clang_getDiagnostic(mUnit, i);
        //     const CXDiagnosticSeverity severity = clang_getDiagnosticSeverity(diagnostic);
        //     const String msg = RTags::eatString(clang_getDiagnosticSpelling(diagnostic));
        //     CXFile file;
        //     unsigned line, col;
        //     clang_getSpellingLocation(clang_getDiagnosticLocation(diagnostic), &file, &line, &col, 0);

        //     error() << i << diagnosticCount << severity << msg
        //             << String::format<128>("%s:%d:%d", RTags::eatString(clang_getFileName(file)).constData(),
        //                                    line, col);
        //     clang_disposeDiagnostic(diagnostic);
        // }

        delete[] nodes;

        //processDiagnostics(results);

        clang_disposeCodeCompleteResults(results);
        std::shared_ptr<Project> proj = project();
        if (proj) {
            // error() << "Adding to cache" << mParseCount << mPath;
            proj->addToCache(mPath, mArgs, mUnit, mParseCount);
        }
    }
    mFinished(mPath, id());
}
QList<ClangCodeCompletionItem> TranslationUnit::completeAt(
    const int line
  , const int column
  , const unsigned completion_flags
  , const clang::unsaved_files_list& unsaved_files
  , const PluginConfiguration::sanitize_rules_list_type& sanitize_rules
  )
{
    auto files = unsaved_files.get();
#ifndef NDEBUG
    for (auto& item : files)
        assert(
            "Sanity check"
          && item.Filename
          && std::strlen(item.Filename)
          && item.Contents
          && item.Length
          );
#endif

    clang::DCXCodeCompleteResults res = {
        clang_codeCompleteAt(
            m_unit
          , m_filename.constData()
          , unsigned(line)
          , unsigned(column)
          , files.data()
          , files.size()
          , completion_flags
          )
      };
    if (!res)
    {
        throw Exception::CompletionFailure(
            i18nc("@item:intext", "Unable to perform code completion").toAscii().constData()
          );
    }

#if 0
    clang_sortCodeCompletionResults(res->Results, res->NumResults);
#endif

    // Collect some diagnostic SPAM
    for (auto i = 0u; i < clang_codeCompleteGetNumDiagnostics(res); ++i)
    {
        clang::DCXDiagnostic diag = {clang_codeCompleteGetDiagnostic(res, i)};
        appendDiagnostic(diag);
    }

    QList<ClangCodeCompletionItem> completions;
    completions.reserve(res->NumResults);                   // Peallocate enough space for completion results

    // Lets look what we've got...
    for (auto i = 0u; i < res->NumResults; ++i)
    {
        const auto str = res->Results[i].CompletionString;
        const auto priority = clang_getCompletionPriority(str);
        const auto cursor_kind = res->Results[i].CursorKind;
        debugShowCompletionResult(i, priority, str, cursor_kind);

        // Skip unusable completions
        // 0) check availability
        const auto availability = clang_getCompletionAvailability(str);
        if (availability != CXAvailability_Available && availability != CXAvailability_Deprecated)
        {
            kDebug(DEBUG_AREA) << "!! Skip result" << i << "as not available";
            continue;
        }
        // 1) check usefulness
        /// \todo Make it configurable
        if (cursor_kind == CXCursor_NotImplemented)
            continue;

        // Collect all completion chunks and from a format string
        QString text_before;
        QString typed_text;
        QString text_after;
        QStringList placeholders;
        int optional_placeholers_start_position = -1;
        // A lambda to append given text to different parts
        // of future completion string, depending on already processed text
        auto appender = [&](const QString& text)
        {
            if (typed_text.isEmpty())
                text_before += text;
            else
                text_after += text;
        };
        auto skip_this_item = false;
        for (
            auto j = 0u
          , chunks = clang_getNumCompletionChunks(str)
          ; j < chunks && !skip_this_item
          ; ++j
          )
        {
            auto kind = clang_getCompletionChunkKind(str, j);
            auto text = toString(clang::DCXString{clang_getCompletionChunkText(str, j)});
            switch (kind)
            {
                // Text that a user would be expected to type to get this code-completion result
                case CXCompletionChunk_TypedText:
                // Text that should be inserted as part of a code-completion result
                case CXCompletionChunk_Text:
                {
                    auto p = sanitize(text, sanitize_rules);// Pipe given piece of text through sanitizer
                    if (p.first)
                        typed_text += p.second;
                    else                                    // Go for next completion item
                        skip_this_item = true;
                    break;
                }
                // Placeholder text that should be replaced by the user
                case CXCompletionChunk_Placeholder:
                {
                    auto p = sanitize(text, sanitize_rules);// Pipe given piece of text through sanitizer
                    if (p.first)
                    {
                        appender(
                            QLatin1String{"%"}
                          + QString::number(placeholders.size() + 1)
                          + QLatin1String{"%"}
                          );
                        placeholders.push_back(p.second);
                    }
                    else                                    // Go for next completion item
                        skip_this_item = true;
                    break;
                }
                // A code-completion string that describes "optional" text that
                // could be a part of the template (but is not required)
                case CXCompletionChunk_Optional:
                {
                    auto ostr = clang_getCompletionChunkCompletionString(str, j);
                    for (
                        auto oci = 0u
                      , ocn = clang_getNumCompletionChunks(ostr)
                      ; oci < ocn
                      ; ++oci
                      )
                    {
                        auto otext = toString(clang::DCXString{clang_getCompletionChunkText(ostr, oci)});
                        // Pipe given piece of text through sanitizer
                        auto p = sanitize(otext, sanitize_rules);
                        if (p.first)
                        {
                            auto okind = clang::kind_of(ostr, oci);
                            if (okind == CXCompletionChunk_Placeholder)
                            {
                                appender(
                                    QLatin1String{"%"}
                                  + QString::number(placeholders.size() + 1)
                                  + QLatin1String{"%"}
                                  );
                                placeholders.push_back(p.second);
                                optional_placeholers_start_position = placeholders.size();
                            }
                            else appender(p.second);
                        }
                        else
                        {
                            skip_this_item = true;
                            break;
                        }
                    }
                    break;
                }
                case CXCompletionChunk_ResultType:
                case CXCompletionChunk_LeftParen:
                case CXCompletionChunk_RightParen:
                case CXCompletionChunk_LeftBracket:
                case CXCompletionChunk_RightBracket:
                case CXCompletionChunk_LeftBrace:
                case CXCompletionChunk_RightBrace:
                case CXCompletionChunk_LeftAngle:
                case CXCompletionChunk_RightAngle:
                case CXCompletionChunk_Comma:
                case CXCompletionChunk_Colon:
                case CXCompletionChunk_SemiColon:
                case CXCompletionChunk_Equal:
                case CXCompletionChunk_CurrentParameter:
                case CXCompletionChunk_HorizontalSpace:
                /// \todo Kate can't handle \c '\n' well in completions list
                case CXCompletionChunk_VerticalSpace:
                {
                    auto p = sanitize(text, sanitize_rules);// Pipe given piece of text through sanitizer
                    if (p.first)
                        appender(p.second);
                    else                                    // Go for next completion item
                        skip_this_item = true;
                    break;
                }
                // Informative text that should be displayed but never inserted
                // as part of the template
                case CXCompletionChunk_Informative:
                    // Informative text before CXCompletionChunk_TypedText usually
                    // just a method scope (i.e. long name of an owner class)
                    // and it's useless for completer cuz it can group items
                    // by parent already...
                    if (!typed_text.isEmpty())
                    {
                        // Pipe given piece of text through sanitizer
                        auto p = sanitize(text, sanitize_rules);
                        if (p.first)
                            appender(p.second);
                        else                                // Go for next completion item
                            skip_this_item = true;
                    }
                    break;
                default:
                    break;
            }
        }
        // Does it pass the completion items sanitizer?
        if (skip_this_item) continue;                       // No! Skip it!

        assert("Priority expected to be less than 100" && priority < 101u);

        const auto comment = toString(clang::DCXString{clang_getCompletionBriefComment(str)});
        //
        completions.push_back({
            makeParentText(str, cursor_kind)
          , text_before
          , typed_text
          , text_after
          , placeholders
          , optional_placeholers_start_position
          , priority
          , cursor_kind
          , comment
          , availability == CXAvailability_Deprecated
          });
    }

    return completions;
}
Beispiel #18
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);
}
    //setCurrentCharFormat(m_formatKeyword);
    currentCursor.setCharFormat(m_formatMacro);
   /* Highlight *hi = new Highlight();
    hi->setCXFile(file);
    hi->setCXSourceRange(range);
    hi->setCXTranslationUnit(cx_tu);

    hi->setDocument(this->document());*/
   // ObjcHighlighter *h = new ObjcHighlighter(this->document());

    //qDebug()<<tokenCount;
    int currentLine = this->textCursor().blockNumber()+1;
    int currentColumn = this->textCursor().columnNumber();
    qDebug() << currentLine <<currentColumn<<endl;
    CXCodeCompleteResults *result = clang_codeCompleteAt(
                cx_tu, "/tmp/a.m", currentLine, currentColumn,
        &unsaved_file, 1, CXCodeComplete_IncludeMacros);
    clang_sortCodeCompletionResults(result->Results, result->NumResults);

    FILE * fp = fopen("/tmp/log.txt","w");
    completion_printCodeCompletionResults(result, fp);
    fclose(fp);


    int maxwidth = 0;
    for ( int i = 0; i < result->NumResults; i++) {
        CXCompletionString cx_str= result->Results[i].CompletionString;
        CXString ac_string;
        for(int i = 0; i < clang_getNumCompletionChunks(cx_str); i++) {
            if(clang_getCompletionChunkKind(cx_str,i) == CXCompletionChunk_TypedText) {
                ac_string= clang_getCompletionChunkText(cx_str, i);