From: Steve Naroff Date: Mon, 9 Nov 2009 17:45:52 +0000 (+0000) Subject: Introduce CXString type and associated functions clang_getCString() and clang_dispose... X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=ef0cef6cec8de5fc60e469a93436eed7212e0dc2;p=clang 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/include/clang-c/Index.h b/include/clang-c/Index.h index 7bdcab5292..bd79eb0803 100644 --- a/include/clang-c/Index.h +++ b/include/clang-c/Index.h @@ -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); diff --git a/tools/CIndex/CIndex.cpp b/tools/CIndex/CIndex.cpp index 8cff4721be..8fba3cf6b5 100644 --- a/tools/CIndex/CIndex.cpp +++ b/tools/CIndex/CIndex.cpp @@ -541,11 +541,14 @@ void clang_disposeTranslationUnit( delete static_cast(CTUnit); } -const char *clang_getTranslationUnitSpelling(CXTranslationUnit CTUnit) +CXString clang_getTranslationUnitSpelling(CXTranslationUnit CTUnit) { assert(CTUnit && "Passed null CXTranslationUnit"); ASTUnit *CXXUnit = static_cast(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(AnonDecl); - + CXString string; + + string.MustFreeString = 0; if (ObjCMethodDecl *OMD = dyn_cast(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(ND)) + else if (ObjCCategoryImplDecl *CIMP = dyn_cast(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(C.decl); - + if (clang_isReference(C.kind)) { + CXString string; + string.MustFreeString = 0; switch (C.kind) { case CXCursor_ObjCSuperClassRef: { ObjCInterfaceDecl *OID = dyn_cast(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(ND)) { - return OID->getIdentifier()->getNameStart(); + string.Spelling = OID->getIdentifier()->getNameStart(); + } else { + ObjCCategoryDecl *OCD = dyn_cast(ND); + assert(OCD && "clang_getCursorLine(): Missing category decl"); + string.Spelling = OCD->getClassInterface()->getIdentifier()->getNameStart(); } - ObjCCategoryDecl *OID = dyn_cast(ND); - assert(OID && "clang_getCursorLine(): Missing category decl"); - return OID->getClassInterface()->getIdentifier()->getNameStart(); + break; } case CXCursor_ObjCProtocolRef: { ObjCProtocolDecl *OID = dyn_cast(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( static_cast(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( static_cast(C.stmt)); assert(DRE && "clang_getCursorLine(): Missing decl ref expr"); - return DRE->getDecl()->getIdentifier()->getNameStart(); + string.Spelling = DRE->getDecl()->getIdentifier()->getNameStart(); + break; } default: - return ""; + string.Spelling = ""; + 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"); diff --git a/tools/CIndex/CIndex.exports b/tools/CIndex/CIndex.exports index 302324bdee..df94c6a5e1 100644 --- a/tools/CIndex/CIndex.exports +++ b/tools/CIndex/CIndex.exports @@ -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 diff --git a/tools/c-index-test/c-index-test.c b/tools/c-index-test/c-index-test.c index fa6fc56fba..4649f5c133 100644 --- a/tools/c-index-test/c-index-test.c +++ b/tools/c-index-test/c-index-test.c @@ -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++; }