]> granicus.if.org Git - clang/commitdiff
Split code in CIndex.cpp into multiple source files, and remove some unnecessary...
authorTed Kremenek <kremenek@apple.com>
Tue, 5 Jan 2010 19:32:54 +0000 (19:32 +0000)
committerTed Kremenek <kremenek@apple.com>
Tue, 5 Jan 2010 19:32:54 +0000 (19:32 +0000)
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@92756 91177308-0d34-0410-b5e6-96231b3b80d8

tools/CIndex/CIndex.cpp
tools/CIndex/CIndexCodeCompletion.cpp [new file with mode: 0644]
tools/CIndex/CIndexer.cpp [new file with mode: 0644]
tools/CIndex/CIndexer.h [new file with mode: 0644]
tools/CIndex/CMakeLists.txt

index 3cb15f640deed0f09f40771072cf59d0166904f6..2b33a63b98305ea39fcabedce844de7a984cfaf9 100644 (file)
@@ -7,49 +7,23 @@
 //
 //===----------------------------------------------------------------------===//
 //
-// This file implements the Clang-C Source Indexing library.
+// This file implements the main API hooks in the Clang-C Source Indexing
+// library.
 //
 //===----------------------------------------------------------------------===//
 
-#include "clang-c/Index.h"
-#include "clang/AST/Decl.h"
+#include "CIndexer.h"
+
 #include "clang/AST/DeclVisitor.h"
 #include "clang/AST/StmtVisitor.h"
-#include "clang/Basic/FileManager.h"
-#include "clang/Basic/SourceManager.h"
-#include "clang/Basic/Version.h"
-#include "clang/Frontend/ASTUnit.h"
-#include "clang/Frontend/CompilerInstance.h"
-#include "clang/Index/ASTLocation.h"
-#include "clang/Index/Indexer.h"
-#include "clang/Index/Program.h"
-#include "clang/Index/Utils.h"
-#include "clang/Sema/CodeCompleteConsumer.h"
-#include "llvm/ADT/StringExtras.h"
-#include "llvm/Config/config.h"
-#include "llvm/Support/Compiler.h"
 #include "llvm/Support/MemoryBuffer.h"
-#include "llvm/Support/raw_ostream.h"
-#include "llvm/System/Path.h"
 #include "llvm/System/Program.h"
 
-#include <cstdio>
-#include <vector>
-#include <sstream>
-
-#ifdef LLVM_ON_WIN32
-#define WIN32_LEAN_AND_MEAN
-#include <windows.h>
-#else
-#include <dlfcn.h>
-#endif
-
 using namespace clang;
 using namespace idx;
 
 namespace {
-static enum CXCursorKind TranslateDeclRefExpr(DeclRefExpr *DRE)
-{
+static enum CXCursorKind TranslateDeclRefExpr(DeclRefExpr *DRE) {
   NamedDecl *D = DRE->getDecl();
   if (isa<VarDecl>(D))
     return CXCursor_VarRef;
@@ -97,14 +71,6 @@ public:
 };
 #endif
 
-/// IgnoreDiagnosticsClient - A DiagnosticsClient that just ignores emitted
-/// warnings and errors.
-class VISIBILITY_HIDDEN IgnoreDiagnosticsClient : public DiagnosticClient {
-public:
-  virtual ~IgnoreDiagnosticsClient() {}
-  virtual void HandleDiagnostic(Diagnostic::Level, const DiagnosticInfo &) {}
-};
-
 // Translation Unit Visitor.
 class TUVisitor : public DeclVisitor<TUVisitor> {
   CXTranslationUnit TUnit;
@@ -291,113 +257,7 @@ public:
                                   : CXCursor_ObjCClassMethodDecl, ND);
   }
 };
-
-class CIndexer : public Indexer {
-  DiagnosticOptions DiagOpts;
-  IgnoreDiagnosticsClient IgnoreDiagClient;
-  llvm::OwningPtr<Diagnostic> TextDiags;
-  Diagnostic IgnoreDiags;
-  bool UseExternalASTGeneration;
-  bool OnlyLocalDecls;
-  bool DisplayDiagnostics;
-
-  llvm::sys::Path ClangPath;
-
-public:
-  explicit CIndexer(Program *prog) : Indexer(*prog),
-                                     IgnoreDiags(&IgnoreDiagClient),
-                                     UseExternalASTGeneration(false),
-                                     OnlyLocalDecls(false),
-                                     DisplayDiagnostics(false) {
-    TextDiags.reset(
-      CompilerInstance::createDiagnostics(DiagOpts, 0, 0));
-  }
-
-  virtual ~CIndexer() { delete &getProgram(); }
-
-  /// \brief Whether we only want to see "local" declarations (that did not
-  /// come from a previous precompiled header). If false, we want to see all
-  /// declarations.
-  bool getOnlyLocalDecls() const { return OnlyLocalDecls; }
-  void setOnlyLocalDecls(bool Local = true) { OnlyLocalDecls = Local; }
-
-  bool getDisplayDiagnostics() const { return DisplayDiagnostics; }
-  void setDisplayDiagnostics(bool Display = true) {
-    DisplayDiagnostics = Display;
-  }
-
-  bool getUseExternalASTGeneration() const { return UseExternalASTGeneration; }
-  void setUseExternalASTGeneration(bool Value) {
-    UseExternalASTGeneration = Value;
-  }
-
-  Diagnostic &getDiags() {
-    return DisplayDiagnostics ? *TextDiags : IgnoreDiags;
-  }
-
-  /// \brief Get the path of the clang binary.
-  const llvm::sys::Path& getClangPath();
-
-  /// \brief Get the path of the clang resource files.
-  std::string getClangResourcesPath();
-};
-
-const llvm::sys::Path& CIndexer::getClangPath() {
-  // Did we already compute the path?
-  if (!ClangPath.empty())
-    return ClangPath;
-
-  // Find the location where this library lives (libCIndex.dylib).
-#ifdef LLVM_ON_WIN32
-  MEMORY_BASIC_INFORMATION mbi;
-  char path[MAX_PATH];
-  VirtualQuery((void *)(uintptr_t)clang_createTranslationUnit, &mbi,
-               sizeof(mbi));
-  GetModuleFileNameA((HINSTANCE)mbi.AllocationBase, path, MAX_PATH);
-
-  llvm::sys::Path CIndexPath(path);
-
-  CIndexPath.eraseComponent();
-  CIndexPath.appendComponent("clang");
-  CIndexPath.appendSuffix("exe");
-  CIndexPath.makeAbsolute();
-#else
-  // This silly cast below avoids a C++ warning.
-  Dl_info info;
-  if (dladdr((void *)(uintptr_t)clang_createTranslationUnit, &info) == 0)
-    assert(0 && "Call to dladdr() failed");
-
-  llvm::sys::Path CIndexPath(info.dli_fname);
-
-  // We now have the CIndex directory, locate clang relative to it.
-  CIndexPath.eraseComponent();
-  CIndexPath.eraseComponent();
-  CIndexPath.appendComponent("bin");
-  CIndexPath.appendComponent("clang");
-#endif
-
-  // Cache our result.
-  ClangPath = CIndexPath;
-  return ClangPath;
-}
-
-std::string CIndexer::getClangResourcesPath() {
-  llvm::sys::Path P = getClangPath();
-
-  if (!P.empty()) {
-    P.eraseComponent();  // Remove /clang from foo/bin/clang
-    P.eraseComponent();  // Remove /bin   from foo/bin
-
-    // Get foo/lib/clang/<version>/include
-    P.appendComponent("lib");
-    P.appendComponent("clang");
-    P.appendComponent(CLANG_VERSION_STRING);
-  }
-
-  return P.str();
-}
-
-}
+} // end anonymous namespace
 
 static SourceLocation getLocationFromCursor(CXCursor C,
                                             SourceManager &SourceMgr,
@@ -1096,330 +956,4 @@ void clang_getDefinitionSpellingAndExtent(CXCursor C,
   *endColumn = SM.getSpellingColumnNumber(Body->getRBracLoc());
 }
 
-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;
-  }
-
-  // Should be unreachable, but let's be careful.
-  return CXCompletionChunk_Text;
-}
-
-const char *clang_getCompletionChunkText(CXCompletionString completion_string,
-                                         unsigned chunk_number) {
-  CodeCompletionString *CCStr = (CodeCompletionString *)completion_string;
-  if (!CCStr || chunk_number >= CCStr->size())
-    return 0;
-
-  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:
-    return (*CCStr)[chunk_number].Text;
-
-  case CodeCompletionString::CK_Optional:
-    // Note: treated as an empty text block.
-    return "";
-  }
-
-  // Should be unreachable, but let's be careful.
-  return 0;
-}
-
-CXCompletionString
-clang_getCompletionChunkCompletionString(CXCompletionString completion_string,
-                                         unsigned chunk_number) {
-  CodeCompletionString *CCStr = (CodeCompletionString *)completion_string;
-  if (!CCStr || chunk_number >= CCStr->size())
-    return 0;
-
-  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:
-    return 0;
-
-  case CodeCompletionString::CK_Optional:
-    // Note: treated as an empty text block.
-    return (*CCStr)[chunk_number].Optional;
-  }
-
-  // Should be unreachable, but let's be careful.
-  return 0;
-}
-
-unsigned clang_getNumCompletionChunks(CXCompletionString completion_string) {
-  CodeCompletionString *CCStr = (CodeCompletionString *)completion_string;
-  return CCStr? CCStr->size() : 0;
-}
-
-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;
-}
-
-/// \brief The CXCodeCompleteResults structure we allocate internally;
-/// the client only sees the initial CXCodeCompleteResults structure.
-struct AllocatedCXCodeCompleteResults : public CXCodeCompleteResults {
-  /// \brief The memory buffer from which we parsed the results. We
-  /// retain this buffer because the completion strings point into it.
-  llvm::MemoryBuffer *Buffer;
-};
-
-CXCodeCompleteResults *clang_codeComplete(CXIndex CIdx,
-                                          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) {
-  // 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;
-
-  // First add the complete path to the 'clang' executable.
-  llvm::sys::Path ClangPath = CXXIdx->getClangPath();
-  argv.push_back(ClangPath.c_str());
-
-  // Add the '-fsyntax-only' argument so that we only perform a basic
-  // syntax check of the code.
-  argv.push_back("-fsyntax-only");
-
-  // Add the appropriate '-code-completion-at=file:line:column' argument
-  // to perform code completion, with an "-Xclang" preceding it.
-  std::string code_complete_at;
-  code_complete_at += complete_filename;
-  code_complete_at += ":";
-  code_complete_at += llvm::utostr(complete_line);
-  code_complete_at += ":";
-  code_complete_at += llvm::utostr(complete_column);
-  argv.push_back("-Xclang");
-  argv.push_back("-code-completion-at");
-  argv.push_back("-Xclang");
-  argv.push_back(code_complete_at.c_str());
-  argv.push_back("-Xclang");
-  argv.push_back("-no-code-completion-debug-printer");
-  argv.push_back("-Xclang");
-  argv.push_back("-code-completion-macros");
-  
-  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 = unsaved_files[i].Filename;
-    RemapArg += ';';
-    RemapArg += tmpFileName;
-    RemapArgs.push_back("-Xclang");
-    RemapArgs.push_back("-remap-file");
-    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)
-    argv.push_back(source_filename);
-
-  // Process the compiler options, stripping off '-o', '-c', '-fsyntax-only'.
-  for (int i = 0; i < num_command_line_args; ++i)
-    if (const char *arg = command_line_args[i]) {
-      if (strcmp(arg, "-o") == 0) {
-        ++i; // Also skip the matching argument.
-        continue;
-      }
-      if (strcmp(arg, "-emit-ast") == 0 ||
-          strcmp(arg, "-c") == 0 ||
-          strcmp(arg, "-fsyntax-only") == 0) {
-        continue;
-      }
-
-      // Keep the argument.
-      argv.push_back(arg);
-    }
-
-  // Add the null terminator.
-  argv.push_back(NULL);
-
-  // Generate a temporary name for the AST file.
-  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
-                           // on Unix or NUL (Windows).
-  std::string ErrMsg;
-  const llvm::sys::Path *Redirects[] = { &DevNull, &ResultsFile, &DevNull, 0 };
-  llvm::sys::Program::ExecuteAndWait(ClangPath, &argv[0], /* env */ NULL,
-                                     /* redirects */ &Redirects[0],
-                                     /* secondsToWait */ 0,
-                                     /* memoryLimits */ 0, &ErrMsg);
-
-  if (CXXIdx->getDisplayDiagnostics() && !ErrMsg.empty()) {
-    llvm::errs() << "clang_codeComplete: " << ErrMsg
-                 << '\n' << "Arguments: \n";
-    for (std::vector<const char*>::iterator I = argv.begin(), E = argv.end();
-         I!=E; ++I) {
-      if (*I)
-        llvm::errs() << ' ' << *I << '\n';
-    }
-    llvm::errs() << '\n';
-  }
-
-  // Parse the resulting source file to find code-completion results.
-  using llvm::MemoryBuffer;
-  using llvm::StringRef;
-  AllocatedCXCodeCompleteResults *Results = 0;
-  if (MemoryBuffer *F = MemoryBuffer::getFile(ResultsFile.c_str())) {
-    llvm::SmallVector<CXCompletionResult, 4> CompletionResults;
-    StringRef Buffer = F->getBuffer();
-    for (const char *Str = Buffer.data(), *StrEnd = Str + Buffer.size();
-         Str < StrEnd;) {
-      unsigned KindValue;
-      if (ReadUnsigned(Str, StrEnd, KindValue))
-        break;
-
-      CodeCompletionString *CCStr 
-        = CodeCompletionString::Deserialize(Str, StrEnd);
-      if (!CCStr)
-        continue;
-
-      if (!CCStr->empty()) {
-        // Vend the code-completion result to the caller.
-        CXCompletionResult Result;
-        Result.CursorKind = (CXCursorKind)KindValue;
-        Result.CompletionString = CCStr;
-        CompletionResults.push_back(Result);
-      }
-    };
-
-    // Allocate the results.
-    Results = new AllocatedCXCodeCompleteResults;
-    Results->Results = new CXCompletionResult [CompletionResults.size()];
-    Results->NumResults = CompletionResults.size();
-    memcpy(Results->Results, CompletionResults.data(),
-           CompletionResults.size() * sizeof(CXCompletionResult));
-    Results->Buffer = F;
-  }
-
-  for (unsigned i = 0, e = TemporaryFiles.size(); i != e; ++i)
-    TemporaryFiles[i].eraseFromDisk();
-
-  return Results;
-}
-
-void clang_disposeCodeCompleteResults(CXCodeCompleteResults *ResultsIn) {
-  if (!ResultsIn)
-    return;
-
-  AllocatedCXCodeCompleteResults *Results
-    = static_cast<AllocatedCXCodeCompleteResults*>(ResultsIn);
-
-  for (unsigned I = 0, N = Results->NumResults; I != N; ++I)
-    delete (CXCompletionString *)Results->Results[I].CompletionString;
-  delete [] Results->Results;
-
-  Results->Results = 0;
-  Results->NumResults = 0;
-  delete Results->Buffer;
-  Results->Buffer = 0;
-  delete Results;
-}
-
 } // end extern "C"
diff --git a/tools/CIndex/CIndexCodeCompletion.cpp b/tools/CIndex/CIndexCodeCompletion.cpp
new file mode 100644 (file)
index 0000000..f4ed6ca
--- /dev/null
@@ -0,0 +1,351 @@
+//===- CIndexCodeCompletion.cpp - Code Completion API hooks ---------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements the Clang-C Source Indexing library hooks for
+// code completion.
+//
+//===----------------------------------------------------------------------===//
+
+#include "CIndexer.h"
+#include "clang/Sema/CodeCompleteConsumer.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/System/Program.h"
+
+using namespace clang;
+
+extern "C" {
+
+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;
+  }
+
+  // Should be unreachable, but let's be careful.
+  return CXCompletionChunk_Text;
+}
+
+const char *clang_getCompletionChunkText(CXCompletionString completion_string,
+                                         unsigned chunk_number) {
+  CodeCompletionString *CCStr = (CodeCompletionString *)completion_string;
+  if (!CCStr || chunk_number >= CCStr->size())
+    return 0;
+
+  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:
+    return (*CCStr)[chunk_number].Text;
+
+  case CodeCompletionString::CK_Optional:
+    // Note: treated as an empty text block.
+    return "";
+  }
+
+  // Should be unreachable, but let's be careful.
+  return 0;
+}
+
+CXCompletionString
+clang_getCompletionChunkCompletionString(CXCompletionString completion_string,
+                                         unsigned chunk_number) {
+  CodeCompletionString *CCStr = (CodeCompletionString *)completion_string;
+  if (!CCStr || chunk_number >= CCStr->size())
+    return 0;
+
+  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:
+    return 0;
+
+  case CodeCompletionString::CK_Optional:
+    // Note: treated as an empty text block.
+    return (*CCStr)[chunk_number].Optional;
+  }
+
+  // Should be unreachable, but let's be careful.
+  return 0;
+}
+
+unsigned clang_getNumCompletionChunks(CXCompletionString completion_string) {
+  CodeCompletionString *CCStr = (CodeCompletionString *)completion_string;
+  return CCStr? CCStr->size() : 0;
+}
+
+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;
+}
+
+/// \brief The CXCodeCompleteResults structure we allocate internally;
+/// the client only sees the initial CXCodeCompleteResults structure.
+struct AllocatedCXCodeCompleteResults : public CXCodeCompleteResults {
+  /// \brief The memory buffer from which we parsed the results. We
+  /// retain this buffer because the completion strings point into it.
+  llvm::MemoryBuffer *Buffer;
+};
+
+CXCodeCompleteResults *clang_codeComplete(CXIndex CIdx,
+                                          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) {
+  // 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;
+
+  // First add the complete path to the 'clang' executable.
+  llvm::sys::Path ClangPath = CXXIdx->getClangPath();
+  argv.push_back(ClangPath.c_str());
+
+  // Add the '-fsyntax-only' argument so that we only perform a basic
+  // syntax check of the code.
+  argv.push_back("-fsyntax-only");
+
+  // Add the appropriate '-code-completion-at=file:line:column' argument
+  // to perform code completion, with an "-Xclang" preceding it.
+  std::string code_complete_at;
+  code_complete_at += complete_filename;
+  code_complete_at += ":";
+  code_complete_at += llvm::utostr(complete_line);
+  code_complete_at += ":";
+  code_complete_at += llvm::utostr(complete_column);
+  argv.push_back("-Xclang");
+  argv.push_back("-code-completion-at");
+  argv.push_back("-Xclang");
+  argv.push_back(code_complete_at.c_str());
+  argv.push_back("-Xclang");
+  argv.push_back("-no-code-completion-debug-printer");
+  argv.push_back("-Xclang");
+  argv.push_back("-code-completion-macros");
+  
+  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 = unsaved_files[i].Filename;
+    RemapArg += ';';
+    RemapArg += tmpFileName;
+    RemapArgs.push_back("-Xclang");
+    RemapArgs.push_back("-remap-file");
+    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)
+    argv.push_back(source_filename);
+
+  // Process the compiler options, stripping off '-o', '-c', '-fsyntax-only'.
+  for (int i = 0; i < num_command_line_args; ++i)
+    if (const char *arg = command_line_args[i]) {
+      if (strcmp(arg, "-o") == 0) {
+        ++i; // Also skip the matching argument.
+        continue;
+      }
+      if (strcmp(arg, "-emit-ast") == 0 ||
+          strcmp(arg, "-c") == 0 ||
+          strcmp(arg, "-fsyntax-only") == 0) {
+        continue;
+      }
+
+      // Keep the argument.
+      argv.push_back(arg);
+    }
+
+  // Add the null terminator.
+  argv.push_back(NULL);
+
+  // Generate a temporary name for the AST file.
+  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
+                           // on Unix or NUL (Windows).
+  std::string ErrMsg;
+  const llvm::sys::Path *Redirects[] = { &DevNull, &ResultsFile, &DevNull, 0 };
+  llvm::sys::Program::ExecuteAndWait(ClangPath, &argv[0], /* env */ NULL,
+                                     /* redirects */ &Redirects[0],
+                                     /* secondsToWait */ 0,
+                                     /* memoryLimits */ 0, &ErrMsg);
+
+  if (CXXIdx->getDisplayDiagnostics() && !ErrMsg.empty()) {
+    llvm::errs() << "clang_codeComplete: " << ErrMsg
+                 << '\n' << "Arguments: \n";
+    for (std::vector<const char*>::iterator I = argv.begin(), E = argv.end();
+         I!=E; ++I) {
+      if (*I)
+        llvm::errs() << ' ' << *I << '\n';
+    }
+    llvm::errs() << '\n';
+  }
+
+  // Parse the resulting source file to find code-completion results.
+  using llvm::MemoryBuffer;
+  using llvm::StringRef;
+  AllocatedCXCodeCompleteResults *Results = 0;
+  if (MemoryBuffer *F = MemoryBuffer::getFile(ResultsFile.c_str())) {
+    llvm::SmallVector<CXCompletionResult, 4> CompletionResults;
+    StringRef Buffer = F->getBuffer();
+    for (const char *Str = Buffer.data(), *StrEnd = Str + Buffer.size();
+         Str < StrEnd;) {
+      unsigned KindValue;
+      if (ReadUnsigned(Str, StrEnd, KindValue))
+        break;
+
+      CodeCompletionString *CCStr 
+        = CodeCompletionString::Deserialize(Str, StrEnd);
+      if (!CCStr)
+        continue;
+
+      if (!CCStr->empty()) {
+        // Vend the code-completion result to the caller.
+        CXCompletionResult Result;
+        Result.CursorKind = (CXCursorKind)KindValue;
+        Result.CompletionString = CCStr;
+        CompletionResults.push_back(Result);
+      }
+    };
+
+    // Allocate the results.
+    Results = new AllocatedCXCodeCompleteResults;
+    Results->Results = new CXCompletionResult [CompletionResults.size()];
+    Results->NumResults = CompletionResults.size();
+    memcpy(Results->Results, CompletionResults.data(),
+           CompletionResults.size() * sizeof(CXCompletionResult));
+    Results->Buffer = F;
+  }
+
+  for (unsigned i = 0, e = TemporaryFiles.size(); i != e; ++i)
+    TemporaryFiles[i].eraseFromDisk();
+
+  return Results;
+}
+
+void clang_disposeCodeCompleteResults(CXCodeCompleteResults *ResultsIn) {
+  if (!ResultsIn)
+    return;
+
+  AllocatedCXCodeCompleteResults *Results
+    = static_cast<AllocatedCXCodeCompleteResults*>(ResultsIn);
+
+  for (unsigned I = 0, N = Results->NumResults; I != N; ++I)
+    delete (CXCompletionString *)Results->Results[I].CompletionString;
+  delete [] Results->Results;
+
+  Results->Results = 0;
+  Results->NumResults = 0;
+  delete Results->Buffer;
+  Results->Buffer = 0;
+  delete Results;
+}
+
+} // end extern "C"
diff --git a/tools/CIndex/CIndexer.cpp b/tools/CIndex/CIndexer.cpp
new file mode 100644 (file)
index 0000000..f26c8ce
--- /dev/null
@@ -0,0 +1,96 @@
+//===- CIndex.cpp - Clang-C Source Indexing Library -----------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements the Clang-C Source Indexing library.
+//
+//===----------------------------------------------------------------------===//
+
+#include "CIndexer.h"
+
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclVisitor.h"
+#include "clang/AST/StmtVisitor.h"
+#include "clang/Basic/FileManager.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/Basic/Version.h"
+#include "clang/Sema/CodeCompleteConsumer.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/Config/config.h"
+#include "llvm/Support/Compiler.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/raw_ostream.h"
+#include "llvm/System/Program.h"
+
+#include <cstdio>
+#include <vector>
+#include <sstream>
+
+#ifdef LLVM_ON_WIN32
+#include <windows.h>
+#else
+#include <dlfcn.h>
+#endif
+
+using namespace clang;
+using namespace idx;
+
+const llvm::sys::Path& CIndexer::getClangPath() {
+  // Did we already compute the path?
+  if (!ClangPath.empty())
+    return ClangPath;
+
+  // Find the location where this library lives (libCIndex.dylib).
+#ifdef LLVM_ON_WIN32
+  MEMORY_BASIC_INFORMATION mbi;
+  char path[MAX_PATH];
+  VirtualQuery((void *)(uintptr_t)clang_createTranslationUnit, &mbi,
+               sizeof(mbi));
+  GetModuleFileNameA((HINSTANCE)mbi.AllocationBase, path, MAX_PATH);
+
+  llvm::sys::Path CIndexPath(path);
+
+  CIndexPath.eraseComponent();
+  CIndexPath.appendComponent("clang");
+  CIndexPath.appendSuffix("exe");
+  CIndexPath.makeAbsolute();
+#else
+  // This silly cast below avoids a C++ warning.
+  Dl_info info;
+  if (dladdr((void *)(uintptr_t)clang_createTranslationUnit, &info) == 0)
+    assert(0 && "Call to dladdr() failed");
+
+  llvm::sys::Path CIndexPath(info.dli_fname);
+
+  // We now have the CIndex directory, locate clang relative to it.
+  CIndexPath.eraseComponent();
+  CIndexPath.eraseComponent();
+  CIndexPath.appendComponent("bin");
+  CIndexPath.appendComponent("clang");
+#endif
+
+  // Cache our result.
+  ClangPath = CIndexPath;
+  return ClangPath;
+}
+
+std::string CIndexer::getClangResourcesPath() {
+  llvm::sys::Path P = getClangPath();
+
+  if (!P.empty()) {
+    P.eraseComponent();  // Remove /clang from foo/bin/clang
+    P.eraseComponent();  // Remove /bin   from foo/bin
+
+    // Get foo/lib/clang/<version>/include
+    P.appendComponent("lib");
+    P.appendComponent("clang");
+    P.appendComponent(CLANG_VERSION_STRING);
+  }
+
+  return P.str();
+}
diff --git a/tools/CIndex/CIndexer.h b/tools/CIndex/CIndexer.h
new file mode 100644 (file)
index 0000000..5a0e143
--- /dev/null
@@ -0,0 +1,86 @@
+//===- CIndexer.h - Clang-C Source Indexing Library -----------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines CIndexer, a subclass of Indexer that provides extra
+// functionality needed by the CIndex library.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_CINDEXER_H
+#define LLVM_CLANG_CINDEXER_H
+
+#include "clang-c/Index.h"
+#include "clang/Index/ASTLocation.h"
+#include "clang/Index/Indexer.h"
+#include "clang/Index/Program.h"
+#include "clang/Index/Utils.h"
+#include "clang/Frontend/CompilerInstance.h"
+#include "clang/Frontend/ASTUnit.h"
+#include "llvm/System/Path.h"
+
+using namespace clang;
+
+/// IgnoreDiagnosticsClient - A DiagnosticsClient that just ignores emitted
+/// warnings and errors.
+class IgnoreDiagnosticsClient : public DiagnosticClient {
+public:
+  virtual ~IgnoreDiagnosticsClient() {}
+  virtual void HandleDiagnostic(Diagnostic::Level, const DiagnosticInfo &) {}
+};
+
+class CIndexer : public Indexer {
+  DiagnosticOptions DiagOpts;
+  IgnoreDiagnosticsClient IgnoreDiagClient;
+  llvm::OwningPtr<Diagnostic> TextDiags;
+  Diagnostic IgnoreDiags;
+  bool UseExternalASTGeneration;
+  bool OnlyLocalDecls;
+  bool DisplayDiagnostics;
+  
+  llvm::sys::Path ClangPath;
+  
+public:
+  explicit CIndexer(Program *prog) : Indexer(*prog),
+    IgnoreDiags(&IgnoreDiagClient),
+    UseExternalASTGeneration(false),
+    OnlyLocalDecls(false),
+    DisplayDiagnostics(false) {
+    TextDiags.reset(CompilerInstance::createDiagnostics(DiagOpts, 0, 0));
+  }
+  
+  virtual ~CIndexer() { delete &getProgram(); }
+  
+  /// \brief Whether we only want to see "local" declarations (that did not
+  /// come from a previous precompiled header). If false, we want to see all
+  /// declarations.
+  bool getOnlyLocalDecls() const { return OnlyLocalDecls; }
+  void setOnlyLocalDecls(bool Local = true) { OnlyLocalDecls = Local; }
+  
+  bool getDisplayDiagnostics() const { return DisplayDiagnostics; }
+  void setDisplayDiagnostics(bool Display = true) {
+    DisplayDiagnostics = Display;
+  }
+  
+  bool getUseExternalASTGeneration() const { return UseExternalASTGeneration; }
+  void setUseExternalASTGeneration(bool Value) {
+    UseExternalASTGeneration = Value;
+  }
+  
+  Diagnostic &getDiags() {
+    return DisplayDiagnostics ? *TextDiags : IgnoreDiags;
+  }
+  
+  /// \brief Get the path of the clang binary.
+  const llvm::sys::Path& getClangPath();
+  
+  /// \brief Get the path of the clang resource files.
+  std::string getClangResourcesPath();
+};
+
+#endif
index a3ff3db2d9b5a0a851fc8fa5a1d7952dabac5bd5..ff3f4db2f437f8bc6dea4612243f9782d81a97df 100644 (file)
@@ -19,7 +19,10 @@ set( LLVM_LINK_COMPONENTS
   core
   )
 
-add_clang_library(CIndex CIndex.cpp)
+add_clang_library(CIndex
+  CIndex.cpp
+  CIndexer.cpp
+  CIndexCodeCompletion)
 
 if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
   # FIXME: Deal with LLVM_SUBMIT_VERSION?