Home | History | Annotate | Line # | Download | only in libclang
      1 //===- CXString.cpp - Routines for manipulating CXStrings -----------------===//
      2 //
      3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
      4 // See https://llvm.org/LICENSE.txt for license information.
      5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
      6 //
      7 //===----------------------------------------------------------------------===//
      8 //
      9 // This file defines routines for manipulating CXStrings. It should be the
     10 // only file that has internal knowledge of the encoding of the data in
     11 // CXStrings.
     12 //
     13 //===----------------------------------------------------------------------===//
     14 
     15 #include "CXString.h"
     16 #include "CXTranslationUnit.h"
     17 #include "clang-c/Index.h"
     18 #include "clang/Frontend/ASTUnit.h"
     19 #include "llvm/Support/ErrorHandling.h"
     20 
     21 using namespace clang;
     22 
     23 /// Describes the kind of underlying data in CXString.
     24 enum CXStringFlag {
     25   /// CXString contains a 'const char *' that it doesn't own.
     26   CXS_Unmanaged,
     27 
     28   /// CXString contains a 'const char *' that it allocated with malloc().
     29   CXS_Malloc,
     30 
     31   /// CXString contains a CXStringBuf that needs to be returned to the
     32   /// CXStringPool.
     33   CXS_StringBuf
     34 };
     35 
     36 namespace clang {
     37 namespace cxstring {
     38 
     39 //===----------------------------------------------------------------------===//
     40 // Basic generation of CXStrings.
     41 //===----------------------------------------------------------------------===//
     42 
     43 CXString createEmpty() {
     44   CXString Str;
     45   Str.data = "";
     46   Str.private_flags = CXS_Unmanaged;
     47   return Str;
     48 }
     49 
     50 CXString createNull() {
     51   CXString Str;
     52   Str.data = nullptr;
     53   Str.private_flags = CXS_Unmanaged;
     54   return Str;
     55 }
     56 
     57 CXString createRef(const char *String) {
     58   if (String && String[0] == '\0')
     59     return createEmpty();
     60 
     61   CXString Str;
     62   Str.data = String;
     63   Str.private_flags = CXS_Unmanaged;
     64   return Str;
     65 }
     66 
     67 CXString createDup(const char *String) {
     68   if (!String)
     69     return createNull();
     70 
     71   if (String[0] == '\0')
     72     return createEmpty();
     73 
     74   CXString Str;
     75   Str.data = strdup(String);
     76   Str.private_flags = CXS_Malloc;
     77   return Str;
     78 }
     79 
     80 CXString createRef(StringRef String) {
     81   // If the string is not nul-terminated, we have to make a copy.
     82 
     83   // FIXME: This is doing a one past end read, and should be removed! For memory
     84   // we don't manage, the API string can become unterminated at any time outside
     85   // our control.
     86 
     87   if (!String.empty() && String.data()[String.size()] != 0)
     88     return createDup(String);
     89 
     90   CXString Result;
     91   Result.data = String.data();
     92   Result.private_flags = (unsigned) CXS_Unmanaged;
     93   return Result;
     94 }
     95 
     96 CXString createDup(StringRef String) {
     97   CXString Result;
     98   char *Spelling = static_cast<char *>(llvm::safe_malloc(String.size() + 1));
     99   memmove(Spelling, String.data(), String.size());
    100   Spelling[String.size()] = 0;
    101   Result.data = Spelling;
    102   Result.private_flags = (unsigned) CXS_Malloc;
    103   return Result;
    104 }
    105 
    106 CXString createCXString(CXStringBuf *buf) {
    107   CXString Str;
    108   Str.data = buf;
    109   Str.private_flags = (unsigned) CXS_StringBuf;
    110   return Str;
    111 }
    112 
    113 CXStringSet *createSet(const std::vector<std::string> &Strings) {
    114   CXStringSet *Set = new CXStringSet;
    115   Set->Count = Strings.size();
    116   Set->Strings = new CXString[Set->Count];
    117   for (unsigned SI = 0, SE = Set->Count; SI < SE; ++SI)
    118     Set->Strings[SI] = createDup(Strings[SI]);
    119   return Set;
    120 }
    121 
    122 
    123 //===----------------------------------------------------------------------===//
    124 // String pools.
    125 //===----------------------------------------------------------------------===//
    126 
    127 CXStringPool::~CXStringPool() {
    128   for (std::vector<CXStringBuf *>::iterator I = Pool.begin(), E = Pool.end();
    129        I != E; ++I) {
    130     delete *I;
    131   }
    132 }
    133 
    134 CXStringBuf *CXStringPool::getCXStringBuf(CXTranslationUnit TU) {
    135   if (Pool.empty())
    136     return new CXStringBuf(TU);
    137 
    138   CXStringBuf *Buf = Pool.back();
    139   Buf->Data.clear();
    140   Pool.pop_back();
    141   return Buf;
    142 }
    143 
    144 CXStringBuf *getCXStringBuf(CXTranslationUnit TU) {
    145   return TU->StringPool->getCXStringBuf(TU);
    146 }
    147 
    148 void CXStringBuf::dispose() {
    149   TU->StringPool->Pool.push_back(this);
    150 }
    151 
    152 bool isManagedByPool(CXString str) {
    153   return ((CXStringFlag) str.private_flags) == CXS_StringBuf;
    154 }
    155 
    156 } // end namespace cxstring
    157 } // end namespace clang
    158 
    159 //===----------------------------------------------------------------------===//
    160 // libClang public APIs.
    161 //===----------------------------------------------------------------------===//
    162 
    163 const char *clang_getCString(CXString string) {
    164   if (string.private_flags == (unsigned) CXS_StringBuf) {
    165     return static_cast<const cxstring::CXStringBuf *>(string.data)->Data.data();
    166   }
    167   return static_cast<const char *>(string.data);
    168 }
    169 
    170 void clang_disposeString(CXString string) {
    171   switch ((CXStringFlag) string.private_flags) {
    172     case CXS_Unmanaged:
    173       break;
    174     case CXS_Malloc:
    175       if (string.data)
    176         free(const_cast<void *>(string.data));
    177       break;
    178     case CXS_StringBuf:
    179       static_cast<cxstring::CXStringBuf *>(
    180           const_cast<void *>(string.data))->dispose();
    181       break;
    182   }
    183 }
    184 
    185 void clang_disposeStringSet(CXStringSet *set) {
    186   for (unsigned SI = 0, SE = set->Count; SI < SE; ++SI)
    187     clang_disposeString(set->Strings[SI]);
    188   delete[] set->Strings;
    189   delete set;
    190 }
    191 
    192