[cfe-commits] r90314 - in /cfe/trunk: include/clang-c/Index.h test/Index/Inputs/remap-complete-to.c test/Index/remap-complete.c tools/CIndex/CIndex.cpp tools/c-index-test/c-index-test.c

Douglas Gregor dgregor at apple.com
Wed Dec 2 01:21:35 PST 2009


Author: dgregor
Date: Wed Dec  2 03:21:34 2009
New Revision: 90314

URL: http://llvm.org/viewvc/llvm-project?rev=90314&view=rev
Log:
Extend the CIndex code-completion API to perform code completion
involving unsaved files, using the -remap-file= functionality recently
added to clang-cc.


Added:
    cfe/trunk/test/Index/Inputs/remap-complete-to.c   (with props)
    cfe/trunk/test/Index/remap-complete.c   (with props)
Modified:
    cfe/trunk/include/clang-c/Index.h
    cfe/trunk/tools/CIndex/CIndex.cpp
    cfe/trunk/tools/c-index-test/c-index-test.c

Modified: cfe/trunk/include/clang-c/Index.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang-c/Index.h?rev=90314&r1=90313&r2=90314&view=diff

==============================================================================
--- cfe/trunk/include/clang-c/Index.h (original)
+++ cfe/trunk/include/clang-c/Index.h Wed Dec  2 03:21:34 2009
@@ -104,6 +104,34 @@
  CXCursor_LastInvalid                   = 72
 };
 
+/**
+ * \brief Provides the contents of a file that has not yet been saved to disk.
+ *
+ * Each CXUnsavedFile instance provides the name of a file on the
+ * system along with the current contents of that file that have not
+ * yet been saved to disk.
+ */
+struct CXUnsavedFile {
+  /** 
+   * \brief The file whose contents have not yet been saved. 
+   *
+   * This file must already exist in the file system.
+   */
+  const char *Filename;
+
+  /** 
+   * \brief A null-terminated buffer containing the unsaved contents
+   * of this file.
+   */
+  const char *Contents;
+
+  /**
+   * \brief The length of the unsaved contents of this buffer, not
+   * counting the NULL at the end of the buffer.
+   */
+  unsigned long Length;
+};
+
 /* A cursor into the CXTranslationUnit. */
 
 typedef struct {
@@ -621,6 +649,13 @@
  * includes, etc., but should not include any information specific to 
  * code completion.
  *
+ * \param num_unsaved_files the number of unsaved file entries in \p
+ * unsaved_files.
+ *
+ * \param unsaved_files the files that have not yet been saved to disk
+ * but may be required for code completion, including the contents of
+ * those files.
+ *
  * \param complete_filename the name of the source file where code completion
  * should be performed. In many cases, this name will be the same as the
  * source filename. However, the completion filename may also be a file 
@@ -643,6 +678,8 @@
                                        const char *source_filename,
                                        int num_command_line_args, 
                                        const char **command_line_args,
+                                       unsigned num_unsaved_files,
+                                       struct CXUnsavedFile *unsaved_files,
                                        const char *complete_filename,
                                        unsigned complete_line,
                                        unsigned complete_column,

Added: cfe/trunk/test/Index/Inputs/remap-complete-to.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Index/Inputs/remap-complete-to.c?rev=90314&view=auto

==============================================================================
--- cfe/trunk/test/Index/Inputs/remap-complete-to.c (added)
+++ cfe/trunk/test/Index/Inputs/remap-complete-to.c Wed Dec  2 03:21:34 2009
@@ -0,0 +1 @@
+void f0() { }

Propchange: cfe/trunk/test/Index/Inputs/remap-complete-to.c

------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: cfe/trunk/test/Index/Inputs/remap-complete-to.c

------------------------------------------------------------------------------
    svn:keywords = Id

Propchange: cfe/trunk/test/Index/Inputs/remap-complete-to.c

------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: cfe/trunk/test/Index/remap-complete.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Index/remap-complete.c?rev=90314&view=auto

==============================================================================
--- cfe/trunk/test/Index/remap-complete.c (added)
+++ cfe/trunk/test/Index/remap-complete.c Wed Dec  2 03:21:34 2009
@@ -0,0 +1,4 @@
+// RUN: c-index-test -code-completion-at=%s:1:12 -remap-file="%s;%S/Inputs/remap-complete-to.c" %s | FileCheck %s
+
+// CHECK: FunctionDecl:{TypedText f0}{LeftParen (}{RightParen )}
+void f() { }

Propchange: cfe/trunk/test/Index/remap-complete.c

------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: cfe/trunk/test/Index/remap-complete.c

------------------------------------------------------------------------------
    svn:keywords = Id

Propchange: cfe/trunk/test/Index/remap-complete.c

------------------------------------------------------------------------------
    svn:mime-type = text/plain

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

==============================================================================
--- cfe/trunk/tools/CIndex/CIndex.cpp (original)
+++ cfe/trunk/tools/CIndex/CIndex.cpp Wed Dec  2 03:21:34 2009
@@ -1141,6 +1141,8 @@
                         const char *source_filename,
                         int num_command_line_args,
                         const char **command_line_args,
+                        unsigned num_unsaved_files,
+                        struct CXUnsavedFile *unsaved_files,
                         const char *complete_filename,
                         unsigned complete_line,
                         unsigned complete_column,
@@ -1149,6 +1151,9 @@
   // The indexer, which is mainly used to determine where diagnostics go.
   CIndexer *CXXIdx = static_cast<CIndexer *>(CIdx);
 
+  // The set of temporary files that we've built.
+  std::vector<llvm::sys::Path> TemporaryFiles;
+
   // Build up the arguments for invoking 'clang'.
   std::vector<const char *> argv;
 
@@ -1174,6 +1179,40 @@
   argv.push_back("-Xclang");
   argv.push_back("-no-code-completion-debug-printer");
 
+  std::vector<std::string> RemapArgs;
+  for (unsigned i = 0; i != num_unsaved_files; ++i) {
+    char tmpFile[L_tmpnam];
+    char *tmpFileName = tmpnam(tmpFile);
+
+    // Write the contents of this unsaved file into the temporary file.
+    llvm::sys::Path SavedFile(tmpFileName);
+    std::string ErrorInfo;
+    llvm::raw_fd_ostream OS(SavedFile.c_str(), ErrorInfo);
+    if (!ErrorInfo.empty())
+      continue;
+    
+    OS.write(unsaved_files[i].Contents, unsaved_files[i].Length);
+    OS.close();
+    if (OS.has_error()) {
+      SavedFile.eraseFromDisk();
+      continue;
+    }
+
+    // Remap the file.
+    std::string RemapArg = "-remap-file=";
+    RemapArg += unsaved_files[i].Filename;
+    RemapArg += ';';
+    RemapArg += tmpFileName;
+    RemapArgs.push_back("-Xclang");
+    RemapArgs.push_back(RemapArg);
+    TemporaryFiles.push_back(SavedFile);
+  }
+
+  // The pointers into the elements of RemapArgs are stable because we
+  // won't be adding anything to RemapArgs after this point.
+  for (unsigned i = 0, e = RemapArgs.size(); i != e; ++i)
+    argv.push_back(RemapArgs[i].c_str());
+
   // Add the source file name (FIXME: later, we'll want to build temporary
   // file from the buffer, or just feed the source text via standard input).
   if (source_filename)
@@ -1203,6 +1242,7 @@
   char tmpFile[L_tmpnam];
   char *tmpFileName = tmpnam(tmpFile);
   llvm::sys::Path ResultsFile(tmpFileName);
+  TemporaryFiles.push_back(ResultsFile);
 
   // Invoke 'clang'.
   llvm::sys::Path DevNull; // leave empty, causes redirection to /dev/null
@@ -1255,7 +1295,8 @@
     delete F;
   }
 
-  ResultsFile.eraseFromDisk();
+  for (unsigned i = 0, e = TemporaryFiles.size(); i != e; ++i)
+    TemporaryFiles[i].eraseFromDisk();
 }
 
 } // end extern "C"

Modified: cfe/trunk/tools/c-index-test/c-index-test.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/tools/c-index-test/c-index-test.c?rev=90314&r1=90313&r2=90314&view=diff

==============================================================================
--- cfe/trunk/tools/c-index-test/c-index-test.c (original)
+++ cfe/trunk/tools/c-index-test/c-index-test.c Wed Dec  2 03:21:34 2009
@@ -389,6 +389,91 @@
   fprintf(file, "\n");
 }
 
+void free_remapped_files(struct CXUnsavedFile *unsaved_files,
+                         int num_unsaved_files) {
+  int i;
+  for (i = 0; i != num_unsaved_files; ++i) {
+    free((char *)unsaved_files[i].Filename);
+    free((char *)unsaved_files[i].Contents);
+  }
+}
+
+int parse_remapped_files(int argc, const char **argv, int start_arg,
+                         struct CXUnsavedFile **unsaved_files,
+                          int *num_unsaved_files) {
+  int i;
+  int arg;
+  int prefix_len = strlen("-remap-file=");
+  *unsaved_files = 0;
+  *num_unsaved_files = 0;
+
+  /* Count the number of remapped files. */
+  for (arg = start_arg; arg < argc; ++arg) {
+    if (strncmp(argv[arg], "-remap-file=", prefix_len))
+      break;
+
+    ++*num_unsaved_files;
+  }
+
+  if (*num_unsaved_files == 0)
+    return 0;
+
+  *unsaved_files
+    = (struct CXUnsavedFile *)malloc(sizeof(struct CXUnsavedFile) * 
+                                     *num_unsaved_files);
+  for (arg = start_arg, i = 0; i != *num_unsaved_files; ++i, ++arg) {
+    struct CXUnsavedFile *unsaved = *unsaved_files + i;
+    const char *arg_string = argv[arg] + prefix_len;
+    int filename_len;
+    char *filename;
+    char *contents;
+    FILE *to_file;
+    const char *semi = strchr(arg_string, ';');
+    if (!semi) {
+      fprintf(stderr, 
+              "error: -remap-file=from;to argument is missing semicolon\n");
+      free_remapped_files(*unsaved_files, i);
+      *unsaved_files = 0;
+      *num_unsaved_files = 0;
+      return -1;
+    }
+
+    /* Open the file that we're remapping to. */
+    to_file = fopen(semi + 1, "r");
+    if (!to_file) {
+      fprintf(stderr, "error: cannot open file %s that we are remapping to\n",
+              semi + 1);
+      free_remapped_files(*unsaved_files, i);
+      *unsaved_files = 0;
+      *num_unsaved_files = 0;
+      return -1;
+    }
+
+    /* Determine the length of the file we're remapping to. */
+    fseek(to_file, 0, SEEK_END);
+    unsaved->Length = ftell(to_file);
+    fseek(to_file, 0, SEEK_SET);
+    
+    /* Read the contents of the file we're remapping to. */
+    contents = (char *)malloc(unsaved->Length + 1);
+    fread(contents, 1, unsaved->Length, to_file);
+    contents[unsaved->Length] = 0;
+    unsaved->Contents = contents;
+
+    /* Close the file. */
+    fclose(to_file);
+    
+    /* Copy the file name that we're remapping from. */
+    filename_len = semi - arg_string;
+    filename = (char *)malloc(filename_len + 1);
+    memcpy(filename, arg_string, filename_len);
+    filename[filename_len] = 0;
+    unsaved->Filename = filename;
+  }
+
+  return 0;
+}
+
 int perform_code_completion(int argc, const char **argv) {
   const char *input = argv[1];
   char *filename = 0;
@@ -396,17 +481,26 @@
   unsigned column;
   CXIndex CIdx;
   int errorCode;
+  struct CXUnsavedFile *unsaved_files = 0;
+  int num_unsaved_files = 0;
 
   input += strlen("-code-completion-at=");
   if ((errorCode = parse_file_line_column(input, &filename, &line, &column)))
     return errorCode;
 
+  if (parse_remapped_files(argc, argv, 2, &unsaved_files, &num_unsaved_files))
+    return -1;
+
   CIdx = clang_createIndex(0, 0);
-  clang_codeComplete(CIdx, argv[argc - 1], argc - 3, argv + 2, 
+  clang_codeComplete(CIdx, argv[argc - 1], argc - num_unsaved_files - 3, 
+                     argv + num_unsaved_files + 2, 
+                     num_unsaved_files, unsaved_files,
                      filename, line, column, &print_completion_result, stdout);
   clang_disposeIndex(CIdx);
   free(filename);
   
+  free_remapped_files(unsaved_files, num_unsaved_files);
+
   return 0;
 }
 





More information about the cfe-commits mailing list