zcov: / tools/CIndex/CIndexCodeCompletion.cpp


Files: 1 Branches Taken: 56.2% 54 / 96
Generated: 2010-02-10 01:31 Branches Executed: 95.8% 92 / 96
Line Coverage: 81.1% 120 / 148


Programs: 1 Runs 121


       1                 : //===- CIndexCodeCompletion.cpp - Code Completion API hooks ---------------===//
       2                 : //
       3                 : //                     The LLVM Compiler Infrastructure
       4                 : //
       5                 : // This file is distributed under the University of Illinois Open Source
       6                 : // License. See LICENSE.TXT for details.
       7                 : //
       8                 : //===----------------------------------------------------------------------===//
       9                 : //
      10                 : // This file implements the Clang-C Source Indexing library hooks for
      11                 : // code completion.
      12                 : //
      13                 : //===----------------------------------------------------------------------===//
      14                 : 
      15                 : #include "CIndexer.h"
      16                 : #include "CIndexDiagnostic.h"
      17                 : #include "clang/Frontend/FrontendDiagnostic.h"
      18                 : #include "clang/Sema/CodeCompleteConsumer.h"
      19                 : #include "llvm/ADT/StringExtras.h"
      20                 : #include "llvm/Support/MemoryBuffer.h"
      21                 : #include "llvm/System/Program.h"
      22                 : 
      23                 : using namespace clang;
      24                 : 
      25                 : extern "C" {
      26                 : 
      27                 : enum CXCompletionChunkKind
      28                 : clang_getCompletionChunkKind(CXCompletionString completion_string,
      29             2263:                              unsigned chunk_number) {
      30             2263:   CodeCompletionString *CCStr = (CodeCompletionString *)completion_string;
                     2263: branch 0 taken
                        0: branch 1 not taken
                        0: branch 3 not taken
                     2263: branch 4 taken
                        0: branch 5 not taken
                     2263: branch 6 taken
      31             2263:   if (!CCStr || chunk_number >= CCStr->size())
      32                0:     return CXCompletionChunk_Text;
      33                 : 
                     1728: branch 1 taken
                       42: branch 2 taken
                        1: branch 3 taken
                      136: branch 4 taken
                       20: branch 5 taken
                       90: branch 6 taken
                        3: branch 7 taken
                       57: branch 8 taken
                       57: branch 9 taken
                        0: branch 10 not taken
                        0: branch 11 not taken
                       23: branch 12 taken
                       23: branch 13 taken
                        0: branch 14 not taken
                        0: branch 15 not taken
                        4: branch 16 taken
                        0: branch 17 not taken
                       22: branch 18 taken
                        0: branch 19 not taken
                       42: branch 20 taken
                       15: branch 21 taken
                        0: branch 22 not taken
      34             2263:   switch ((*CCStr)[chunk_number].Kind) {
      35                 :   case CodeCompletionString::CK_TypedText:
      36             1728:     return CXCompletionChunk_TypedText;
      37                 :   case CodeCompletionString::CK_Text:
      38               42:     return CXCompletionChunk_Text;
      39                 :   case CodeCompletionString::CK_Optional:
      40                1:     return CXCompletionChunk_Optional;
      41                 :   case CodeCompletionString::CK_Placeholder:
      42              136:     return CXCompletionChunk_Placeholder;
      43                 :   case CodeCompletionString::CK_Informative:
      44               20:     return CXCompletionChunk_Informative;
      45                 :   case CodeCompletionString::CK_ResultType:
      46               90:     return CXCompletionChunk_ResultType;
      47                 :   case CodeCompletionString::CK_CurrentParameter:
      48                3:     return CXCompletionChunk_CurrentParameter;
      49                 :   case CodeCompletionString::CK_LeftParen:
      50               57:     return CXCompletionChunk_LeftParen;
      51                 :   case CodeCompletionString::CK_RightParen:
      52               57:     return CXCompletionChunk_RightParen;
      53                 :   case CodeCompletionString::CK_LeftBracket:
      54                0:     return CXCompletionChunk_LeftBracket;
      55                 :   case CodeCompletionString::CK_RightBracket:
      56                0:     return CXCompletionChunk_RightBracket;
      57                 :   case CodeCompletionString::CK_LeftBrace:
      58               23:     return CXCompletionChunk_LeftBrace;
      59                 :   case CodeCompletionString::CK_RightBrace:
      60               23:     return CXCompletionChunk_RightBrace;
      61                 :   case CodeCompletionString::CK_LeftAngle:
      62                0:     return CXCompletionChunk_LeftAngle;
      63                 :   case CodeCompletionString::CK_RightAngle:
      64                0:     return CXCompletionChunk_RightAngle;
      65                 :   case CodeCompletionString::CK_Comma:
      66                4:     return CXCompletionChunk_Comma;
      67                 :   case CodeCompletionString::CK_Colon:
      68                0:     return CXCompletionChunk_Colon;
      69                 :   case CodeCompletionString::CK_SemiColon:
      70               22:     return CXCompletionChunk_SemiColon;
      71                 :   case CodeCompletionString::CK_Equal:
      72                0:     return CXCompletionChunk_Equal;
      73                 :   case CodeCompletionString::CK_HorizontalSpace:
      74               42:     return CXCompletionChunk_HorizontalSpace;
      75                 :   case CodeCompletionString::CK_VerticalSpace:
      76               15:     return CXCompletionChunk_VerticalSpace;
      77                 :   }
      78                 : 
      79                 :   // Should be unreachable, but let's be careful.
      80                0:   return CXCompletionChunk_Text;
      81                 : }
      82                 : 
      83                 : const char *clang_getCompletionChunkText(CXCompletionString completion_string,
      84             2262:                                          unsigned chunk_number) {
      85             2262:   CodeCompletionString *CCStr = (CodeCompletionString *)completion_string;
                     2262: branch 0 taken
                        0: branch 1 not taken
                        0: branch 3 not taken
                     2262: branch 4 taken
                        0: branch 5 not taken
                     2262: branch 6 taken
      86             2262:   if (!CCStr || chunk_number >= CCStr->size())
      87                0:     return 0;
      88                 : 
                     2262: branch 1 taken
                        0: branch 2 not taken
                        0: branch 3 not taken
      89             2262:   switch ((*CCStr)[chunk_number].Kind) {
      90                 :   case CodeCompletionString::CK_TypedText:
      91                 :   case CodeCompletionString::CK_Text:
      92                 :   case CodeCompletionString::CK_Placeholder:
      93                 :   case CodeCompletionString::CK_CurrentParameter:
      94                 :   case CodeCompletionString::CK_Informative:
      95                 :   case CodeCompletionString::CK_LeftParen:
      96                 :   case CodeCompletionString::CK_RightParen:
      97                 :   case CodeCompletionString::CK_LeftBracket:
      98                 :   case CodeCompletionString::CK_RightBracket:
      99                 :   case CodeCompletionString::CK_LeftBrace:
     100                 :   case CodeCompletionString::CK_RightBrace:
     101                 :   case CodeCompletionString::CK_LeftAngle:
     102                 :   case CodeCompletionString::CK_RightAngle:
     103                 :   case CodeCompletionString::CK_Comma:
     104                 :   case CodeCompletionString::CK_ResultType:
     105                 :   case CodeCompletionString::CK_Colon:
     106                 :   case CodeCompletionString::CK_SemiColon:
     107                 :   case CodeCompletionString::CK_Equal:
     108                 :   case CodeCompletionString::CK_HorizontalSpace:
     109                 :   case CodeCompletionString::CK_VerticalSpace:
     110             2262:     return (*CCStr)[chunk_number].Text;
     111                 : 
     112                 :   case CodeCompletionString::CK_Optional:
     113                 :     // Note: treated as an empty text block.
     114                0:     return "";
     115                 :   }
     116                 : 
     117                 :   // Should be unreachable, but let's be careful.
     118                0:   return 0;
     119                 : }
     120                 : 
     121                 : CXCompletionString
     122                 : clang_getCompletionChunkCompletionString(CXCompletionString completion_string,
     123                1:                                          unsigned chunk_number) {
     124                1:   CodeCompletionString *CCStr = (CodeCompletionString *)completion_string;
                        1: branch 0 taken
                        0: branch 1 not taken
                        0: branch 3 not taken
                        1: branch 4 taken
                        0: branch 5 not taken
                        1: branch 6 taken
     125                1:   if (!CCStr || chunk_number >= CCStr->size())
     126                0:     return 0;
     127                 : 
                        0: branch 1 not taken
                        1: branch 2 taken
                        0: branch 3 not taken
     128                1:   switch ((*CCStr)[chunk_number].Kind) {
     129                 :   case CodeCompletionString::CK_TypedText:
     130                 :   case CodeCompletionString::CK_Text:
     131                 :   case CodeCompletionString::CK_Placeholder:
     132                 :   case CodeCompletionString::CK_CurrentParameter:
     133                 :   case CodeCompletionString::CK_Informative:
     134                 :   case CodeCompletionString::CK_LeftParen:
     135                 :   case CodeCompletionString::CK_RightParen:
     136                 :   case CodeCompletionString::CK_LeftBracket:
     137                 :   case CodeCompletionString::CK_RightBracket:
     138                 :   case CodeCompletionString::CK_LeftBrace:
     139                 :   case CodeCompletionString::CK_RightBrace:
     140                 :   case CodeCompletionString::CK_LeftAngle:
     141                 :   case CodeCompletionString::CK_RightAngle:
     142                 :   case CodeCompletionString::CK_Comma:
     143                 :   case CodeCompletionString::CK_ResultType:
     144                 :   case CodeCompletionString::CK_Colon:
     145                 :   case CodeCompletionString::CK_SemiColon:
     146                 :   case CodeCompletionString::CK_Equal:
     147                 :   case CodeCompletionString::CK_HorizontalSpace:
     148                 :   case CodeCompletionString::CK_VerticalSpace:
     149                0:     return 0;
     150                 : 
     151                 :   case CodeCompletionString::CK_Optional:
     152                 :     // Note: treated as an empty text block.
     153                1:     return (*CCStr)[chunk_number].Optional;
     154                 :   }
     155                 : 
     156                 :   // Should be unreachable, but let's be careful.
     157                0:   return 0;
     158                 : }
     159                 : 
     160             1732: unsigned clang_getNumCompletionChunks(CXCompletionString completion_string) {
     161             1732:   CodeCompletionString *CCStr = (CodeCompletionString *)completion_string;
                     1732: branch 0 taken
                        0: branch 1 not taken
     162             1732:   return CCStr? CCStr->size() : 0;
     163                 : }
     164                 : 
     165                 : static bool ReadUnsigned(const char *&Memory, const char *MemoryEnd,
     166             1731:                          unsigned &Value) {
                        0: branch 0 not taken
                     1731: branch 1 taken
     167             1731:   if (Memory + sizeof(unsigned) > MemoryEnd)
     168                0:     return true;
     169                 : 
     170             1731:   memmove(&Value, Memory, sizeof(unsigned));
     171             1731:   Memory += sizeof(unsigned);
     172             1731:   return false;
     173                 : }
     174                 : 
     175                 : /// \brief The CXCodeCompleteResults structure we allocate internally;
     176                 : /// the client only sees the initial CXCodeCompleteResults structure.
     177              102: struct AllocatedCXCodeCompleteResults : public CXCodeCompleteResults {
     178                 :   /// \brief The memory buffer from which we parsed the results. We
     179                 :   /// retain this buffer because the completion strings point into it.
     180                 :   llvm::MemoryBuffer *Buffer;
     181                 : 
     182                 :   LangOptions LangOpts;
     183                 : };
     184                 : 
     185                 : CXCodeCompleteResults *clang_codeComplete(CXIndex CIdx,
     186                 :                                           const char *source_filename,
     187                 :                                           int num_command_line_args,
     188                 :                                           const char **command_line_args,
     189                 :                                           unsigned num_unsaved_files,
     190                 :                                           struct CXUnsavedFile *unsaved_files,
     191                 :                                           const char *complete_filename,
     192                 :                                           unsigned complete_line,
     193                 :                                           unsigned complete_column,
     194                 :                                           CXDiagnosticCallback diag_callback,
     195               51:                                           CXClientData diag_client_data) {
     196                 :   // The indexer, which is mainly used to determine where diagnostics go.
     197               51:   CIndexer *CXXIdx = static_cast<CIndexer *>(CIdx);
     198                 : 
     199                 :   // Configure the diagnostics.
     200               51:   DiagnosticOptions DiagOpts;
     201               51:   llvm::OwningPtr<Diagnostic> Diags;
     202               51:   Diags.reset(CompilerInstance::createDiagnostics(DiagOpts, 0, 0));
     203               51:   CIndexDiagnosticClient DiagClient(diag_callback, diag_client_data);
     204               51:   Diags->setClient(&DiagClient);
     205                 :   
     206                 :   // The set of temporary files that we've built.
     207               51:   std::vector<llvm::sys::Path> TemporaryFiles;
     208                 : 
     209                 :   // Build up the arguments for invoking 'clang'.
     210               51:   std::vector<const char *> argv;
     211                 : 
     212                 :   // First add the complete path to the 'clang' executable.
     213               51:   llvm::sys::Path ClangPath = CXXIdx->getClangPath();
     214               51:   argv.push_back(ClangPath.c_str());
     215                 : 
     216                 :   // Add the '-fsyntax-only' argument so that we only perform a basic
     217                 :   // syntax check of the code.
     218               51:   argv.push_back("-fsyntax-only");
     219                 : 
     220                 :   // Add the appropriate '-code-completion-at=file:line:column' argument
     221                 :   // to perform code completion, with an "-Xclang" preceding it.
     222               51:   std::string code_complete_at;
     223               51:   code_complete_at += complete_filename;
     224               51:   code_complete_at += ":";
     225               51:   code_complete_at += llvm::utostr(complete_line);
     226               51:   code_complete_at += ":";
     227               51:   code_complete_at += llvm::utostr(complete_column);
     228               51:   argv.push_back("-Xclang");
     229               51:   argv.push_back("-code-completion-at");
     230               51:   argv.push_back("-Xclang");
     231               51:   argv.push_back(code_complete_at.c_str());
     232               51:   argv.push_back("-Xclang");
     233               51:   argv.push_back("-no-code-completion-debug-printer");
     234               51:   argv.push_back("-Xclang");
     235               51:   argv.push_back("-code-completion-macros");
     236               51:   argv.push_back("-fdiagnostics-binary");
     237                 : 
     238                 :   // Remap any unsaved files to temporary files.
     239               51:   std::vector<std::string> RemapArgs;
                        0: branch 1 not taken
                       51: branch 2 taken
     240               51:   if (RemapFiles(num_unsaved_files, unsaved_files, RemapArgs, TemporaryFiles))
     241                0:     return 0;
     242                 : 
     243                 :   // The pointers into the elements of RemapArgs are stable because we
     244                 :   // won't be adding anything to RemapArgs after this point.
                        4: branch 1 taken
                       51: branch 2 taken
     245               55:   for (unsigned i = 0, e = RemapArgs.size(); i != e; ++i)
     246                4:     argv.push_back(RemapArgs[i].c_str());
     247                 : 
     248                 :   // Add the source file name (FIXME: later, we'll want to build temporary
     249                 :   // file from the buffer, or just feed the source text via standard input).
                       51: branch 0 taken
                        0: branch 1 not taken
     250               51:   if (source_filename)
     251               51:     argv.push_back(source_filename);
     252                 : 
     253                 :   // Process the compiler options, stripping off '-o', '-c', '-fsyntax-only'.
                        1: branch 0 taken
                       51: branch 1 taken
     254               52:   for (int i = 0; i < num_command_line_args; ++i)
                        1: branch 0 taken
                        0: branch 1 not taken
     255                1:     if (const char *arg = command_line_args[i]) {
                        0: branch 1 not taken
                        1: branch 2 taken
     256                1:       if (strcmp(arg, "-o") == 0) {
     257                0:         ++i; // Also skip the matching argument.
     258                0:         continue;
     259                 :       }
                        1: branch 1 taken
                        0: branch 2 not taken
                        1: branch 4 taken
                        0: branch 5 not taken
                        0: branch 7 not taken
                        1: branch 8 taken
     260                1:       if (strcmp(arg, "-emit-ast") == 0 ||
     261                 :           strcmp(arg, "-c") == 0 ||
     262                 :           strcmp(arg, "-fsyntax-only") == 0) {
     263                0:         continue;
     264                 :       }
     265                 : 
     266                 :       // Keep the argument.
     267                1:       argv.push_back(arg);
     268                 :     }
     269                 : 
     270                 :   // Add the null terminator.
     271               51:   argv.push_back(NULL);
     272                 : 
     273                 :   // Generate a temporary name for the code-completion results file.
     274                 :   char tmpFile[L_tmpnam];
     275               51:   char *tmpFileName = tmpnam(tmpFile);
     276               51:   llvm::sys::Path ResultsFile(tmpFileName);
     277               51:   TemporaryFiles.push_back(ResultsFile);
     278                 : 
     279                 :   // Generate a temporary name for the diagnostics file.
     280                 :   char tmpFileResults[L_tmpnam];
     281               51:   char *tmpResultsFileName = tmpnam(tmpFileResults);
     282               51:   llvm::sys::Path DiagnosticsFile(tmpResultsFileName);
     283               51:   TemporaryFiles.push_back(DiagnosticsFile);
     284                 : 
     285                 :   // Invoke 'clang'.
     286               51:   llvm::sys::Path DevNull; // leave empty, causes redirection to /dev/null
     287                 :                            // on Unix or NUL (Windows).
     288               51:   std::string ErrMsg;
     289                 :   const llvm::sys::Path *Redirects[] = { &DevNull, &ResultsFile, 
     290               51:                                          &DiagnosticsFile, 0 };
     291                 :   llvm::sys::Program::ExecuteAndWait(ClangPath, &argv[0], /* env */ NULL,
     292                 :                                      /* redirects */ &Redirects[0],
     293                 :                                      /* secondsToWait */ 0,
     294               51:                                      /* memoryLimits */ 0, &ErrMsg);
     295                 : 
                        0: branch 1 not taken
                       51: branch 2 taken
     296               51:   if (!ErrMsg.empty()) {
     297                0:     std::string AllArgs;
                        0: branch 4 not taken
                        0: branch 5 not taken
     298                0:     for (std::vector<const char*>::iterator I = argv.begin(), E = argv.end();
     299                 :          I != E; ++I) {
     300                0:       AllArgs += ' ';
                        0: branch 1 not taken
                        0: branch 2 not taken
     301                0:       if (*I)
     302                0:         AllArgs += *I;
     303                 :     }
     304                 :     
     305                0:     Diags->Report(diag::err_fe_clang) << AllArgs << ErrMsg;
     306                 :   }
     307                 : 
     308                 :   // Parse the resulting source file to find code-completion results.
     309                 :   using llvm::MemoryBuffer;
     310                 :   using llvm::StringRef;
     311               51:   AllocatedCXCodeCompleteResults *Results = 0;
                       51: branch 3 taken
                        0: branch 4 not taken
     312               51:   if (MemoryBuffer *F = MemoryBuffer::getFile(ResultsFile.c_str())) {
     313               51:     llvm::SmallVector<CXCompletionResult, 4> CompletionResults;
     314               51:     StringRef Buffer = F->getBuffer();
                     1731: branch 2 taken
                       51: branch 3 taken
     315             1833:     for (const char *Str = Buffer.data(), *StrEnd = Str + Buffer.size();
     316                 :          Str < StrEnd;) {
     317                 :       unsigned KindValue;
                        0: branch 1 not taken
                     1731: branch 2 taken
     318             1731:       if (ReadUnsigned(Str, StrEnd, KindValue))
     319                0:         break;
     320                 : 
     321                 :       CodeCompletionString *CCStr 
     322             1731:         = CodeCompletionString::Deserialize(Str, StrEnd);
                        0: branch 0 not taken
                     1731: branch 1 taken
     323             1731:       if (!CCStr)
     324                0:         continue;
     325                 : 
                     1731: branch 1 taken
                        0: branch 2 not taken
     326             1731:       if (!CCStr->empty()) {
     327                 :         // Vend the code-completion result to the caller.
     328                 :         CXCompletionResult Result;
     329             1731:         Result.CursorKind = (CXCursorKind)KindValue;
     330             1731:         Result.CompletionString = CCStr;
     331             1731:         CompletionResults.push_back(Result);
     332                 :       }
     333                 :     };
     334                 : 
     335                 :     // Allocate the results.
     336               51:     Results = new AllocatedCXCodeCompleteResults;
     337               51:     Results->Results = new CXCompletionResult [CompletionResults.size()];
     338               51:     Results->NumResults = CompletionResults.size();
     339                 :     memcpy(Results->Results, CompletionResults.data(),
     340               51:            CompletionResults.size() * sizeof(CXCompletionResult));
     341               51:     Results->Buffer = F;
     342                 :   }
     343                 : 
     344                 :   // FIXME: The LangOptions we are passing here are not at all correct. However,
     345                 :   // in the current design we must pass something in so the SourceLocations have
     346                 :   // a LangOptions object to refer to.
     347                 :   ReportSerializedDiagnostics(DiagnosticsFile, *Diags, 
     348                 :                               num_unsaved_files, unsaved_files,
     349               51:                               Results->LangOpts);
     350                 :   
                      103: branch 1 taken
                       51: branch 2 taken
     351              154:   for (unsigned i = 0, e = TemporaryFiles.size(); i != e; ++i)
     352              103:     TemporaryFiles[i].eraseFromDisk();
     353                 : 
     354               51:   return Results;
     355                 : }
     356                 : 
     357               51: void clang_disposeCodeCompleteResults(CXCodeCompleteResults *ResultsIn) {
                        0: branch 0 not taken
                       51: branch 1 taken
     358               51:   if (!ResultsIn)
     359                0:     return;
     360                 : 
     361                 :   AllocatedCXCodeCompleteResults *Results
     362               51:     = static_cast<AllocatedCXCodeCompleteResults*>(ResultsIn);
     363                 : 
                     1731: branch 0 taken
                       51: branch 1 taken
     364             1782:   for (unsigned I = 0, N = Results->NumResults; I != N; ++I)
     365             1731:     delete (CXCompletionString *)Results->Results[I].CompletionString;
                       51: branch 0 taken
                        0: branch 1 not taken
     366               51:   delete [] Results->Results;
     367                 : 
     368               51:   Results->Results = 0;
     369               51:   Results->NumResults = 0;
                       51: branch 0 taken
                        0: branch 1 not taken
     370               51:   delete Results->Buffer;
     371               51:   Results->Buffer = 0;
                       51: branch 0 taken
                        0: branch 1 not taken
     372               51:   delete Results;
     373                 : }
     374                 : 
     375                 : } // end extern "C"

Generated: 2010-02-10 01:31 by zcov