Introduce CXString type and associated functions clang_getCString() and clang_disposeString().

This abstraction will help us manage string memory for complex names that cross the C++/C boundary (e.g. ObjC methods, selectors). This patch also uses it in clang_getTranslationUnitSpelling (which I'm not sure is necessary). Will investigate later...since the extra malloc() can't hurt (for now).

Patch by John Thompson.



git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@86562 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/tools/CIndex/CIndex.cpp b/tools/CIndex/CIndex.cpp
index 8cff472..8fba3cf 100644
--- a/tools/CIndex/CIndex.cpp
+++ b/tools/CIndex/CIndex.cpp
@@ -541,11 +541,14 @@
   delete static_cast<ASTUnit *>(CTUnit);
 }
   
-const char *clang_getTranslationUnitSpelling(CXTranslationUnit CTUnit)
+CXString clang_getTranslationUnitSpelling(CXTranslationUnit CTUnit)
 {
   assert(CTUnit && "Passed null CXTranslationUnit");
   ASTUnit *CXXUnit = static_cast<ASTUnit *>(CTUnit);
-  return CXXUnit->getOriginalSourceFileName().c_str();
+  CXString string;
+  string.Spelling = strdup(CXXUnit->getOriginalSourceFileName().c_str());
+  string.MustFreeString = 1;
+  return string;
 }
 
 void clang_loadTranslationUnit(CXTranslationUnit CTUnit, 
@@ -610,25 +613,27 @@
 {
   return 0;
 }
-const char *clang_getDeclSpelling(CXDecl AnonDecl)
+CXString clang_getDeclSpelling(CXDecl AnonDecl)
 {
   assert(AnonDecl && "Passed null CXDecl");
   NamedDecl *ND = static_cast<NamedDecl *>(AnonDecl);
-  
+  CXString string;
+
+  string.MustFreeString = 0;
   if (ObjCMethodDecl *OMD = dyn_cast<ObjCMethodDecl>(ND)) {
-    // FIXME: Memory leak! We need to move to a CXString or other API.
-    return ::strdup(OMD->getSelector().getAsString().c_str());
+    string.Spelling = strdup(OMD->getSelector().getAsString().c_str());
+    string.MustFreeString = 1;
   }
-  if (ObjCCategoryImplDecl *CIMP = dyn_cast<ObjCCategoryImplDecl>(ND))
+  else if (ObjCCategoryImplDecl *CIMP = dyn_cast<ObjCCategoryImplDecl>(ND))
     // No, this isn't the same as the code below. getIdentifier() is non-virtual
     // and returns different names. NamedDecl returns the class name and
     // ObjCCategoryImplDecl returns the category name.
-    return CIMP->getIdentifier()->getNameStart();
-    
-  if (ND->getIdentifier())
-    return ND->getIdentifier()->getNameStart();
+    string.Spelling = CIMP->getIdentifier()->getNameStart(); 
+  else if (ND->getIdentifier())
+    string.Spelling = ND->getIdentifier()->getNameStart();
   else 
-    return "";
+    string.Spelling = "";
+  return string;
 }
 
 unsigned clang_getDeclLine(CXDecl AnonDecl)
@@ -686,37 +691,44 @@
   return FEnt->getModificationTime();
 }
 
-const char *clang_getCursorSpelling(CXCursor C)
+CXString clang_getCursorSpelling(CXCursor C)
 {
   assert(C.decl && "CXCursor has null decl");
   NamedDecl *ND = static_cast<NamedDecl *>(C.decl);
-  
+
   if (clang_isReference(C.kind)) {
+    CXString string;
+    string.MustFreeString = 0;
     switch (C.kind) {
       case CXCursor_ObjCSuperClassRef: {
         ObjCInterfaceDecl *OID = dyn_cast<ObjCInterfaceDecl>(ND);
         assert(OID && "clang_getCursorLine(): Missing interface decl");
-        return OID->getSuperClass()->getIdentifier()->getNameStart();
+        string.Spelling = OID->getSuperClass()->getIdentifier()->getNameStart();
+        break;
       }
       case CXCursor_ObjCClassRef: {
         if (ObjCInterfaceDecl *OID = dyn_cast<ObjCInterfaceDecl>(ND)) {
-          return OID->getIdentifier()->getNameStart();
+          string.Spelling = OID->getIdentifier()->getNameStart();
+        } else {
+          ObjCCategoryDecl *OCD = dyn_cast<ObjCCategoryDecl>(ND);
+          assert(OCD && "clang_getCursorLine(): Missing category decl");
+          string.Spelling = OCD->getClassInterface()->getIdentifier()->getNameStart();
         }
-        ObjCCategoryDecl *OID = dyn_cast<ObjCCategoryDecl>(ND);
-        assert(OID && "clang_getCursorLine(): Missing category decl");
-        return OID->getClassInterface()->getIdentifier()->getNameStart();
+        break;
       }
       case CXCursor_ObjCProtocolRef: {
         ObjCProtocolDecl *OID = dyn_cast<ObjCProtocolDecl>(ND);
         assert(OID && "clang_getCursorLine(): Missing protocol decl");
-        return OID->getIdentifier()->getNameStart();
+        string.Spelling = OID->getIdentifier()->getNameStart();
+        break;
       }
       case CXCursor_ObjCSelectorRef: {
         ObjCMessageExpr *OME = dyn_cast<ObjCMessageExpr>(
                                  static_cast<Stmt *>(C.stmt));
         assert(OME && "clang_getCursorLine(): Missing message expr");
-        // FIXME: Memory leak! We need to move to a CXString or other API.
-        return ::strdup(OME->getSelector().getAsString().c_str());
+        string.Spelling = strdup(OME->getSelector().getAsString().c_str());
+        string.MustFreeString = 1;
+        break;
       }
       case CXCursor_VarRef:
       case CXCursor_FunctionRef:
@@ -724,11 +736,14 @@
         DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(
                                  static_cast<Stmt *>(C.stmt));
         assert(DRE && "clang_getCursorLine(): Missing decl ref expr");
-        return DRE->getDecl()->getIdentifier()->getNameStart();
+        string.Spelling = DRE->getDecl()->getIdentifier()->getNameStart();
+        break;
       }
       default:
-        return "<not implemented>";
+        string.Spelling = "<not implemented>";
+        break;
     }
+    return string;
   }
   return clang_getDeclSpelling(C.decl);
 }
@@ -936,6 +951,22 @@
   return SourceMgr.getSpellingLineNumber(SLoc);
 }
 
+// Access string.
+const char *clang_getCString(CXString string) {
+  return string.Spelling;
+}
+ 
+// Free CXString.
+void clang_disposeString(CXString string) {
+  if (string.MustFreeString) {
+    if (string.Spelling) {
+      free((void *)string.Spelling);
+      string.Spelling = NULL;
+    }
+    string.MustFreeString = 0;
+  }
+}
+
 unsigned clang_getCursorColumn(CXCursor C)
 {
   assert(C.decl && "CXCursor has null decl");