]> granicus.if.org Git - clang/commitdiff
Introduce CXString type and associated functions clang_getCString() and clang_dispose...
authorSteve Naroff <snaroff@apple.com>
Mon, 9 Nov 2009 17:45:52 +0000 (17:45 +0000)
committerSteve Naroff <snaroff@apple.com>
Mon, 9 Nov 2009 17:45:52 +0000 (17:45 +0000)
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

include/clang-c/Index.h
tools/CIndex/CIndex.cpp
tools/CIndex/CIndex.exports
tools/c-index-test/c-index-test.c

index 7bdcab5292ce063ece5cc59aef19d2efb88d8f50..bd79eb0803162d81a5d822926d3f75ed9c08e29e 100644 (file)
@@ -115,6 +115,26 @@ typedef struct {
 /* A unique token for looking up "visible" CXDecls from a CXTranslationUnit. */
 typedef void *CXEntity;
 
+/**
+ * For functions returning a string that might or might not need
+ * to be internally allocated and freed.
+ * Use clang_getCString to access the C string value.
+ * Use clang_disposeString to free the value.
+ * Treat it as an opaque type.
+ */
+typedef struct {
+  const char *Spelling;
+  /* A 1 value indicates the clang_ indexing API needed to allocate the string
+     (and it must be freed by clang_disposeString()). */
+  int MustFreeString;
+} CXString;
+
+/* Get C string pointer from a CXString. */
+CINDEX_LINKAGE const char *clang_getCString(CXString string);
+
+/* Free CXString. */
+CINDEX_LINKAGE void clang_disposeString(CXString string);
+
 /**  
  * \brief clang_createIndex() provides a shared context for creating
  * translation units. It provides two options:
@@ -155,8 +175,7 @@ typedef void *CXEntity;
 CINDEX_LINKAGE CXIndex clang_createIndex(int excludeDeclarationsFromPCH,
                           int displayDiagnostics);
 CINDEX_LINKAGE void clang_disposeIndex(CXIndex);
-
-CINDEX_LINKAGE const char *clang_getTranslationUnitSpelling(CXTranslationUnit CTUnit);
+CINDEX_LINKAGE CXString clang_getTranslationUnitSpelling(CXTranslationUnit CTUnit);
 
 /* 
  * \brief Create a translation unit from an AST file (-emit-ast).
@@ -260,7 +279,7 @@ CINDEX_LINKAGE CXEntity clang_getEntity(const char *URI);
  */
 CINDEX_LINKAGE CXCursor clang_getCursorFromDecl(CXDecl);
 CINDEX_LINKAGE CXEntity clang_getEntityFromDecl(CXDecl);
-CINDEX_LINKAGE const char *clang_getDeclSpelling(CXDecl);
+CINDEX_LINKAGE CXString clang_getDeclSpelling(CXDecl);
 CINDEX_LINKAGE unsigned clang_getDeclLine(CXDecl);
 CINDEX_LINKAGE unsigned clang_getDeclColumn(CXDecl);
 CINDEX_LINKAGE const char *clang_getDeclSource(CXDecl); /* deprecate */
@@ -284,7 +303,7 @@ CINDEX_LINKAGE unsigned clang_isInvalid(enum CXCursorKind);
 
 CINDEX_LINKAGE unsigned clang_getCursorLine(CXCursor);
 CINDEX_LINKAGE unsigned clang_getCursorColumn(CXCursor);
-CINDEX_LINKAGE const char *clang_getCursorSpelling(CXCursor);
+CINDEX_LINKAGE CXString clang_getCursorSpelling(CXCursor);
 CINDEX_LINKAGE const char *clang_getCursorSource(CXCursor); /* deprecate */
 CINDEX_LINKAGE CXFile clang_getCursorSourceFile(CXCursor);
 
index 8cff4721be48e7b4f75b63de4d62f40d9fdd9c5c..8fba3cf6b5cd0f74428900c4617c284e26a443f0 100644 (file)
@@ -541,11 +541,14 @@ void clang_disposeTranslationUnit(
   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 @@ CXEntity clang_getEntityFromDecl(CXDecl)
 {
   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 @@ time_t clang_getFileTime(CXFile SFile) {
   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 @@ const char *clang_getCursorSpelling(CXCursor C)
         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 @@ unsigned clang_getCursorLine(CXCursor C)
   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");
index 302324bdee41a6b6e2531201ec132e90b1027787..df94c6a5e1ac588f6229db13f531198a28eadd38 100644 (file)
@@ -3,6 +3,7 @@ _clang_createIndex
 _clang_createTranslationUnit
 _clang_createTranslationUnitFromSourceFile
 _clang_disposeIndex
+_clang_disposeString
 _clang_disposeTranslationUnit
 _clang_getCompletionChunkCompletionString
 _clang_getCompletionChunkKind
@@ -17,6 +18,7 @@ _clang_getCursorLine
 _clang_getCursorSource
 _clang_getCursorSourceFile
 _clang_getCursorSpelling
+_clang_getCString
 _clang_getDeclColumn
 _clang_getDeclLine
 _clang_getDeclSource
index fa6fc56fba5ce95081e5a65928040e9da1019564..4649f5c133bd56878d2d2ae5a8984cd70eeaac54 100644 (file)
@@ -28,8 +28,11 @@ static void PrintCursor(CXCursor Cursor) {
     printf("Invalid Cursor => %s\n", clang_getCursorKindSpelling(Cursor.kind));
   else {
     CXDecl DeclReferenced;
+    CXString string;
+    string = clang_getCursorSpelling(Cursor);
     printf("%s=%s", clang_getCursorKindSpelling(Cursor.kind),
-                      clang_getCursorSpelling(Cursor));
+                      clang_getCString(string));
+    clang_disposeString(string);
     DeclReferenced = clang_getCursorDecl(Cursor);
     if (DeclReferenced)
       printf(":%d:%d", clang_getDeclLine(DeclReferenced),
@@ -40,22 +43,29 @@ static void PrintCursor(CXCursor Cursor) {
 static void DeclVisitor(CXDecl Dcl, CXCursor Cursor, CXClientData Filter)
 {
   if (!Filter || (Cursor.kind == *(enum CXCursorKind *)Filter)) {
+    CXString string;
     printf("// CHECK: %s:%d:%d: ", basename(clang_getCursorSource(Cursor)),
                                  clang_getCursorLine(Cursor),
                                  clang_getCursorColumn(Cursor));
     PrintCursor(Cursor);
-    printf(" [Context=%s]\n", clang_getDeclSpelling(Dcl));
+    string = clang_getDeclSpelling(Dcl);
+    printf(" [Context=%s]\n", clang_getCString(string));
+    clang_disposeString(string);
   }
 }
 static void TranslationUnitVisitor(CXTranslationUnit Unit, CXCursor Cursor,
                                    CXClientData Filter)
 {
   if (!Filter || (Cursor.kind == *(enum CXCursorKind *)Filter)) {
+    CXString string;
     printf("// CHECK: %s:%d:%d: ", basename(clang_getCursorSource(Cursor)),
                                  clang_getCursorLine(Cursor),
                                  clang_getCursorColumn(Cursor));
     PrintCursor(Cursor);
-    printf(" [Context=%s]\n", basename(clang_getTranslationUnitSpelling(Unit)));
+    string = clang_getTranslationUnitSpelling(Unit);
+    printf(" [Context=%s]\n",
+          basename(clang_getCString(string)));
+    clang_disposeString(string);
 
     clang_loadDeclaration(Cursor.decl, DeclVisitor, 0);
 
@@ -83,10 +93,13 @@ static void TranslationUnitVisitor(CXTranslationUnit Unit, CXCursor Cursor,
           if (Ref.kind == CXCursor_NoDeclFound) {
             /* Nothing found here; that's fine. */
           } else if (Ref.kind != CXCursor_FunctionDecl) {
+            CXString string;
             printf("// CHECK: %s:%d:%d: ", basename(clang_getCursorSource(Ref)),
                                              curLine, curColumn);
             PrintCursor(Ref);
-            printf(" [Context:%s]\n", clang_getDeclSpelling(Ref.decl));
+            string = clang_getDeclSpelling(Ref.decl);
+            printf(" [Context:%s]\n", clang_getCString(string));
+            clang_disposeString(string);
           }
           startBuf++;
         }