| //===- CIndexCodeCompletion.cpp - Code Completion API hooks ---------------===// | 
 | // | 
 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | 
 | // See https://llvm.org/LICENSE.txt for license information. | 
 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | 
 | // | 
 | //===----------------------------------------------------------------------===// | 
 | // | 
 | // This file implements the Clang-C Source Indexing library hooks for | 
 | // code completion. | 
 | // | 
 | //===----------------------------------------------------------------------===// | 
 |  | 
 | #include "CIndexer.h" | 
 | #include "CIndexDiagnostic.h" | 
 | #include "CLog.h" | 
 | #include "CXCursor.h" | 
 | #include "CXSourceLocation.h" | 
 | #include "CXString.h" | 
 | #include "CXTranslationUnit.h" | 
 | #include "clang/AST/Decl.h" | 
 | #include "clang/AST/DeclObjC.h" | 
 | #include "clang/AST/Type.h" | 
 | #include "clang/Basic/FileManager.h" | 
 | #include "clang/Basic/SourceManager.h" | 
 | #include "clang/Frontend/ASTUnit.h" | 
 | #include "clang/Frontend/CompilerInstance.h" | 
 | #include "clang/Sema/CodeCompleteConsumer.h" | 
 | #include "clang/Sema/Sema.h" | 
 | #include "llvm/ADT/SmallString.h" | 
 | #include "llvm/ADT/StringExtras.h" | 
 | #include "llvm/Support/CrashRecoveryContext.h" | 
 | #include "llvm/Support/FileSystem.h" | 
 | #include "llvm/Support/FormatVariadic.h" | 
 | #include "llvm/Support/MemoryBuffer.h" | 
 | #include "llvm/Support/Program.h" | 
 | #include "llvm/Support/Timer.h" | 
 | #include "llvm/Support/raw_ostream.h" | 
 | #include <atomic> | 
 | #include <cstdio> | 
 | #include <cstdlib> | 
 | #include <string> | 
 |  | 
 |  | 
 | #ifdef UDP_CODE_COMPLETION_LOGGER | 
 | #include "clang/Basic/Version.h" | 
 | #include <arpa/inet.h> | 
 | #include <sys/socket.h> | 
 | #include <sys/types.h> | 
 | #include <unistd.h> | 
 | #endif | 
 |  | 
 | using namespace clang; | 
 | using namespace clang::cxindex; | 
 |  | 
 | enum CXCompletionChunkKind | 
 | clang_getCompletionChunkKind(CXCompletionString completion_string, | 
 |                              unsigned chunk_number) { | 
 |   CodeCompletionString *CCStr = (CodeCompletionString *)completion_string; | 
 |   if (!CCStr || chunk_number >= CCStr->size()) | 
 |     return CXCompletionChunk_Text; | 
 |  | 
 |   switch ((*CCStr)[chunk_number].Kind) { | 
 |   case CodeCompletionString::CK_TypedText: | 
 |     return CXCompletionChunk_TypedText; | 
 |   case CodeCompletionString::CK_Text: | 
 |     return CXCompletionChunk_Text; | 
 |   case CodeCompletionString::CK_Optional: | 
 |     return CXCompletionChunk_Optional; | 
 |   case CodeCompletionString::CK_Placeholder: | 
 |     return CXCompletionChunk_Placeholder; | 
 |   case CodeCompletionString::CK_Informative: | 
 |     return CXCompletionChunk_Informative; | 
 |   case CodeCompletionString::CK_ResultType: | 
 |     return CXCompletionChunk_ResultType; | 
 |   case CodeCompletionString::CK_CurrentParameter: | 
 |     return CXCompletionChunk_CurrentParameter; | 
 |   case CodeCompletionString::CK_LeftParen: | 
 |     return CXCompletionChunk_LeftParen; | 
 |   case CodeCompletionString::CK_RightParen: | 
 |     return CXCompletionChunk_RightParen; | 
 |   case CodeCompletionString::CK_LeftBracket: | 
 |     return CXCompletionChunk_LeftBracket; | 
 |   case CodeCompletionString::CK_RightBracket: | 
 |     return CXCompletionChunk_RightBracket; | 
 |   case CodeCompletionString::CK_LeftBrace: | 
 |     return CXCompletionChunk_LeftBrace; | 
 |   case CodeCompletionString::CK_RightBrace: | 
 |     return CXCompletionChunk_RightBrace; | 
 |   case CodeCompletionString::CK_LeftAngle: | 
 |     return CXCompletionChunk_LeftAngle; | 
 |   case CodeCompletionString::CK_RightAngle: | 
 |     return CXCompletionChunk_RightAngle; | 
 |   case CodeCompletionString::CK_Comma: | 
 |     return CXCompletionChunk_Comma; | 
 |   case CodeCompletionString::CK_Colon: | 
 |     return CXCompletionChunk_Colon; | 
 |   case CodeCompletionString::CK_SemiColon: | 
 |     return CXCompletionChunk_SemiColon; | 
 |   case CodeCompletionString::CK_Equal: | 
 |     return CXCompletionChunk_Equal; | 
 |   case CodeCompletionString::CK_HorizontalSpace: | 
 |     return CXCompletionChunk_HorizontalSpace; | 
 |   case CodeCompletionString::CK_VerticalSpace: | 
 |     return CXCompletionChunk_VerticalSpace; | 
 |   } | 
 |  | 
 |   llvm_unreachable("Invalid CompletionKind!"); | 
 | } | 
 |  | 
 | CXString clang_getCompletionChunkText(CXCompletionString completion_string, | 
 |                                       unsigned chunk_number) { | 
 |   CodeCompletionString *CCStr = (CodeCompletionString *)completion_string; | 
 |   if (!CCStr || chunk_number >= CCStr->size()) | 
 |     return cxstring::createNull(); | 
 |  | 
 |   switch ((*CCStr)[chunk_number].Kind) { | 
 |   case CodeCompletionString::CK_TypedText: | 
 |   case CodeCompletionString::CK_Text: | 
 |   case CodeCompletionString::CK_Placeholder: | 
 |   case CodeCompletionString::CK_CurrentParameter: | 
 |   case CodeCompletionString::CK_Informative: | 
 |   case CodeCompletionString::CK_LeftParen: | 
 |   case CodeCompletionString::CK_RightParen: | 
 |   case CodeCompletionString::CK_LeftBracket: | 
 |   case CodeCompletionString::CK_RightBracket: | 
 |   case CodeCompletionString::CK_LeftBrace: | 
 |   case CodeCompletionString::CK_RightBrace: | 
 |   case CodeCompletionString::CK_LeftAngle: | 
 |   case CodeCompletionString::CK_RightAngle: | 
 |   case CodeCompletionString::CK_Comma: | 
 |   case CodeCompletionString::CK_ResultType: | 
 |   case CodeCompletionString::CK_Colon: | 
 |   case CodeCompletionString::CK_SemiColon: | 
 |   case CodeCompletionString::CK_Equal: | 
 |   case CodeCompletionString::CK_HorizontalSpace: | 
 |   case CodeCompletionString::CK_VerticalSpace: | 
 |     return cxstring::createRef((*CCStr)[chunk_number].Text); | 
 |        | 
 |   case CodeCompletionString::CK_Optional: | 
 |     // Note: treated as an empty text block. | 
 |     return cxstring::createEmpty(); | 
 |   } | 
 |  | 
 |   llvm_unreachable("Invalid CodeCompletionString Kind!"); | 
 | } | 
 |  | 
 |  | 
 | CXCompletionString | 
 | clang_getCompletionChunkCompletionString(CXCompletionString completion_string, | 
 |                                          unsigned chunk_number) { | 
 |   CodeCompletionString *CCStr = (CodeCompletionString *)completion_string; | 
 |   if (!CCStr || chunk_number >= CCStr->size()) | 
 |     return nullptr; | 
 |  | 
 |   switch ((*CCStr)[chunk_number].Kind) { | 
 |   case CodeCompletionString::CK_TypedText: | 
 |   case CodeCompletionString::CK_Text: | 
 |   case CodeCompletionString::CK_Placeholder: | 
 |   case CodeCompletionString::CK_CurrentParameter: | 
 |   case CodeCompletionString::CK_Informative: | 
 |   case CodeCompletionString::CK_LeftParen: | 
 |   case CodeCompletionString::CK_RightParen: | 
 |   case CodeCompletionString::CK_LeftBracket: | 
 |   case CodeCompletionString::CK_RightBracket: | 
 |   case CodeCompletionString::CK_LeftBrace: | 
 |   case CodeCompletionString::CK_RightBrace: | 
 |   case CodeCompletionString::CK_LeftAngle: | 
 |   case CodeCompletionString::CK_RightAngle: | 
 |   case CodeCompletionString::CK_Comma: | 
 |   case CodeCompletionString::CK_ResultType: | 
 |   case CodeCompletionString::CK_Colon: | 
 |   case CodeCompletionString::CK_SemiColon: | 
 |   case CodeCompletionString::CK_Equal: | 
 |   case CodeCompletionString::CK_HorizontalSpace: | 
 |   case CodeCompletionString::CK_VerticalSpace: | 
 |     return nullptr; | 
 |  | 
 |   case CodeCompletionString::CK_Optional: | 
 |     // Note: treated as an empty text block. | 
 |     return (*CCStr)[chunk_number].Optional; | 
 |   } | 
 |  | 
 |   llvm_unreachable("Invalid CompletionKind!"); | 
 | } | 
 |  | 
 | unsigned clang_getNumCompletionChunks(CXCompletionString completion_string) { | 
 |   CodeCompletionString *CCStr = (CodeCompletionString *)completion_string; | 
 |   return CCStr? CCStr->size() : 0; | 
 | } | 
 |  | 
 | unsigned clang_getCompletionPriority(CXCompletionString completion_string) { | 
 |   CodeCompletionString *CCStr = (CodeCompletionString *)completion_string; | 
 |   return CCStr? CCStr->getPriority() : unsigned(CCP_Unlikely); | 
 | } | 
 |    | 
 | enum CXAvailabilityKind  | 
 | clang_getCompletionAvailability(CXCompletionString completion_string) { | 
 |   CodeCompletionString *CCStr = (CodeCompletionString *)completion_string; | 
 |   return CCStr? static_cast<CXAvailabilityKind>(CCStr->getAvailability()) | 
 |               : 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 ? cxstring::createRef(CCStr->getAnnotation(annotation_number)) | 
 |                : cxstring::createNull(); | 
 | } | 
 |  | 
 | CXString | 
 | clang_getCompletionParent(CXCompletionString completion_string, | 
 |                           CXCursorKind *kind) { | 
 |   if (kind) | 
 |     *kind = CXCursor_NotImplemented; | 
 |    | 
 |   CodeCompletionString *CCStr = (CodeCompletionString *)completion_string; | 
 |   if (!CCStr) | 
 |     return cxstring::createNull(); | 
 |    | 
 |   return cxstring::createRef(CCStr->getParentContextName()); | 
 | } | 
 |  | 
 | CXString | 
 | clang_getCompletionBriefComment(CXCompletionString completion_string) { | 
 |   CodeCompletionString *CCStr = (CodeCompletionString *)completion_string; | 
 |  | 
 |   if (!CCStr) | 
 |     return cxstring::createNull(); | 
 |  | 
 |   return cxstring::createRef(CCStr->getBriefComment()); | 
 | } | 
 |  | 
 | namespace { | 
 |  | 
 | /// The CXCodeCompleteResults structure we allocate internally; | 
 | /// the client only sees the initial CXCodeCompleteResults structure. | 
 | /// | 
 | /// Normally, clients of CXString shouldn't care whether or not a CXString is | 
 | /// managed by a pool or by explicitly malloc'ed memory.  But | 
 | /// AllocatedCXCodeCompleteResults outlives the CXTranslationUnit, so we can | 
 | /// not rely on the StringPool in the TU. | 
 | struct AllocatedCXCodeCompleteResults : public CXCodeCompleteResults { | 
 |   AllocatedCXCodeCompleteResults(IntrusiveRefCntPtr<FileManager> FileMgr); | 
 |   ~AllocatedCXCodeCompleteResults(); | 
 |    | 
 |   /// Diagnostics produced while performing code completion. | 
 |   SmallVector<StoredDiagnostic, 8> Diagnostics; | 
 |  | 
 |   /// Allocated API-exposed wrappters for Diagnostics. | 
 |   SmallVector<std::unique_ptr<CXStoredDiagnostic>, 8> DiagnosticsWrappers; | 
 |  | 
 |   IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts; | 
 |    | 
 |   /// Diag object | 
 |   IntrusiveRefCntPtr<DiagnosticsEngine> Diag; | 
 |    | 
 |   /// Language options used to adjust source locations. | 
 |   LangOptions LangOpts; | 
 |  | 
 |   /// File manager, used for diagnostics. | 
 |   IntrusiveRefCntPtr<FileManager> FileMgr; | 
 |  | 
 |   /// Source manager, used for diagnostics. | 
 |   IntrusiveRefCntPtr<SourceManager> SourceMgr; | 
 |    | 
 |   /// Temporary buffers that will be deleted once we have finished with | 
 |   /// the code-completion results. | 
 |   SmallVector<const llvm::MemoryBuffer *, 1> TemporaryBuffers; | 
 |    | 
 |   /// Allocator used to store globally cached code-completion results. | 
 |   std::shared_ptr<clang::GlobalCodeCompletionAllocator> | 
 |       CachedCompletionAllocator; | 
 |  | 
 |   /// Allocator used to store code completion results. | 
 |   std::shared_ptr<clang::GlobalCodeCompletionAllocator> CodeCompletionAllocator; | 
 |  | 
 |   /// Context under which completion occurred. | 
 |   enum clang::CodeCompletionContext::Kind ContextKind; | 
 |    | 
 |   /// A bitfield representing the acceptable completions for the | 
 |   /// current context. | 
 |   unsigned long long Contexts; | 
 |    | 
 |   /// The kind of the container for the current context for completions. | 
 |   enum CXCursorKind ContainerKind; | 
 |  | 
 |   /// The USR of the container for the current context for completions. | 
 |   std::string ContainerUSR; | 
 |  | 
 |   /// a boolean value indicating whether there is complete information | 
 |   /// about the container | 
 |   unsigned ContainerIsIncomplete; | 
 |    | 
 |   /// A string containing the Objective-C selector entered thus far for a | 
 |   /// message send. | 
 |   std::string Selector; | 
 |  | 
 |   /// Vector of fix-its for each completion result that *must* be applied | 
 |   /// before that result for the corresponding completion item. | 
 |   std::vector<std::vector<FixItHint>> FixItsVector; | 
 | }; | 
 |  | 
 | } // end anonymous namespace | 
 |  | 
 | unsigned clang_getCompletionNumFixIts(CXCodeCompleteResults *results, | 
 |                                       unsigned completion_index) { | 
 |   AllocatedCXCodeCompleteResults *allocated_results = (AllocatedCXCodeCompleteResults *)results; | 
 |  | 
 |   if (!allocated_results || allocated_results->FixItsVector.size() <= completion_index) | 
 |     return 0; | 
 |  | 
 |   return static_cast<unsigned>(allocated_results->FixItsVector[completion_index].size()); | 
 | } | 
 |  | 
 | CXString clang_getCompletionFixIt(CXCodeCompleteResults *results, | 
 |                                   unsigned completion_index, | 
 |                                   unsigned fixit_index, | 
 |                                   CXSourceRange *replacement_range) { | 
 |   AllocatedCXCodeCompleteResults *allocated_results = (AllocatedCXCodeCompleteResults *)results; | 
 |  | 
 |   if (!allocated_results || allocated_results->FixItsVector.size() <= completion_index) { | 
 |     if (replacement_range) | 
 |       *replacement_range = clang_getNullRange(); | 
 |     return cxstring::createNull(); | 
 |   } | 
 |  | 
 |   ArrayRef<FixItHint> FixIts = allocated_results->FixItsVector[completion_index]; | 
 |   if (FixIts.size() <= fixit_index) { | 
 |     if (replacement_range) | 
 |       *replacement_range = clang_getNullRange(); | 
 |     return cxstring::createNull(); | 
 |   } | 
 |  | 
 |   const FixItHint &FixIt = FixIts[fixit_index]; | 
 |   if (replacement_range) { | 
 |     *replacement_range = cxloc::translateSourceRange( | 
 |         *allocated_results->SourceMgr, allocated_results->LangOpts, | 
 |         FixIt.RemoveRange); | 
 |   } | 
 |  | 
 |   return cxstring::createRef(FixIt.CodeToInsert.c_str()); | 
 | } | 
 |  | 
 | /// Tracks the number of code-completion result objects that are  | 
 | /// currently active. | 
 | /// | 
 | /// Used for debugging purposes only. | 
 | static std::atomic<unsigned> CodeCompletionResultObjects; | 
 |  | 
 | AllocatedCXCodeCompleteResults::AllocatedCXCodeCompleteResults( | 
 |     IntrusiveRefCntPtr<FileManager> FileMgr) | 
 |     : CXCodeCompleteResults(), DiagOpts(new DiagnosticOptions), | 
 |       Diag(new DiagnosticsEngine( | 
 |           IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs), &*DiagOpts)), | 
 |       FileMgr(std::move(FileMgr)), | 
 |       SourceMgr(new SourceManager(*Diag, *this->FileMgr)), | 
 |       CodeCompletionAllocator( | 
 |           std::make_shared<clang::GlobalCodeCompletionAllocator>()), | 
 |       Contexts(CXCompletionContext_Unknown), | 
 |       ContainerKind(CXCursor_InvalidCode), ContainerIsIncomplete(1) { | 
 |   if (getenv("LIBCLANG_OBJTRACKING")) | 
 |     fprintf(stderr, "+++ %u completion results\n", | 
 |             ++CodeCompletionResultObjects); | 
 | } | 
 |    | 
 | AllocatedCXCodeCompleteResults::~AllocatedCXCodeCompleteResults() { | 
 |   delete [] Results; | 
 |  | 
 |   for (unsigned I = 0, N = TemporaryBuffers.size(); I != N; ++I) | 
 |     delete TemporaryBuffers[I]; | 
 |  | 
 |   if (getenv("LIBCLANG_OBJTRACKING")) | 
 |     fprintf(stderr, "--- %u completion results\n", | 
 |             --CodeCompletionResultObjects); | 
 | } | 
 |  | 
 | static unsigned long long getContextsForContextKind( | 
 |                                           enum CodeCompletionContext::Kind kind,  | 
 |                                                     Sema &S) { | 
 |   unsigned long long contexts = 0; | 
 |   switch (kind) { | 
 |     case CodeCompletionContext::CCC_OtherWithMacros: { | 
 |       //We can allow macros here, but we don't know what else is permissible | 
 |       //So we'll say the only thing permissible are macros | 
 |       contexts = CXCompletionContext_MacroName; | 
 |       break; | 
 |     } | 
 |     case CodeCompletionContext::CCC_TopLevel: | 
 |     case CodeCompletionContext::CCC_ObjCIvarList: | 
 |     case CodeCompletionContext::CCC_ClassStructUnion: | 
 |     case CodeCompletionContext::CCC_Type: { | 
 |       contexts = CXCompletionContext_AnyType |  | 
 |                  CXCompletionContext_ObjCInterface; | 
 |       if (S.getLangOpts().CPlusPlus) { | 
 |         contexts |= CXCompletionContext_EnumTag | | 
 |                     CXCompletionContext_UnionTag | | 
 |                     CXCompletionContext_StructTag | | 
 |                     CXCompletionContext_ClassTag | | 
 |                     CXCompletionContext_NestedNameSpecifier; | 
 |       } | 
 |       break; | 
 |     } | 
 |     case CodeCompletionContext::CCC_Statement: { | 
 |       contexts = CXCompletionContext_AnyType | | 
 |                  CXCompletionContext_ObjCInterface | | 
 |                  CXCompletionContext_AnyValue; | 
 |       if (S.getLangOpts().CPlusPlus) { | 
 |         contexts |= CXCompletionContext_EnumTag | | 
 |                     CXCompletionContext_UnionTag | | 
 |                     CXCompletionContext_StructTag | | 
 |                     CXCompletionContext_ClassTag | | 
 |                     CXCompletionContext_NestedNameSpecifier; | 
 |       } | 
 |       break; | 
 |     } | 
 |     case CodeCompletionContext::CCC_Expression: { | 
 |       contexts = CXCompletionContext_AnyValue; | 
 |       if (S.getLangOpts().CPlusPlus) { | 
 |         contexts |= CXCompletionContext_AnyType | | 
 |                     CXCompletionContext_ObjCInterface | | 
 |                     CXCompletionContext_EnumTag | | 
 |                     CXCompletionContext_UnionTag | | 
 |                     CXCompletionContext_StructTag | | 
 |                     CXCompletionContext_ClassTag | | 
 |                     CXCompletionContext_NestedNameSpecifier; | 
 |       } | 
 |       break; | 
 |     } | 
 |     case CodeCompletionContext::CCC_ObjCMessageReceiver: { | 
 |       contexts = CXCompletionContext_ObjCObjectValue | | 
 |                  CXCompletionContext_ObjCSelectorValue | | 
 |                  CXCompletionContext_ObjCInterface; | 
 |       if (S.getLangOpts().CPlusPlus) { | 
 |         contexts |= CXCompletionContext_CXXClassTypeValue | | 
 |                     CXCompletionContext_AnyType | | 
 |                     CXCompletionContext_EnumTag | | 
 |                     CXCompletionContext_UnionTag | | 
 |                     CXCompletionContext_StructTag | | 
 |                     CXCompletionContext_ClassTag | | 
 |                     CXCompletionContext_NestedNameSpecifier; | 
 |       } | 
 |       break; | 
 |     } | 
 |     case CodeCompletionContext::CCC_DotMemberAccess: { | 
 |       contexts = CXCompletionContext_DotMemberAccess; | 
 |       break; | 
 |     } | 
 |     case CodeCompletionContext::CCC_ArrowMemberAccess: { | 
 |       contexts = CXCompletionContext_ArrowMemberAccess; | 
 |       break; | 
 |     } | 
 |     case CodeCompletionContext::CCC_ObjCPropertyAccess: { | 
 |       contexts = CXCompletionContext_ObjCPropertyAccess; | 
 |       break; | 
 |     } | 
 |     case CodeCompletionContext::CCC_EnumTag: { | 
 |       contexts = CXCompletionContext_EnumTag | | 
 |                  CXCompletionContext_NestedNameSpecifier; | 
 |       break; | 
 |     } | 
 |     case CodeCompletionContext::CCC_UnionTag: { | 
 |       contexts = CXCompletionContext_UnionTag | | 
 |                  CXCompletionContext_NestedNameSpecifier; | 
 |       break; | 
 |     } | 
 |     case CodeCompletionContext::CCC_ClassOrStructTag: { | 
 |       contexts = CXCompletionContext_StructTag | | 
 |                  CXCompletionContext_ClassTag | | 
 |                  CXCompletionContext_NestedNameSpecifier; | 
 |       break; | 
 |     } | 
 |     case CodeCompletionContext::CCC_ObjCProtocolName: { | 
 |       contexts = CXCompletionContext_ObjCProtocol; | 
 |       break; | 
 |     } | 
 |     case CodeCompletionContext::CCC_Namespace: { | 
 |       contexts = CXCompletionContext_Namespace; | 
 |       break; | 
 |     } | 
 |     case CodeCompletionContext::CCC_SymbolOrNewName: | 
 |     case CodeCompletionContext::CCC_Symbol: { | 
 |       contexts = CXCompletionContext_NestedNameSpecifier; | 
 |       break; | 
 |     } | 
 |     case CodeCompletionContext::CCC_MacroNameUse: { | 
 |       contexts = CXCompletionContext_MacroName; | 
 |       break; | 
 |     } | 
 |     case CodeCompletionContext::CCC_NaturalLanguage: { | 
 |       contexts = CXCompletionContext_NaturalLanguage; | 
 |       break; | 
 |     } | 
 |     case CodeCompletionContext::CCC_IncludedFile: { | 
 |       contexts = CXCompletionContext_IncludedFile; | 
 |       break; | 
 |     } | 
 |     case CodeCompletionContext::CCC_SelectorName: { | 
 |       contexts = CXCompletionContext_ObjCSelectorName; | 
 |       break; | 
 |     } | 
 |     case CodeCompletionContext::CCC_ParenthesizedExpression: { | 
 |       contexts = CXCompletionContext_AnyType | | 
 |                  CXCompletionContext_ObjCInterface | | 
 |                  CXCompletionContext_AnyValue; | 
 |       if (S.getLangOpts().CPlusPlus) { | 
 |         contexts |= CXCompletionContext_EnumTag | | 
 |                     CXCompletionContext_UnionTag | | 
 |                     CXCompletionContext_StructTag | | 
 |                     CXCompletionContext_ClassTag | | 
 |                     CXCompletionContext_NestedNameSpecifier; | 
 |       } | 
 |       break; | 
 |     } | 
 |     case CodeCompletionContext::CCC_ObjCInstanceMessage: { | 
 |       contexts = CXCompletionContext_ObjCInstanceMessage; | 
 |       break; | 
 |     } | 
 |     case CodeCompletionContext::CCC_ObjCClassMessage: { | 
 |       contexts = CXCompletionContext_ObjCClassMessage; | 
 |       break; | 
 |     } | 
 |     case CodeCompletionContext::CCC_ObjCInterfaceName: { | 
 |       contexts = CXCompletionContext_ObjCInterface; | 
 |       break; | 
 |     } | 
 |     case CodeCompletionContext::CCC_ObjCCategoryName: { | 
 |       contexts = CXCompletionContext_ObjCCategory; | 
 |       break; | 
 |     } | 
 |     case CodeCompletionContext::CCC_Other: | 
 |     case CodeCompletionContext::CCC_ObjCInterface: | 
 |     case CodeCompletionContext::CCC_ObjCImplementation: | 
 |     case CodeCompletionContext::CCC_NewName: | 
 |     case CodeCompletionContext::CCC_MacroName: | 
 |     case CodeCompletionContext::CCC_PreprocessorExpression: | 
 |     case CodeCompletionContext::CCC_PreprocessorDirective: | 
 |     case CodeCompletionContext::CCC_TypeQualifiers: { | 
 |       //Only Clang results should be accepted, so we'll set all of the other | 
 |       //context bits to 0 (i.e. the empty set) | 
 |       contexts = CXCompletionContext_Unexposed; | 
 |       break; | 
 |     } | 
 |     case CodeCompletionContext::CCC_Recovery: { | 
 |       //We don't know what the current context is, so we'll return unknown | 
 |       //This is the equivalent of setting all of the other context bits | 
 |       contexts = CXCompletionContext_Unknown; | 
 |       break; | 
 |     } | 
 |   } | 
 |   return contexts; | 
 | } | 
 |  | 
 | namespace { | 
 |   class CaptureCompletionResults : public CodeCompleteConsumer { | 
 |     AllocatedCXCodeCompleteResults &AllocatedResults; | 
 |     CodeCompletionTUInfo CCTUInfo; | 
 |     SmallVector<CXCompletionResult, 16> StoredResults; | 
 |     CXTranslationUnit *TU; | 
 |   public: | 
 |     CaptureCompletionResults(const CodeCompleteOptions &Opts, | 
 |                              AllocatedCXCodeCompleteResults &Results, | 
 |                              CXTranslationUnit *TranslationUnit) | 
 |         : CodeCompleteConsumer(Opts), AllocatedResults(Results), | 
 |           CCTUInfo(Results.CodeCompletionAllocator), TU(TranslationUnit) {} | 
 |     ~CaptureCompletionResults() override { Finish(); } | 
 |  | 
 |     void ProcessCodeCompleteResults(Sema &S,  | 
 |                                     CodeCompletionContext Context, | 
 |                                     CodeCompletionResult *Results, | 
 |                                     unsigned NumResults) override { | 
 |       StoredResults.reserve(StoredResults.size() + NumResults); | 
 |       if (includeFixIts()) | 
 |         AllocatedResults.FixItsVector.reserve(NumResults); | 
 |       for (unsigned I = 0; I != NumResults; ++I) { | 
 |         CodeCompletionString *StoredCompletion | 
 |           = Results[I].CreateCodeCompletionString(S, Context, getAllocator(), | 
 |                                                   getCodeCompletionTUInfo(), | 
 |                                                   includeBriefComments()); | 
 |          | 
 |         CXCompletionResult R; | 
 |         R.CursorKind = Results[I].CursorKind; | 
 |         R.CompletionString = StoredCompletion; | 
 |         StoredResults.push_back(R); | 
 |         if (includeFixIts()) | 
 |           AllocatedResults.FixItsVector.emplace_back(std::move(Results[I].FixIts)); | 
 |       } | 
 |  | 
 |       enum CodeCompletionContext::Kind contextKind = Context.getKind(); | 
 |        | 
 |       AllocatedResults.ContextKind = contextKind; | 
 |       AllocatedResults.Contexts = getContextsForContextKind(contextKind, S); | 
 |        | 
 |       AllocatedResults.Selector = ""; | 
 |       ArrayRef<IdentifierInfo *> SelIdents = Context.getSelIdents(); | 
 |       for (ArrayRef<IdentifierInfo *>::iterator I = SelIdents.begin(), | 
 |                                                 E = SelIdents.end(); | 
 |            I != E; ++I) { | 
 |         if (IdentifierInfo *selIdent = *I) | 
 |           AllocatedResults.Selector += selIdent->getName(); | 
 |         AllocatedResults.Selector += ":"; | 
 |       } | 
 |        | 
 |       QualType baseType = Context.getBaseType(); | 
 |       NamedDecl *D = nullptr; | 
 |  | 
 |       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 != nullptr) { | 
 |         CXCursor cursor = cxcursor::MakeCXCursor(D, *TU); | 
 |  | 
 |         AllocatedResults.ContainerKind = clang_getCursorKind(cursor); | 
 |  | 
 |         CXString CursorUSR = clang_getCursorUSR(cursor); | 
 |         AllocatedResults.ContainerUSR = clang_getCString(CursorUSR); | 
 |         clang_disposeString(CursorUSR); | 
 |  | 
 |         const Type *type = baseType.getTypePtrOrNull(); | 
 |         if (type) { | 
 |           AllocatedResults.ContainerIsIncomplete = type->isIncompleteType(); | 
 |         } | 
 |         else { | 
 |           AllocatedResults.ContainerIsIncomplete = 1; | 
 |         } | 
 |       } | 
 |       else { | 
 |         AllocatedResults.ContainerKind = CXCursor_InvalidCode; | 
 |         AllocatedResults.ContainerUSR.clear(); | 
 |         AllocatedResults.ContainerIsIncomplete = 1; | 
 |       } | 
 |     } | 
 |  | 
 |     void ProcessOverloadCandidates(Sema &S, unsigned CurrentArg, | 
 |                                    OverloadCandidate *Candidates, | 
 |                                    unsigned NumCandidates, | 
 |                                    SourceLocation OpenParLoc) override { | 
 |       StoredResults.reserve(StoredResults.size() + NumCandidates); | 
 |       for (unsigned I = 0; I != NumCandidates; ++I) { | 
 |         CodeCompletionString *StoredCompletion | 
 |           = Candidates[I].CreateSignatureString(CurrentArg, S, getAllocator(), | 
 |                                                 getCodeCompletionTUInfo(), | 
 |                                                 includeBriefComments()); | 
 |          | 
 |         CXCompletionResult R; | 
 |         R.CursorKind = CXCursor_OverloadCandidate; | 
 |         R.CompletionString = StoredCompletion; | 
 |         StoredResults.push_back(R); | 
 |       } | 
 |     } | 
 |  | 
 |     CodeCompletionAllocator &getAllocator() override { | 
 |       return *AllocatedResults.CodeCompletionAllocator; | 
 |     } | 
 |  | 
 |     CodeCompletionTUInfo &getCodeCompletionTUInfo() override { return CCTUInfo;} | 
 |  | 
 |   private: | 
 |     void Finish() { | 
 |       AllocatedResults.Results = new CXCompletionResult [StoredResults.size()]; | 
 |       AllocatedResults.NumResults = StoredResults.size(); | 
 |       std::memcpy(AllocatedResults.Results, StoredResults.data(),  | 
 |                   StoredResults.size() * sizeof(CXCompletionResult)); | 
 |       StoredResults.clear(); | 
 |     } | 
 |   }; | 
 | } | 
 |  | 
 | static CXCodeCompleteResults * | 
 | clang_codeCompleteAt_Impl(CXTranslationUnit TU, const char *complete_filename, | 
 |                           unsigned complete_line, unsigned complete_column, | 
 |                           ArrayRef<CXUnsavedFile> unsaved_files, | 
 |                           unsigned options) { | 
 |   bool IncludeBriefComments = options & CXCodeComplete_IncludeBriefComments; | 
 |   bool SkipPreamble = options & CXCodeComplete_SkipPreamble; | 
 |   bool IncludeFixIts = options & CXCodeComplete_IncludeCompletionsWithFixIts; | 
 |  | 
 | #ifdef UDP_CODE_COMPLETION_LOGGER | 
 | #ifdef UDP_CODE_COMPLETION_LOGGER_PORT | 
 |   const llvm::TimeRecord &StartTime =  llvm::TimeRecord::getCurrentTime(); | 
 | #endif | 
 | #endif | 
 |   bool EnableLogging = getenv("LIBCLANG_CODE_COMPLETION_LOGGING") != nullptr; | 
 |  | 
 |   if (cxtu::isNotUsableTU(TU)) { | 
 |     LOG_BAD_TU(TU); | 
 |     return nullptr; | 
 |   } | 
 |  | 
 |   ASTUnit *AST = cxtu::getASTUnit(TU); | 
 |   if (!AST) | 
 |     return nullptr; | 
 |  | 
 |   CIndexer *CXXIdx = TU->CIdx; | 
 |   if (CXXIdx->isOptEnabled(CXGlobalOpt_ThreadBackgroundPriorityForEditing)) | 
 |     setThreadBackgroundPriority(); | 
 |  | 
 |   ASTUnit::ConcurrencyCheck Check(*AST); | 
 |  | 
 |   // Perform the remapping of source files. | 
 |   SmallVector<ASTUnit::RemappedFile, 4> RemappedFiles; | 
 |  | 
 |   for (auto &UF : unsaved_files) { | 
 |     std::unique_ptr<llvm::MemoryBuffer> MB = | 
 |         llvm::MemoryBuffer::getMemBufferCopy(getContents(UF), UF.Filename); | 
 |     RemappedFiles.push_back(std::make_pair(UF.Filename, MB.release())); | 
 |   } | 
 |  | 
 |   if (EnableLogging) { | 
 |     // FIXME: Add logging. | 
 |   } | 
 |  | 
 |   // Parse the resulting source file to find code-completion results. | 
 |   AllocatedCXCodeCompleteResults *Results = new AllocatedCXCodeCompleteResults( | 
 |       &AST->getFileManager()); | 
 |   Results->Results = nullptr; | 
 |   Results->NumResults = 0; | 
 |    | 
 |   // Create a code-completion consumer to capture the results. | 
 |   CodeCompleteOptions Opts; | 
 |   Opts.IncludeBriefComments = IncludeBriefComments; | 
 |   Opts.LoadExternal = !SkipPreamble; | 
 |   Opts.IncludeFixIts = IncludeFixIts; | 
 |   CaptureCompletionResults Capture(Opts, *Results, &TU); | 
 |  | 
 |   // Perform completion. | 
 |   std::vector<const char *> CArgs; | 
 |   for (const auto &Arg : TU->Arguments) | 
 |     CArgs.push_back(Arg.c_str()); | 
 |   std::string CompletionInvocation = | 
 |       llvm::formatv("-code-completion-at={0}:{1}:{2}", complete_filename, | 
 |                     complete_line, complete_column) | 
 |           .str(); | 
 |   LibclangInvocationReporter InvocationReporter( | 
 |       *CXXIdx, LibclangInvocationReporter::OperationKind::CompletionOperation, | 
 |       TU->ParsingOptions, CArgs, CompletionInvocation, unsaved_files); | 
 |   AST->CodeComplete(complete_filename, complete_line, complete_column, | 
 |                     RemappedFiles, (options & CXCodeComplete_IncludeMacros), | 
 |                     (options & CXCodeComplete_IncludeCodePatterns), | 
 |                     IncludeBriefComments, Capture, | 
 |                     CXXIdx->getPCHContainerOperations(), *Results->Diag, | 
 |                     Results->LangOpts, *Results->SourceMgr, *Results->FileMgr, | 
 |                     Results->Diagnostics, Results->TemporaryBuffers); | 
 |  | 
 |   Results->DiagnosticsWrappers.resize(Results->Diagnostics.size()); | 
 |  | 
 |   // Keep a reference to the allocator used for cached global completions, so | 
 |   // that we can be sure that the memory used by our code completion strings | 
 |   // doesn't get freed due to subsequent reparses (while the code completion | 
 |   // results are still active). | 
 |   Results->CachedCompletionAllocator = AST->getCachedCompletionAllocator(); | 
 |  | 
 |    | 
 |  | 
 | #ifdef UDP_CODE_COMPLETION_LOGGER | 
 | #ifdef UDP_CODE_COMPLETION_LOGGER_PORT | 
 |   const llvm::TimeRecord &EndTime =  llvm::TimeRecord::getCurrentTime(); | 
 |   SmallString<256> LogResult; | 
 |   llvm::raw_svector_ostream os(LogResult); | 
 |  | 
 |   // Figure out the language and whether or not it uses PCH. | 
 |   const char *lang = 0; | 
 |   bool usesPCH = false; | 
 |  | 
 |   for (std::vector<const char*>::iterator I = argv.begin(), E = argv.end(); | 
 |        I != E; ++I) { | 
 |     if (*I == 0) | 
 |       continue; | 
 |     if (strcmp(*I, "-x") == 0) { | 
 |       if (I + 1 != E) { | 
 |         lang = *(++I); | 
 |         continue; | 
 |       } | 
 |     } | 
 |     else if (strcmp(*I, "-include") == 0) { | 
 |       if (I+1 != E) { | 
 |         const char *arg = *(++I); | 
 |         SmallString<512> pchName; | 
 |         { | 
 |           llvm::raw_svector_ostream os(pchName); | 
 |           os << arg << ".pth"; | 
 |         } | 
 |         pchName.push_back('\0'); | 
 |         llvm::sys::fs::file_status stat_results; | 
 |         if (!llvm::sys::fs::status(pchName, stat_results)) | 
 |           usesPCH = true; | 
 |         continue; | 
 |       } | 
 |     } | 
 |   } | 
 |  | 
 |   os << "{ "; | 
 |   os << "\"wall\": " << (EndTime.getWallTime() - StartTime.getWallTime()); | 
 |   os << ", \"numRes\": " << Results->NumResults; | 
 |   os << ", \"diags\": " << Results->Diagnostics.size(); | 
 |   os << ", \"pch\": " << (usesPCH ? "true" : "false"); | 
 |   os << ", \"lang\": \"" << (lang ? lang : "<unknown>") << '"'; | 
 |   const char *name = getlogin(); | 
 |   os << ", \"user\": \"" << (name ? name : "unknown") << '"'; | 
 |   os << ", \"clangVer\": \"" << getClangFullVersion() << '"'; | 
 |   os << " }"; | 
 |  | 
 |   StringRef res = os.str(); | 
 |   if (res.size() > 0) { | 
 |     do { | 
 |       // Setup the UDP socket. | 
 |       struct sockaddr_in servaddr; | 
 |       bzero(&servaddr, sizeof(servaddr)); | 
 |       servaddr.sin_family = AF_INET; | 
 |       servaddr.sin_port = htons(UDP_CODE_COMPLETION_LOGGER_PORT); | 
 |       if (inet_pton(AF_INET, UDP_CODE_COMPLETION_LOGGER, | 
 |                     &servaddr.sin_addr) <= 0) | 
 |         break; | 
 |  | 
 |       int sockfd = socket(AF_INET, SOCK_DGRAM, 0); | 
 |       if (sockfd < 0) | 
 |         break; | 
 |  | 
 |       sendto(sockfd, res.data(), res.size(), 0, | 
 |              (struct sockaddr *)&servaddr, sizeof(servaddr)); | 
 |       close(sockfd); | 
 |     } | 
 |     while (false); | 
 |   } | 
 | #endif | 
 | #endif | 
 |   return Results; | 
 | } | 
 |  | 
 | CXCodeCompleteResults *clang_codeCompleteAt(CXTranslationUnit TU, | 
 |                                             const char *complete_filename, | 
 |                                             unsigned complete_line, | 
 |                                             unsigned complete_column, | 
 |                                             struct CXUnsavedFile *unsaved_files, | 
 |                                             unsigned num_unsaved_files, | 
 |                                             unsigned options) { | 
 |   LOG_FUNC_SECTION { | 
 |     *Log << TU << ' ' | 
 |          << complete_filename << ':' << complete_line << ':' << complete_column; | 
 |   } | 
 |  | 
 |   if (num_unsaved_files && !unsaved_files) | 
 |     return nullptr; | 
 |  | 
 |   CXCodeCompleteResults *result; | 
 |   auto CodeCompleteAtImpl = [=, &result]() { | 
 |     result = clang_codeCompleteAt_Impl( | 
 |         TU, complete_filename, complete_line, complete_column, | 
 |         llvm::makeArrayRef(unsaved_files, num_unsaved_files), options); | 
 |   }; | 
 |  | 
 |   llvm::CrashRecoveryContext CRC; | 
 |  | 
 |   if (!RunSafely(CRC, CodeCompleteAtImpl)) { | 
 |     fprintf(stderr, "libclang: crash detected in code completion\n"); | 
 |     cxtu::getASTUnit(TU)->setUnsafeToFree(true); | 
 |     return nullptr; | 
 |   } else if (getenv("LIBCLANG_RESOURCE_USAGE")) | 
 |     PrintLibclangResourceUsage(TU); | 
 |  | 
 |   return result; | 
 | } | 
 |  | 
 | unsigned clang_defaultCodeCompleteOptions(void) { | 
 |   return CXCodeComplete_IncludeMacros; | 
 | } | 
 |  | 
 | void clang_disposeCodeCompleteResults(CXCodeCompleteResults *ResultsIn) { | 
 |   if (!ResultsIn) | 
 |     return; | 
 |  | 
 |   AllocatedCXCodeCompleteResults *Results | 
 |     = static_cast<AllocatedCXCodeCompleteResults*>(ResultsIn); | 
 |   delete Results; | 
 | } | 
 |    | 
 | unsigned  | 
 | clang_codeCompleteGetNumDiagnostics(CXCodeCompleteResults *ResultsIn) { | 
 |   AllocatedCXCodeCompleteResults *Results | 
 |     = static_cast<AllocatedCXCodeCompleteResults*>(ResultsIn); | 
 |   if (!Results) | 
 |     return 0; | 
 |  | 
 |   return Results->Diagnostics.size(); | 
 | } | 
 |  | 
 | CXDiagnostic  | 
 | clang_codeCompleteGetDiagnostic(CXCodeCompleteResults *ResultsIn, | 
 |                                 unsigned Index) { | 
 |   AllocatedCXCodeCompleteResults *Results | 
 |     = static_cast<AllocatedCXCodeCompleteResults*>(ResultsIn); | 
 |   if (!Results || Index >= Results->Diagnostics.size()) | 
 |     return nullptr; | 
 |  | 
 |   CXStoredDiagnostic *Diag = Results->DiagnosticsWrappers[Index].get(); | 
 |   if (!Diag) | 
 |     Diag = (Results->DiagnosticsWrappers[Index] = | 
 |                 std::make_unique<CXStoredDiagnostic>( | 
 |                     Results->Diagnostics[Index], Results->LangOpts)) | 
 |                .get(); | 
 |   return Diag; | 
 | } | 
 |  | 
 | unsigned long long | 
 | clang_codeCompleteGetContexts(CXCodeCompleteResults *ResultsIn) { | 
 |   AllocatedCXCodeCompleteResults *Results | 
 |     = static_cast<AllocatedCXCodeCompleteResults*>(ResultsIn); | 
 |   if (!Results) | 
 |     return 0; | 
 |    | 
 |   return Results->Contexts; | 
 | } | 
 |  | 
 | enum CXCursorKind clang_codeCompleteGetContainerKind( | 
 |                                                CXCodeCompleteResults *ResultsIn, | 
 |                                                      unsigned *IsIncomplete) { | 
 |   AllocatedCXCodeCompleteResults *Results = | 
 |     static_cast<AllocatedCXCodeCompleteResults *>(ResultsIn); | 
 |   if (!Results) | 
 |     return CXCursor_InvalidCode; | 
 |  | 
 |   if (IsIncomplete != nullptr) { | 
 |     *IsIncomplete = Results->ContainerIsIncomplete; | 
 |   } | 
 |    | 
 |   return Results->ContainerKind; | 
 | } | 
 |    | 
 | CXString clang_codeCompleteGetContainerUSR(CXCodeCompleteResults *ResultsIn) { | 
 |   AllocatedCXCodeCompleteResults *Results = | 
 |     static_cast<AllocatedCXCodeCompleteResults *>(ResultsIn); | 
 |   if (!Results) | 
 |     return cxstring::createEmpty(); | 
 |  | 
 |   return cxstring::createRef(Results->ContainerUSR.c_str()); | 
 | } | 
 |  | 
 |    | 
 | CXString clang_codeCompleteGetObjCSelector(CXCodeCompleteResults *ResultsIn) { | 
 |   AllocatedCXCodeCompleteResults *Results = | 
 |     static_cast<AllocatedCXCodeCompleteResults *>(ResultsIn); | 
 |   if (!Results) | 
 |     return cxstring::createEmpty(); | 
 |    | 
 |   return cxstring::createDup(Results->Selector); | 
 | } | 
 |    | 
 | /// Simple utility function that appends a \p New string to the given | 
 | /// \p Old string, using the \p Buffer for storage. | 
 | /// | 
 | /// \param Old The string to which we are appending. This parameter will be | 
 | /// updated to reflect the complete string. | 
 | /// | 
 | /// | 
 | /// \param New The string to append to \p Old. | 
 | /// | 
 | /// \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(StringRef &Old, StringRef New, | 
 |                            SmallString<256> &Buffer) { | 
 |   if (Old.empty()) { | 
 |     Old = New; | 
 |     return; | 
 |   } | 
 |    | 
 |   if (Buffer.empty()) | 
 |     Buffer.append(Old.begin(), Old.end()); | 
 |   Buffer.append(New.begin(), New.end()); | 
 |   Old = Buffer.str(); | 
 | } | 
 |  | 
 | /// Get the typed-text blocks from the given code-completion string | 
 | /// and return them as a single string. | 
 | /// | 
 | /// \param String The code-completion string whose typed-text blocks will be | 
 | /// concatenated. | 
 | /// | 
 | /// \param Buffer A buffer used for storage of the completed name. | 
 | static StringRef GetTypedName(CodeCompletionString *String, | 
 |                                     SmallString<256> &Buffer) { | 
 |   StringRef Result; | 
 |   for (CodeCompletionString::iterator C = String->begin(), CEnd = String->end(); | 
 |        C != CEnd; ++C) { | 
 |     if (C->Kind == CodeCompletionString::CK_TypedText) | 
 |       AppendToString(Result, C->Text, Buffer); | 
 |   } | 
 |    | 
 |   return Result; | 
 | } | 
 |  | 
 | namespace { | 
 |   struct OrderCompletionResults { | 
 |     bool operator()(const CXCompletionResult &XR,  | 
 |                     const CXCompletionResult &YR) const { | 
 |       CodeCompletionString *X | 
 |         = (CodeCompletionString *)XR.CompletionString; | 
 |       CodeCompletionString *Y | 
 |         = (CodeCompletionString *)YR.CompletionString; | 
 |  | 
 |       SmallString<256> XBuffer; | 
 |       StringRef XText = GetTypedName(X, XBuffer); | 
 |       SmallString<256> YBuffer; | 
 |       StringRef YText = GetTypedName(Y, YBuffer); | 
 |        | 
 |       if (XText.empty() || YText.empty()) | 
 |         return !XText.empty(); | 
 |              | 
 |       int result = XText.compare_lower(YText); | 
 |       if (result < 0) | 
 |         return true; | 
 |       if (result > 0) | 
 |         return false; | 
 |        | 
 |       result = XText.compare(YText); | 
 |       return result < 0; | 
 |     } | 
 |   }; | 
 | } | 
 |  | 
 | void clang_sortCodeCompletionResults(CXCompletionResult *Results, | 
 |                                      unsigned NumResults) { | 
 |   std::stable_sort(Results, Results + NumResults, OrderCompletionResults()); | 
 | } |