[cfe-commits] r90209 - in /cfe/trunk: include/clang/Basic/DiagnosticFrontendKinds.td include/clang/Sema/CodeCompleteConsumer.h lib/Frontend/CompilerInstance.cpp lib/Sema/CodeCompleteConsumer.cpp lib/Sema/SemaCodeComplete.cpp tools/CIndex/CIndex.cpp

Douglas Gregor dgregor at apple.com
Mon Nov 30 21:55:21 PST 2009


Author: dgregor
Date: Mon Nov 30 23:55:20 2009
New Revision: 90209

URL: http://llvm.org/viewvc/llvm-project?rev=90209&view=rev
Log:
Switch the clang-to-CIndex interface for code-completion to a binary format, for a massive speedup

Modified:
    cfe/trunk/include/clang/Basic/DiagnosticFrontendKinds.td
    cfe/trunk/include/clang/Sema/CodeCompleteConsumer.h
    cfe/trunk/lib/Frontend/CompilerInstance.cpp
    cfe/trunk/lib/Sema/CodeCompleteConsumer.cpp
    cfe/trunk/lib/Sema/SemaCodeComplete.cpp
    cfe/trunk/tools/CIndex/CIndex.cpp

Modified: cfe/trunk/include/clang/Basic/DiagnosticFrontendKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticFrontendKinds.td?rev=90209&r1=90208&r2=90209&view=diff

==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticFrontendKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticFrontendKinds.td Mon Nov 30 23:55:20 2009
@@ -17,6 +17,8 @@
 def err_fe_invalid_ast_action : Error<"invalid action for AST input">, DefaultFatal;
 def err_fe_invalid_code_complete_file
   : Error<"cannot locate code-completion file %0">, DefaultFatal;
+def err_fe_stdout_binary : Error<"unable to change standard output to binary">,
+  DefaultFatal;
 def err_fe_dependency_file_requires_MT : Error<
     "-dependency-file requires at least one -MT option">;
 def err_fe_incompatible_options : Error<

Modified: cfe/trunk/include/clang/Sema/CodeCompleteConsumer.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/CodeCompleteConsumer.h?rev=90209&r1=90208&r2=90209&view=diff

==============================================================================
--- cfe/trunk/include/clang/Sema/CodeCompleteConsumer.h (original)
+++ cfe/trunk/include/clang/Sema/CodeCompleteConsumer.h Mon Nov 30 23:55:20 2009
@@ -209,7 +209,8 @@
   void Serialize(llvm::raw_ostream &OS) const;
   
   /// \brief Deserialize a code-completion string from the given string.
-  static CodeCompletionString *Deserialize(llvm::StringRef &Str);  
+  static CodeCompletionString *Deserialize(const char *&Str, 
+                                           const char *StrEnd);
 };
   
 llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, 
@@ -221,6 +222,10 @@
 protected:
   /// \brief Whether to include macros in the code-completion results.
   bool IncludeMacros;
+
+  /// \brief Whether the output format for the code-completion consumer is
+  /// binary.
+  bool OutputIsBinary;
   
 public:
   /// \brief Captures a result of code completion.
@@ -394,17 +399,20 @@
                                                 Sema &S) const;    
   };
   
-  CodeCompleteConsumer() : IncludeMacros(false) { }
+  CodeCompleteConsumer() : IncludeMacros(false), OutputIsBinary(false) { }
   
-  explicit CodeCompleteConsumer(bool IncludeMacros)
-    : IncludeMacros(IncludeMacros) { }
+  CodeCompleteConsumer(bool IncludeMacros, bool OutputIsBinary)
+    : IncludeMacros(IncludeMacros), OutputIsBinary(OutputIsBinary) { }
   
   /// \brief Whether the code-completion consumer wants to see macros.
   bool includeMacros() const { return IncludeMacros; }
+
+  /// \brief Determine whether the output of this consumer is binary.
+  bool isOutputBinary() const { return OutputIsBinary; }
   
   /// \brief Deregisters and destroys this code-completion consumer.
   virtual ~CodeCompleteConsumer();
-    
+
   /// \name Code-completion callbacks
   //@{
   /// \brief Process the finalized code-completion results.
@@ -436,7 +444,7 @@
   /// results to the given raw output stream.
   PrintingCodeCompleteConsumer(bool IncludeMacros,
                                llvm::raw_ostream &OS)
-    : CodeCompleteConsumer(IncludeMacros), OS(OS) { }
+    : CodeCompleteConsumer(IncludeMacros, false), OS(OS) { }
   
   /// \brief Prints the finalized code-completion results.
   virtual void ProcessCodeCompleteResults(Sema &S, Result *Results,
@@ -458,7 +466,7 @@
   /// results to the given raw output stream in a format readable to the CIndex
   /// library.
   CIndexCodeCompleteConsumer(bool IncludeMacros, llvm::raw_ostream &OS)
-    : CodeCompleteConsumer(IncludeMacros), OS(OS) { }
+    : CodeCompleteConsumer(IncludeMacros, true), OS(OS) { }
   
   /// \brief Prints the finalized code-completion results.
   virtual void ProcessCodeCompleteResults(Sema &S, Result *Results, 

Modified: cfe/trunk/lib/Frontend/CompilerInstance.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Frontend/CompilerInstance.cpp?rev=90209&r1=90208&r2=90209&view=diff

==============================================================================
--- cfe/trunk/lib/Frontend/CompilerInstance.cpp (original)
+++ cfe/trunk/lib/Frontend/CompilerInstance.cpp Mon Nov 30 23:55:20 2009
@@ -29,6 +29,7 @@
 #include "llvm/Support/raw_ostream.h"
 #include "llvm/Support/Timer.h"
 #include "llvm/System/Path.h"
+#include "llvm/System/Program.h"
 using namespace clang;
 
 CompilerInstance::CompilerInstance(llvm::LLVMContext *_LLVMContext,
@@ -256,6 +257,12 @@
                                  getFrontendOpts().DebugCodeCompletionPrinter,
                                  getFrontendOpts().ShowMacrosInCodeCompletion,
                                  llvm::outs()));
+
+  if (CompletionConsumer->isOutputBinary() &&
+      llvm::sys::Program::ChangeStdoutToBinary()) {
+    getPreprocessor().getDiagnostics().Report(diag::err_fe_stdout_binary);
+    CompletionConsumer.reset();
+  }
 }
 
 void CompilerInstance::createFrontendTimer() {

Modified: cfe/trunk/lib/Sema/CodeCompleteConsumer.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/CodeCompleteConsumer.cpp?rev=90209&r1=90208&r2=90209&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/CodeCompleteConsumer.cpp (original)
+++ cfe/trunk/lib/Sema/CodeCompleteConsumer.cpp Mon Nov 30 23:55:20 2009
@@ -14,6 +14,7 @@
 #include "clang/AST/DeclCXX.h"
 #include "clang/Parse/Scope.h"
 #include "clang/Lex/Preprocessor.h"
+#include "clang-c/Index.h"
 #include "Sema.h"
 #include "llvm/ADT/STLExtras.h"
 #include "llvm/ADT/StringSwitch.h"
@@ -209,306 +210,111 @@
   return Result;
 }
 
-namespace {
-  // Escape a string for XML-like formatting.
-  struct EscapedString {
-    EscapedString(llvm::StringRef Str) : Str(Str) { }
-    
-    llvm::StringRef Str;
-  };
-  
-  llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, EscapedString EStr) {
-    llvm::StringRef Str = EStr.Str;
-    while (!Str.empty()) {
-      // Find the next escaped character.
-      llvm::StringRef::size_type Pos = Str.find_first_of("<>&\"'");
-      
-      // Print everything before that escaped character.
-      OS << Str.substr(0, Pos);
+static void WriteUnsigned(llvm::raw_ostream &OS, unsigned Value) {
+  OS.write((const char *)&Value, sizeof(unsigned));
+}
 
-      // If we didn't find any escaped characters, we're done.
-      if (Pos == llvm::StringRef::npos)
-        break;
-      
-      // Print the appropriate escape sequence.
-      switch (Str[Pos]) {
-        case '<': OS << "<"; break;
-        case '>': OS << ">"; break;
-        case '&': OS << "&"; break;
-        case '"': OS << """; break;
-        case '\'': OS << "'"; break;
-      }
-      
-      // Remove everything up to and including that escaped character.
-      Str = Str.substr(Pos + 1);
-    }
-    
-    return OS;
-  }
-  
-  /// \brief Remove XML-like escaping from a string.
-  std::string UnescapeString(llvm::StringRef Str) {
-    using llvm::StringRef;
-    
-    std::string Result;
-    llvm::raw_string_ostream OS(Result);
-    
-    while (!Str.empty()) {
-      StringRef::size_type Amp = Str.find('&');
-      OS << Str.substr(0, Amp);
-      
-      if (Amp == StringRef::npos)
-        break;
-      
-      StringRef::size_type Semi = Str.substr(Amp).find(';');
-      if (Semi == StringRef::npos) {
-        // Malformed input; do the best we can.
-        OS << '&';
-        Str = Str.substr(Amp + 1);
-        continue;
-      }
-      
-      char Unescaped = llvm::StringSwitch<char>(Str.substr(Amp + 1, Semi - 1))
-        .Case("lt", '<')
-        .Case("gt", '>')
-        .Case("amp", '&')
-        .Case("quot", '"')
-        .Case("apos", '\'')
-        .Default('\0');
-      
-      if (Unescaped)
-        OS << Unescaped;
-      else
-        OS << Str.substr(Amp, Semi + 1);
-      Str = Str.substr(Amp + Semi + 1);
-    }
-    
-    return OS.str();
-  }
+static bool ReadUnsigned(const char *&Memory, const char *MemoryEnd,
+                         unsigned &Value) {
+  if (Memory + sizeof(unsigned) > MemoryEnd)
+    return true;
+
+  memmove(&Value, Memory, sizeof(unsigned));
+  Memory += sizeof(unsigned);
+  return false;
 }
 
 void CodeCompletionString::Serialize(llvm::raw_ostream &OS) const {
+  // Write the number of chunks.
+  WriteUnsigned(OS, size());
+
   for (iterator C = begin(), CEnd = end(); C != CEnd; ++C) {
+    WriteUnsigned(OS, C->Kind);
+
     switch (C->Kind) {
     case CK_TypedText:
-      OS << "<typed-text>" << EscapedString(C->Text) << "</>";
-      break;
     case CK_Text:
-      OS << "<text>" << EscapedString(C->Text) << "</>";
-      break;
-    case CK_Optional:
-      OS << "<optional>";
-      C->Optional->Serialize(OS);
-      OS << "</>";
-      break;
     case CK_Placeholder:
-      OS << "<placeholder>" << EscapedString(C->Text) << "</>";
-      break;
     case CK_Informative:
-      OS << "<informative>" << EscapedString(C->Text) << "</>";
+    case CK_CurrentParameter: {
+      const char *Text = C->Text;
+      unsigned StrLen = strlen(Text);
+      WriteUnsigned(OS, StrLen);
+      OS.write(Text, StrLen);
       break;
-    case CK_CurrentParameter:
-      OS << "<current-parameter>" << EscapedString(C->Text) << "</>";
+    }
+
+    case CK_Optional:
+      C->Optional->Serialize(OS);
       break;
+
     case CK_LeftParen:
-      OS << "<lparen/>";
-      break;
     case CK_RightParen:
-      OS << "<rparen/>";
-      break;
     case CK_LeftBracket:
-      OS << "<lbracket/>";
-      break;
     case CK_RightBracket:
-      OS << "<rbracket/>";
-      break;
     case CK_LeftBrace:
-      OS << "<lbrace/>";
-      break;
     case CK_RightBrace:
-      OS << "<rbrace/>";
-      break;
     case CK_LeftAngle:
-      OS << "<langle/>";
-      break;
     case CK_RightAngle:
-      OS << "<rangle/>";
-      break;
     case CK_Comma:
-      OS << "<comma/>";
       break;
-    }  
+    }
   }
 }
 
-/// \brief Parse the next XML-ish tag of the form <blah>.
-///
-/// \param Str the string in which we're looking for the next tag.
-///
-/// \param TagPos if successful, will be set to the start of the tag we found.
-///
-/// \param Standalone will indicate whether this is a "standalone" tag that
-/// has no associated data, e.g., <comma/>.
-///
-/// \param Terminator will indicate whether this is a terminating tag (that is
-/// or starts with '/').
-///
-/// \returns the tag itself, without the angle brackets.
-static llvm::StringRef ParseNextTag(llvm::StringRef Str, 
-                                    llvm::StringRef::size_type &StartTag,
-                                    llvm::StringRef::size_type &AfterTag,
-                                    bool &Standalone, bool &Terminator) {
-  using llvm::StringRef;
-  
-  Standalone = false;
-  Terminator = false;
-  AfterTag = StringRef::npos;
-  
-  // Find the starting '<'. 
-  StartTag = Str.find('<');
-  if (StartTag == StringRef::npos)
-    return llvm::StringRef();
-  
-  // Find the corresponding '>'.
-  llvm::StringRef::size_type EndTag = Str.substr(StartTag).find('>');
-  if (EndTag == StringRef::npos)
-    return llvm::StringRef();
-  AfterTag = StartTag + EndTag + 1;
-  
-  // Determine whether this is a terminating tag.
-  if (Str[StartTag + 1] == '/') {
-    Terminator = true;
-    Str = Str.substr(1);
-    --EndTag;
-  }
-  
-  // Determine whether this is a standalone tag.
-  if (!Terminator && Str[StartTag + EndTag - 1] == '/') {
-    Standalone = true;
-    if (EndTag > 1)
-      --EndTag;
-  }
-
-  return Str.substr(StartTag + 1, EndTag - 1);
-}
+CodeCompletionString *CodeCompletionString::Deserialize(const char *&Str,
+                                                        const char *StrEnd) {
+  if (Str == StrEnd || *Str == 0)
+    return 0;
 
-CodeCompletionString *CodeCompletionString::Deserialize(llvm::StringRef &Str) {
-  using llvm::StringRef;
-  
   CodeCompletionString *Result = new CodeCompletionString;
-  
-  do {
-    // Parse the next tag.
-    StringRef::size_type StartTag, AfterTag;
-    bool Standalone, Terminator;
-    StringRef Tag = ParseNextTag(Str, StartTag, AfterTag, Standalone, 
-                                 Terminator);
-    
-    if (StartTag == StringRef::npos)
-      break;
-    
-    // Figure out what kind of chunk we have.
-    const unsigned UnknownKind = 10000;
-    unsigned Kind = llvm::StringSwitch<unsigned>(Tag)
-      .Case("typed-text", CK_TypedText)
-      .Case("text", CK_Text)
-      .Case("optional", CK_Optional)
-      .Case("placeholder", CK_Placeholder)
-      .Case("informative", CK_Informative)
-      .Case("current-parameter", CK_CurrentParameter)
-      .Case("lparen", CK_LeftParen)
-      .Case("rparen", CK_RightParen)
-      .Case("lbracket", CK_LeftBracket)
-      .Case("rbracket", CK_RightBracket)
-      .Case("lbrace", CK_LeftBrace)
-      .Case("rbrace", CK_RightBrace)
-      .Case("langle", CK_LeftAngle)
-      .Case("rangle", CK_RightAngle)
-      .Case("comma", CK_Comma)
-      .Default(UnknownKind);
-    
-    // If we've hit a terminator tag, we're done.
-    if (Terminator)
+  unsigned NumBlocks;
+  if (ReadUnsigned(Str, StrEnd, NumBlocks))
+    return Result;
+
+  for (unsigned I = 0; I != NumBlocks; ++I) {
+    if (Str + 1 >= StrEnd)
       break;
-    
-    // Consume the tag.
-    Str = Str.substr(AfterTag);
 
-    // Handle standalone tags now, since they don't need to be matched to
-    // anything.
-    if (Standalone) {
-      // Ignore anything we don't know about.
-      if (Kind == UnknownKind)
-        continue;
-      
-      switch ((ChunkKind)Kind) {
-      case CK_TypedText:
-      case CK_Text:
-      case CK_Optional:
-      case CK_Placeholder:
-      case CK_Informative:
-      case CK_CurrentParameter:
-        // There is no point in creating empty chunks of these kinds.
-        break;
-        
-      case CK_LeftParen:
-      case CK_RightParen:
-      case CK_LeftBracket:
-      case CK_RightBracket:
-      case CK_LeftBrace:
-      case CK_RightBrace:
-      case CK_LeftAngle:
-      case CK_RightAngle:
-      case CK_Comma:
-        Result->AddChunk(Chunk((ChunkKind)Kind));
-        break;
-      }
-      
-      continue;
+    // Parse the next kind.
+    unsigned KindValue;
+    if (ReadUnsigned(Str, StrEnd, KindValue))
+      return Result;
+
+    switch (ChunkKind Kind = (ChunkKind)KindValue) {
+    case CK_TypedText:
+    case CK_Text:
+    case CK_Placeholder:
+    case CK_Informative:
+    case CK_CurrentParameter: {
+      unsigned StrLen;
+      if (ReadUnsigned(Str, StrEnd, StrLen) || (Str + StrLen > StrEnd))
+        return Result;
+
+      Result->AddChunk(Chunk(Kind, StringRef(Str, StrLen)));
+      Str += StrLen;
+      break;
     }
-    
-    if (Kind == CK_Optional) {
-      // Deserialize the optional code-completion string.
-      std::auto_ptr<CodeCompletionString> Optional(Deserialize(Str));
+
+    case CK_Optional: {
+      std::auto_ptr<CodeCompletionString> Optional(Deserialize(Str, StrEnd));
       Result->AddOptionalChunk(Optional);
+      break;
     }
-    
-    StringRef EndTag = ParseNextTag(Str, StartTag, AfterTag, Standalone, 
-                                    Terminator);
-    if (StartTag == StringRef::npos || !Terminator || Standalone)
-      break; // Parsing failed; just give up.
-    
-    if (EndTag.empty() || Tag == EndTag) {
-      // Found the matching end tag. Add this chunk based on the text
-      // between the tags, then consume that input.
-      StringRef Text = Str.substr(0, StartTag);
-      switch ((ChunkKind)Kind) {
-      case CK_TypedText:
-      case CK_Text:
-      case CK_Placeholder:
-      case CK_Informative:
-      case CK_CurrentParameter:
-      case CK_LeftParen:
-      case CK_RightParen:
-      case CK_LeftBracket:
-      case CK_RightBracket:
-      case CK_LeftBrace:
-      case CK_RightBrace:
-      case CK_LeftAngle:
-      case CK_RightAngle:
-      case CK_Comma:
-        Result->AddChunk(Chunk((ChunkKind)Kind, UnescapeString(Text)));
-        break;
-          
-      case CK_Optional:
-        // We've already added the optional chunk.
-        break;
-      }
+
+    case CK_LeftParen:
+    case CK_RightParen:
+    case CK_LeftBracket:
+    case CK_RightBracket:
+    case CK_LeftBrace:
+    case CK_RightBrace:
+    case CK_LeftAngle:
+    case CK_RightAngle:
+    case CK_Comma:
+      Result->AddChunk(Chunk(Kind));
+      break;      
     }
-    
-    // Remove this tag.
-    Str = Str.substr(AfterTag);
-  } while (!Str.empty());
+  };
   
   return Result;
 }
@@ -632,62 +438,110 @@
                                                        unsigned NumResults) {
   // Print the results.
   for (unsigned I = 0; I != NumResults; ++I) {
-    OS << "COMPLETION:" << Results[I].Rank << ":";
+    CXCursorKind Kind = CXCursor_NotImplemented;
+
     switch (Results[I].Kind) {
-      case Result::RK_Declaration:
-        if (RecordDecl *Record = dyn_cast<RecordDecl>(Results[I].Declaration)) {
-          if (Record->isStruct())
-            OS << "Struct:";
-          else if (Record->isUnion())
-            OS << "Union:";
-          else
-            OS << "Class:";
-        } else if (ObjCMethodDecl *Method
-                     = dyn_cast<ObjCMethodDecl>(Results[I].Declaration)) {
-          if (Method->isInstanceMethod())
-            OS << "ObjCInstanceMethod:";
-          else
-            OS << "ObjCClassMethod:";
-        } else {
-          OS << Results[I].Declaration->getDeclKindName() << ":";
-        }
-        if (CodeCompletionString *CCS 
-              = Results[I].CreateCodeCompletionString(SemaRef)) {
-          CCS->Serialize(OS);
-          delete CCS;
-        } else {
-          OS << "<typed-text>" 
-             << Results[I].Declaration->getNameAsString() 
-             << "</>";
-        }
-        
-        OS << '\n';
-        break;
-        
-      case Result::RK_Keyword:
-        OS << "Keyword:<typed-text>" << Results[I].Keyword << "</>\n";
-        break;
-        
-      case Result::RK_Macro: {
-        OS << "Macro:";
-        if (CodeCompletionString *CCS 
-              = Results[I].CreateCodeCompletionString(SemaRef)) {
-          CCS->Serialize(OS);
-          delete CCS;
-        } else {
-          OS << "<typed-text>" << Results[I].Macro->getName() << "</>";
-        }
-        OS << '\n';
+    case Result::RK_Declaration:
+      switch (Results[I].Declaration->getKind()) {
+      case Decl::Record:
+      case Decl::CXXRecord:
+      case Decl::ClassTemplateSpecialization: {
+        RecordDecl *Record = cast<RecordDecl>(Results[I].Declaration);
+        if (Record->isStruct())
+          Kind = CXCursor_StructDecl;
+        else if (Record->isUnion())
+          Kind = CXCursor_UnionDecl;
+        else
+          Kind = CXCursor_ClassDecl;
+        break;
+      }
+        
+      case Decl::ObjCMethod: {
+        ObjCMethodDecl *Method = cast<ObjCMethodDecl>(Results[I].Declaration);
+        if (Method->isInstanceMethod())
+            Kind = CXCursor_ObjCInstanceMethodDecl;
+        else
+          Kind = CXCursor_ObjCClassMethodDecl;
         break;
       }
         
-      case Result::RK_Pattern: {
-        OS << "Pattern:";
-        Results[I].Pattern->Serialize(OS);
-        OS << '\n';
+      case Decl::Typedef:
+        Kind = CXCursor_TypedefDecl;
+        break;
+        
+      case Decl::Enum:
+        Kind = CXCursor_EnumDecl;
+        break;
+        
+      case Decl::Field:
+        Kind = CXCursor_FieldDecl;
+        break;
+        
+      case Decl::EnumConstant:
+        Kind = CXCursor_EnumConstantDecl;
+        break;
+        
+      case Decl::Function:
+      case Decl::CXXMethod:
+      case Decl::CXXConstructor:
+      case Decl::CXXDestructor:
+      case Decl::CXXConversion:
+        Kind = CXCursor_FunctionDecl;
+        break;
+        
+      case Decl::Var:
+        Kind = CXCursor_VarDecl;
+        break;
+        
+      case Decl::ParmVar:
+        Kind = CXCursor_ParmDecl;
+        break;
+        
+      case Decl::ObjCInterface:
+        Kind = CXCursor_ObjCInterfaceDecl;
+        break;
+        
+      case Decl::ObjCCategory:
+        Kind = CXCursor_ObjCCategoryDecl;
+        break;
+        
+      case Decl::ObjCProtocol:
+        Kind = CXCursor_ObjCProtocolDecl;
+        break;
+        
+      case Decl::ObjCProperty:
+        Kind = CXCursor_ObjCPropertyDecl;
+        break;
+        
+      case Decl::ObjCIvar:
+        Kind = CXCursor_ObjCIvarDecl;
+        break;
+        
+      case Decl::ObjCImplementation:
+        Kind = CXCursor_ObjCClassDefn;
+        break;
+        
+      case Decl::ObjCCategoryImpl:
+        Kind = CXCursor_ObjCCategoryDefn;
+        break;
+        
+      default:
         break;
       }
+      break;
+        
+    case Result::RK_Keyword:
+    case Result::RK_Macro:
+    case Result::RK_Pattern:
+      Kind = CXCursor_NotImplemented;
+      break;
     }
+
+    WriteUnsigned(OS, Kind);
+    CodeCompletionString *CCS = Results[I].CreateCodeCompletionString(SemaRef);
+    assert(CCS && "No code-completion string?");
+    CCS->Serialize(OS);
+    delete CCS;
   }
   
   // Once we've printed the code-completion results, suppress remaining
@@ -702,13 +556,12 @@
                                                 OverloadCandidate *Candidates,
                                                        unsigned NumCandidates) {
   for (unsigned I = 0; I != NumCandidates; ++I) {
-    if (CodeCompletionString *CCS
-        = Candidates[I].CreateSignatureString(CurrentArg, SemaRef)) {
-      OS << "OVERLOAD:";
-      CCS->Serialize(OS);
-      OS << '\n';
-      delete CCS;
-    }
+    WriteUnsigned(OS, CXCursor_NotImplemented);
+    CodeCompletionString *CCS
+      = Candidates[I].CreateSignatureString(CurrentArg, SemaRef);
+    assert(CCS && "No code-completion string?");
+    CCS->Serialize(OS);
+    delete CCS;
   }
   
   // Once we've printed the code-completion results, suppress remaining

Modified: cfe/trunk/lib/Sema/SemaCodeComplete.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaCodeComplete.cpp?rev=90209&r1=90208&r2=90209&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/SemaCodeComplete.cpp (original)
+++ cfe/trunk/lib/Sema/SemaCodeComplete.cpp Mon Nov 30 23:55:20 2009
@@ -801,17 +801,26 @@
 CodeCompleteConsumer::Result::CreateCodeCompletionString(Sema &S) {
   typedef CodeCompletionString::Chunk Chunk;
   
-  if (Kind == RK_Keyword)
-    return 0;
+  if (Kind == RK_Pattern)
+    return Pattern->Clone();
+  
+  CodeCompletionString *Result = new CodeCompletionString;
+
+  if (Kind == RK_Keyword) {
+    Result->AddTypedTextChunk(Keyword);
+    return Result;
+  }
   
   if (Kind == RK_Macro) {
     MacroInfo *MI = S.PP.getMacroInfo(Macro);
-    if (!MI || !MI->isFunctionLike())
-      return 0;
+    assert(MI && "Not a macro?");
+
+    Result->AddTypedTextChunk(Macro->getName());
+
+    if (!MI->isFunctionLike())
+      return Result;
     
     // Format a function-like macro with placeholders for the arguments.
-    CodeCompletionString *Result = new CodeCompletionString;
-    Result->AddTypedTextChunk(Macro->getName());
     Result->AddChunk(Chunk(CodeCompletionString::CK_LeftParen));
     for (MacroInfo::arg_iterator A = MI->arg_begin(), AEnd = MI->arg_end();
          A != AEnd; ++A) {
@@ -843,14 +852,12 @@
   NamedDecl *ND = Declaration;
   
   if (StartsNestedNameSpecifier) {
-    CodeCompletionString *Result = new CodeCompletionString;
     Result->AddTypedTextChunk(ND->getNameAsString());
     Result->AddTextChunk("::");
     return Result;
   }
   
   if (FunctionDecl *Function = dyn_cast<FunctionDecl>(ND)) {
-    CodeCompletionString *Result = new CodeCompletionString;
     AddQualifierToCompletionString(Result, Qualifier, QualifierIsInformative, 
                                    S.Context);
     Result->AddTypedTextChunk(Function->getNameAsString());
@@ -861,7 +868,6 @@
   }
   
   if (FunctionTemplateDecl *FunTmpl = dyn_cast<FunctionTemplateDecl>(ND)) {
-    CodeCompletionString *Result = new CodeCompletionString;
     AddQualifierToCompletionString(Result, Qualifier, QualifierIsInformative, 
                                    S.Context);
     FunctionDecl *Function = FunTmpl->getTemplatedDecl();
@@ -915,7 +921,6 @@
   }
   
   if (TemplateDecl *Template = dyn_cast<TemplateDecl>(ND)) {
-    CodeCompletionString *Result = new CodeCompletionString;
     AddQualifierToCompletionString(Result, Qualifier, QualifierIsInformative, 
                                    S.Context);
     Result->AddTypedTextChunk(Template->getNameAsString());
@@ -926,7 +931,6 @@
   }
   
   if (ObjCMethodDecl *Method = dyn_cast<ObjCMethodDecl>(ND)) {
-    CodeCompletionString *Result = new CodeCompletionString;
     Selector Sel = Method->getSelector();
     if (Sel.isUnarySelector()) {
       Result->AddTypedTextChunk(Sel.getIdentifierInfoForSlot(0)->getName());
@@ -982,15 +986,12 @@
     return Result;
   }
 
-  if (Qualifier) {
-    CodeCompletionString *Result = new CodeCompletionString;
+  if (Qualifier)
     AddQualifierToCompletionString(Result, Qualifier, QualifierIsInformative, 
                                    S.Context);
-    Result->AddTypedTextChunk(ND->getNameAsString());
-    return Result;
-  }
-  
-  return 0;
+
+  Result->AddTypedTextChunk(ND->getNameAsString());
+  return Result;
 }
 
 CodeCompletionString *

Modified: cfe/trunk/tools/CIndex/CIndex.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/tools/CIndex/CIndex.cpp?rev=90209&r1=90208&r2=90209&view=diff

==============================================================================
--- cfe/trunk/tools/CIndex/CIndex.cpp (original)
+++ cfe/trunk/tools/CIndex/CIndex.cpp Mon Nov 30 23:55:20 2009
@@ -24,7 +24,6 @@
 #include "clang/Basic/SourceManager.h"
 #include "clang/Frontend/ASTUnit.h"
 #include "llvm/ADT/StringExtras.h"
-#include "llvm/ADT/StringSwitch.h"
 #include "llvm/Config/config.h"
 #include "llvm/Support/Compiler.h"
 #include "llvm/Support/MemoryBuffer.h"
@@ -1128,31 +1127,14 @@
   return CCStr? CCStr->size() : 0;
 }
 
-static CXCursorKind parseResultKind(llvm::StringRef Str) {
-  return llvm::StringSwitch<CXCursorKind>(Str)
-    .Case("Typedef", CXCursor_TypedefDecl)
-    .Case("Struct", CXCursor_StructDecl)
-    .Case("Union", CXCursor_UnionDecl)
-    .Case("Class", CXCursor_ClassDecl)
-    .Case("Enum", CXCursor_EnumDecl)
-    .Case("Field", CXCursor_FieldDecl)
-    .Case("EnumConstant", CXCursor_EnumConstantDecl)
-    .Case("Function", CXCursor_FunctionDecl)
-    // FIXME: Hacks here to make C++ member functions look like C functions
-    .Case("CXXMethod", CXCursor_FunctionDecl)
-    .Case("CXXConstructor", CXCursor_FunctionDecl)
-    .Case("CXXDestructor", CXCursor_FunctionDecl)
-    .Case("CXXConversion", CXCursor_FunctionDecl)
-    .Case("Var", CXCursor_VarDecl)
-    .Case("ParmVar", CXCursor_ParmDecl)
-    .Case("ObjCInterface", CXCursor_ObjCInterfaceDecl)
-    .Case("ObjCCategory", CXCursor_ObjCCategoryDecl)
-    .Case("ObjCProtocol", CXCursor_ObjCProtocolDecl)
-    .Case("ObjCProperty", CXCursor_ObjCPropertyDecl)
-    .Case("ObjCIvar", CXCursor_ObjCIvarDecl)
-    .Case("ObjCInstanceMethod", CXCursor_ObjCInstanceMethodDecl)
-    .Case("ObjCClassMethod", CXCursor_ObjCClassMethodDecl)
-    .Default(CXCursor_NotImplemented);
+static bool ReadUnsigned(const char *&Memory, const char *MemoryEnd,
+                         unsigned &Value) {
+  if (Memory + sizeof(unsigned) > MemoryEnd)
+    return true;
+
+  memmove(&Value, Memory, sizeof(unsigned));
+  Memory += sizeof(unsigned);
+  return false;
 }
 
 void clang_codeComplete(CXIndex CIdx,
@@ -1248,80 +1230,28 @@
   using llvm::StringRef;
   if (MemoryBuffer *F = MemoryBuffer::getFile(ResultsFile.c_str())) {
     StringRef Buffer = F->getBuffer();
-    do {
-      StringRef::size_type CompletionIdx = Buffer.find("COMPLETION:");
-      StringRef::size_type OverloadIdx = Buffer.find("OVERLOAD:");
-      if (CompletionIdx == StringRef::npos && OverloadIdx == StringRef::npos)
+    for (const char *Str = Buffer.data(), *StrEnd = Str + Buffer.size();
+         Str < StrEnd;) {
+      unsigned KindValue;
+      if (ReadUnsigned(Str, StrEnd, KindValue))
         break;
 
-      if (OverloadIdx < CompletionIdx) {
-        // Parse an overload result.
-        Buffer = Buffer.substr(OverloadIdx);
-
-        // Skip past the OVERLOAD:
-        Buffer = Buffer.substr(Buffer.find(':') + 1);
-
-        // Find the entire completion string.
-        StringRef::size_type EOL = Buffer.find_first_of("\n\r");
-        if (EOL == StringRef::npos)
-          continue;
-
-        StringRef Line = Buffer.substr(0, EOL);
-        Buffer = Buffer.substr(EOL + 1);
-        CodeCompletionString *CCStr = CodeCompletionString::Deserialize(Line);
-        if (!CCStr || CCStr->empty())
-          continue;
+      CodeCompletionString *CCStr 
+        = CodeCompletionString::Deserialize(Str, StrEnd);
+      if (!CCStr)
+        continue;
 
+      if (!CCStr->empty()) {
         // Vend the code-completion result to the caller.
         CXCompletionResult Result;
-        Result.CursorKind = CXCursor_NotImplemented;
+        Result.CursorKind = (CXCursorKind)KindValue;
         Result.CompletionString = CCStr;
         if (completion_iterator)
           completion_iterator(&Result, client_data);
-        delete CCStr;
-
-        continue;
       }
 
-      // Parse a completion result.
-      Buffer = Buffer.substr(CompletionIdx);
-
-      // Skip past the COMPLETION:
-      Buffer = Buffer.substr(Buffer.find(':') + 1);
-
-      // Get the rank
-      unsigned Rank = 0;
-      StringRef::size_type AfterRank = Buffer.find(':');
-      Buffer.substr(0, AfterRank).getAsInteger(10, Rank);
-      Buffer = Buffer.substr(AfterRank + 1);
-
-      // Get the kind of result.
-      StringRef::size_type AfterKind = Buffer.find(':');
-      StringRef Kind = Buffer.substr(0, AfterKind);
-      Buffer = Buffer.substr(AfterKind + 1);
-
-      // Skip over any whitespace.
-      Buffer = Buffer.substr(Buffer.find_first_not_of(" \t"));
-
-      // Find the entire completion string.
-      StringRef::size_type EOL = Buffer.find_first_of("\n\r");
-      if (EOL == StringRef::npos)
-        continue;
-
-      StringRef Line = Buffer.substr(0, EOL);
-      Buffer = Buffer.substr(EOL + 1);
-      CodeCompletionString *CCStr = CodeCompletionString::Deserialize(Line);
-      if (!CCStr || CCStr->empty())
-        continue;
-
-      // Vend the code-completion result to the caller.
-      CXCompletionResult Result;
-      Result.CursorKind = parseResultKind(Kind);
-      Result.CompletionString = CCStr;
-      if (completion_iterator)
-        completion_iterator(&Result, client_data);
       delete CCStr;
-    } while (true);
+    };
     delete F;
   }
 





More information about the cfe-commits mailing list