diff options
Diffstat (limited to 'tools/libclang/CIndexCodeCompletion.cpp')
-rw-r--r-- | tools/libclang/CIndexCodeCompletion.cpp | 185 |
1 files changed, 163 insertions, 22 deletions
diff --git a/tools/libclang/CIndexCodeCompletion.cpp b/tools/libclang/CIndexCodeCompletion.cpp index 832e2f2..c19b340 100644 --- a/tools/libclang/CIndexCodeCompletion.cpp +++ b/tools/libclang/CIndexCodeCompletion.cpp @@ -15,7 +15,12 @@ #include "CIndexer.h" #include "CXTranslationUnit.h" #include "CXString.h" +#include "CXCursor.h" +#include "CXString.h" #include "CIndexDiagnostic.h" +#include "clang/AST/Type.h" +#include "clang/AST/Decl.h" +#include "clang/AST/DeclObjC.h" #include "clang/Basic/SourceManager.h" #include "clang/Basic/FileManager.h" #include "clang/Frontend/ASTUnit.h" @@ -198,6 +203,20 @@ clang_getCompletionAvailability(CXCompletionString completion_string) { : CXAvailability_Available; } +unsigned clang_getCompletionNumAnnotations(CXCompletionString completion_string) +{ + CodeCompletionString *CCStr = (CodeCompletionString *)completion_string; + return CCStr ? CCStr->getAnnotationCount() : 0; +} + +CXString clang_getCompletionAnnotation(CXCompletionString completion_string, + unsigned annotation_number) { + CodeCompletionString *CCStr = (CodeCompletionString *)completion_string; + return CCStr ? createCXString(CCStr->getAnnotation(annotation_number)) + : createCXString((const char *) 0); +} + + /// \brief The CXCodeCompleteResults structure we allocate internally; /// the client only sees the initial CXCodeCompleteResults structure. struct AllocatedCXCodeCompleteResults : public CXCodeCompleteResults { @@ -205,10 +224,10 @@ struct AllocatedCXCodeCompleteResults : public CXCodeCompleteResults { ~AllocatedCXCodeCompleteResults(); /// \brief Diagnostics produced while performing code completion. - llvm::SmallVector<StoredDiagnostic, 8> Diagnostics; + SmallVector<StoredDiagnostic, 8> Diagnostics; /// \brief Diag object - llvm::IntrusiveRefCntPtr<Diagnostic> Diag; + llvm::IntrusiveRefCntPtr<DiagnosticsEngine> Diag; /// \brief Language options used to adjust source locations. LangOptions LangOpts; @@ -227,7 +246,7 @@ struct AllocatedCXCodeCompleteResults : public CXCodeCompleteResults { /// \brief Temporary buffers that will be deleted once we have finished with /// the code-completion results. - llvm::SmallVector<const llvm::MemoryBuffer *, 1> TemporaryBuffers; + SmallVector<const llvm::MemoryBuffer *, 1> TemporaryBuffers; /// \brief Allocator used to store globally cached code-completion results. llvm::IntrusiveRefCntPtr<clang::GlobalCodeCompletionAllocator> @@ -242,6 +261,18 @@ struct AllocatedCXCodeCompleteResults : public CXCodeCompleteResults { /// \brief A bitfield representing the acceptable completions for the /// current context. unsigned long long Contexts; + + /// \brief The kind of the container for the current context for completions. + enum CXCursorKind ContainerKind; + /// \brief The USR of the container for the current context for completions. + CXString ContainerUSR; + /// \brief a boolean value indicating whether there is complete information + /// about the container + unsigned ContainerIsIncomplete; + + /// \brief A string containing the Objective-C selector entered thus far for a + /// message send. + std::string Selector; }; /// \brief Tracks the number of code-completion result objects that are @@ -253,11 +284,16 @@ static llvm::sys::cas_flag CodeCompletionResultObjects; AllocatedCXCodeCompleteResults::AllocatedCXCodeCompleteResults( const FileSystemOptions& FileSystemOpts) : CXCodeCompleteResults(), - Diag(new Diagnostic( + Diag(new DiagnosticsEngine( llvm::IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs))), FileSystemOpts(FileSystemOpts), FileMgr(new FileManager(FileSystemOpts)), - SourceMgr(new SourceManager(*Diag, *FileMgr)) { + SourceMgr(new SourceManager(*Diag, *FileMgr)), + Contexts(CXCompletionContext_Unknown), + ContainerKind(CXCursor_InvalidCode), + ContainerUSR(createCXString("")), + ContainerIsIncomplete(1) +{ if (getenv("LIBCLANG_OBJTRACKING")) { llvm::sys::AtomicIncrement(&CodeCompletionResultObjects); fprintf(stderr, "+++ %d completion results\n", CodeCompletionResultObjects); @@ -267,6 +303,8 @@ AllocatedCXCodeCompleteResults::AllocatedCXCodeCompleteResults( AllocatedCXCodeCompleteResults::~AllocatedCXCodeCompleteResults() { delete [] Results; + clang_disposeString(ContainerUSR); + for (unsigned I = 0, N = TemporaryFiles.size(); I != N; ++I) TemporaryFiles[I].eraseFromDisk(); for (unsigned I = 0, N = TemporaryBuffers.size(); I != N; ++I) @@ -420,7 +458,7 @@ static unsigned long long getContextsForContextKind( contexts = CXCompletionContext_ObjCClassMessage; break; } - case CodeCompletionContext::CCC_ObjCSuperclass: { + case CodeCompletionContext::CCC_ObjCInterfaceName: { contexts = CXCompletionContext_ObjCInterface; break; } @@ -454,11 +492,13 @@ static unsigned long long getContextsForContextKind( namespace { class CaptureCompletionResults : public CodeCompleteConsumer { AllocatedCXCodeCompleteResults &AllocatedResults; - llvm::SmallVector<CXCompletionResult, 16> StoredResults; + SmallVector<CXCompletionResult, 16> StoredResults; + CXTranslationUnit *TU; public: - CaptureCompletionResults(AllocatedCXCodeCompleteResults &Results) + CaptureCompletionResults(AllocatedCXCodeCompleteResults &Results, + CXTranslationUnit *TranslationUnit) : CodeCompleteConsumer(true, false, true, false), - AllocatedResults(Results) { } + AllocatedResults(Results), TU(TranslationUnit) { } ~CaptureCompletionResults() { Finish(); } virtual void ProcessCodeCompleteResults(Sema &S, @@ -477,10 +517,77 @@ namespace { StoredResults.push_back(R); } - enum CodeCompletionContext::Kind kind = Context.getKind(); + enum CodeCompletionContext::Kind contextKind = Context.getKind(); - AllocatedResults.ContextKind = kind; - AllocatedResults.Contexts = getContextsForContextKind(kind, S); + AllocatedResults.ContextKind = contextKind; + AllocatedResults.Contexts = getContextsForContextKind(contextKind, S); + + AllocatedResults.Selector = ""; + if (Context.getNumSelIdents() > 0) { + for (unsigned i = 0; i < Context.getNumSelIdents(); i++) { + IdentifierInfo *selIdent = Context.getSelIdents()[i]; + if (selIdent != NULL) { + StringRef selectorString = Context.getSelIdents()[i]->getName(); + AllocatedResults.Selector += selectorString; + } + AllocatedResults.Selector += ":"; + } + } + + QualType baseType = Context.getBaseType(); + NamedDecl *D = NULL; + + if (!baseType.isNull()) { + // Get the declaration for a class/struct/union/enum type + if (const TagType *Tag = baseType->getAs<TagType>()) + D = Tag->getDecl(); + // Get the @interface declaration for a (possibly-qualified) Objective-C + // object pointer type, e.g., NSString* + else if (const ObjCObjectPointerType *ObjPtr = + baseType->getAs<ObjCObjectPointerType>()) + D = ObjPtr->getInterfaceDecl(); + // Get the @interface declaration for an Objective-C object type + else if (const ObjCObjectType *Obj = baseType->getAs<ObjCObjectType>()) + D = Obj->getInterface(); + // Get the class for a C++ injected-class-name + else if (const InjectedClassNameType *Injected = + baseType->getAs<InjectedClassNameType>()) + D = Injected->getDecl(); + } + + if (D != NULL) { + CXCursor cursor = cxcursor::MakeCXCursor(D, *TU); + + CXCursorKind cursorKind = clang_getCursorKind(cursor); + CXString cursorUSR = clang_getCursorUSR(cursor); + + // Normally, clients of CXString shouldn't care whether or not + // a CXString is managed by a pool or by explicitly malloc'ed memory. + // However, there are cases when AllocatedResults outlives the + // CXTranslationUnit. This is a workaround that failure mode. + if (cxstring::isManagedByPool(cursorUSR)) { + CXString heapStr = + cxstring::createCXString(clang_getCString(cursorUSR), true); + clang_disposeString(cursorUSR); + cursorUSR = heapStr; + } + + AllocatedResults.ContainerKind = cursorKind; + AllocatedResults.ContainerUSR = cursorUSR; + + const Type *type = baseType.getTypePtrOrNull(); + if (type != NULL) { + AllocatedResults.ContainerIsIncomplete = type->isIncompleteType(); + } + else { + AllocatedResults.ContainerIsIncomplete = 1; + } + } + else { + AllocatedResults.ContainerKind = CXCursor_InvalidCode; + AllocatedResults.ContainerUSR = createCXString(""); + AllocatedResults.ContainerIsIncomplete = 1; + } } virtual void ProcessOverloadCandidates(Sema &S, unsigned CurrentArg, @@ -551,9 +658,9 @@ void clang_codeCompleteAt_Impl(void *UserData) { ASTUnit::ConcurrencyCheck Check(*AST); // Perform the remapping of source files. - llvm::SmallVector<ASTUnit::RemappedFile, 4> RemappedFiles; + SmallVector<ASTUnit::RemappedFile, 4> RemappedFiles; for (unsigned I = 0; I != num_unsaved_files; ++I) { - llvm::StringRef Data(unsaved_files[I].Contents, unsaved_files[I].Length); + StringRef Data(unsaved_files[I].Contents, unsaved_files[I].Length); const llvm::MemoryBuffer *Buffer = llvm::MemoryBuffer::getMemBufferCopy(Data, unsaved_files[I].Filename); RemappedFiles.push_back(std::make_pair(unsaved_files[I].Filename, @@ -571,7 +678,7 @@ void clang_codeCompleteAt_Impl(void *UserData) { Results->NumResults = 0; // Create a code-completion consumer to capture the results. - CaptureCompletionResults Capture(*Results); + CaptureCompletionResults Capture(*Results, &TU); // Perform completion. AST->CodeComplete(complete_filename, complete_line, complete_column, @@ -621,7 +728,7 @@ void clang_codeCompleteAt_Impl(void *UserData) { } pchName.push_back('\0'); struct stat stat_results; - if (stat(pchName.data(), &stat_results) == 0) + if (stat(pchName.str().c_str(), &stat_results) == 0) usesPCH = true; continue; } @@ -639,7 +746,7 @@ void clang_codeCompleteAt_Impl(void *UserData) { os << ", \"clangVer\": \"" << getClangFullVersion() << '"'; os << " }"; - llvm::StringRef res = os.str(); + StringRef res = os.str(); if (res.size() > 0) { do { // Setup the UDP socket. @@ -731,6 +838,40 @@ clang_codeCompleteGetContexts(CXCodeCompleteResults *ResultsIn) { return Results->Contexts; } +enum CXCursorKind clang_codeCompleteGetContainerKind( + CXCodeCompleteResults *ResultsIn, + unsigned *IsIncomplete) { + AllocatedCXCodeCompleteResults *Results = + static_cast<AllocatedCXCodeCompleteResults *>(ResultsIn); + if (!Results) + return CXCursor_InvalidCode; + + if (IsIncomplete != NULL) { + *IsIncomplete = Results->ContainerIsIncomplete; + } + + return Results->ContainerKind; +} + +CXString clang_codeCompleteGetContainerUSR(CXCodeCompleteResults *ResultsIn) { + AllocatedCXCodeCompleteResults *Results = + static_cast<AllocatedCXCodeCompleteResults *>(ResultsIn); + if (!Results) + return createCXString(""); + + return createCXString(clang_getCString(Results->ContainerUSR)); +} + + +CXString clang_codeCompleteGetObjCSelector(CXCodeCompleteResults *ResultsIn) { + AllocatedCXCodeCompleteResults *Results = + static_cast<AllocatedCXCodeCompleteResults *>(ResultsIn); + if (!Results) + return createCXString(""); + + return createCXString(Results->Selector); +} + } // end extern "C" /// \brief Simple utility function that appends a \p New string to the given @@ -744,7 +885,7 @@ clang_codeCompleteGetContexts(CXCodeCompleteResults *ResultsIn) { /// /// \param Buffer A buffer that stores the actual, concatenated string. It will /// be used if the old string is already-non-empty. -static void AppendToString(llvm::StringRef &Old, llvm::StringRef New, +static void AppendToString(StringRef &Old, StringRef New, llvm::SmallString<256> &Buffer) { if (Old.empty()) { Old = New; @@ -764,9 +905,9 @@ static void AppendToString(llvm::StringRef &Old, llvm::StringRef New, /// concatenated. /// /// \param Buffer A buffer used for storage of the completed name. -static llvm::StringRef GetTypedName(CodeCompletionString *String, +static StringRef GetTypedName(CodeCompletionString *String, llvm::SmallString<256> &Buffer) { - llvm::StringRef Result; + StringRef Result; for (CodeCompletionString::iterator C = String->begin(), CEnd = String->end(); C != CEnd; ++C) { if (C->Kind == CodeCompletionString::CK_TypedText) @@ -786,9 +927,9 @@ namespace { = (CodeCompletionString *)YR.CompletionString; llvm::SmallString<256> XBuffer; - llvm::StringRef XText = GetTypedName(X, XBuffer); + StringRef XText = GetTypedName(X, XBuffer); llvm::SmallString<256> YBuffer; - llvm::StringRef YText = GetTypedName(Y, YBuffer); + StringRef YText = GetTypedName(Y, YBuffer); if (XText.empty() || YText.empty()) return !XText.empty(); |