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 
createEmpty()43 CXString createEmpty() {
44   CXString Str;
45   Str.data = "";
46   Str.private_flags = CXS_Unmanaged;
47   return Str;
48 }
49 
createNull()50 CXString createNull() {
51   CXString Str;
52   Str.data = nullptr;
53   Str.private_flags = CXS_Unmanaged;
54   return Str;
55 }
56 
createRef(const char * String)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 
createDup(const char * String)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 
createRef(StringRef String)80 CXString createRef(StringRef String) {
81   if (!String.data())
82     return createNull();
83 
84   // If the string is empty, it might point to a position in another string
85   // while having zero length. Make sure we don't create a reference to the
86   // larger string.
87   if (String.empty())
88     return createEmpty();
89 
90   // If the string is not nul-terminated, we have to make a copy.
91 
92   // FIXME: This is doing a one past end read, and should be removed! For memory
93   // we don't manage, the API string can become unterminated at any time outside
94   // our control.
95 
96   if (String.data()[String.size()] != 0)
97     return createDup(String);
98 
99   CXString Result;
100   Result.data = String.data();
101   Result.private_flags = (unsigned) CXS_Unmanaged;
102   return Result;
103 }
104 
createDup(StringRef String)105 CXString createDup(StringRef String) {
106   CXString Result;
107   char *Spelling = static_cast<char *>(llvm::safe_malloc(String.size() + 1));
108   memmove(Spelling, String.data(), String.size());
109   Spelling[String.size()] = 0;
110   Result.data = Spelling;
111   Result.private_flags = (unsigned) CXS_Malloc;
112   return Result;
113 }
114 
createCXString(CXStringBuf * buf)115 CXString createCXString(CXStringBuf *buf) {
116   CXString Str;
117   Str.data = buf;
118   Str.private_flags = (unsigned) CXS_StringBuf;
119   return Str;
120 }
121 
createSet(const std::vector<std::string> & Strings)122 CXStringSet *createSet(const std::vector<std::string> &Strings) {
123   CXStringSet *Set = new CXStringSet;
124   Set->Count = Strings.size();
125   Set->Strings = new CXString[Set->Count];
126   for (unsigned SI = 0, SE = Set->Count; SI < SE; ++SI)
127     Set->Strings[SI] = createDup(Strings[SI]);
128   return Set;
129 }
130 
131 
132 //===----------------------------------------------------------------------===//
133 // String pools.
134 //===----------------------------------------------------------------------===//
135 
~CXStringPool()136 CXStringPool::~CXStringPool() {
137   for (std::vector<CXStringBuf *>::iterator I = Pool.begin(), E = Pool.end();
138        I != E; ++I) {
139     delete *I;
140   }
141 }
142 
getCXStringBuf(CXTranslationUnit TU)143 CXStringBuf *CXStringPool::getCXStringBuf(CXTranslationUnit TU) {
144   if (Pool.empty())
145     return new CXStringBuf(TU);
146 
147   CXStringBuf *Buf = Pool.back();
148   Buf->Data.clear();
149   Pool.pop_back();
150   return Buf;
151 }
152 
getCXStringBuf(CXTranslationUnit TU)153 CXStringBuf *getCXStringBuf(CXTranslationUnit TU) {
154   return TU->StringPool->getCXStringBuf(TU);
155 }
156 
dispose()157 void CXStringBuf::dispose() {
158   TU->StringPool->Pool.push_back(this);
159 }
160 
isManagedByPool(CXString str)161 bool isManagedByPool(CXString str) {
162   return ((CXStringFlag) str.private_flags) == CXS_StringBuf;
163 }
164 
165 } // end namespace cxstring
166 } // end namespace clang
167 
168 //===----------------------------------------------------------------------===//
169 // libClang public APIs.
170 //===----------------------------------------------------------------------===//
171 
clang_getCString(CXString string)172 const char *clang_getCString(CXString string) {
173   if (string.private_flags == (unsigned) CXS_StringBuf) {
174     return static_cast<const cxstring::CXStringBuf *>(string.data)->Data.data();
175   }
176   return static_cast<const char *>(string.data);
177 }
178 
clang_disposeString(CXString string)179 void clang_disposeString(CXString string) {
180   switch ((CXStringFlag) string.private_flags) {
181     case CXS_Unmanaged:
182       break;
183     case CXS_Malloc:
184       if (string.data)
185         free(const_cast<void *>(string.data));
186       break;
187     case CXS_StringBuf:
188       static_cast<cxstring::CXStringBuf *>(
189           const_cast<void *>(string.data))->dispose();
190       break;
191   }
192 }
193 
clang_disposeStringSet(CXStringSet * set)194 void clang_disposeStringSet(CXStringSet *set) {
195   for (unsigned SI = 0, SE = set->Count; SI < SE; ++SI)
196     clang_disposeString(set->Strings[SI]);
197   delete[] set->Strings;
198   delete set;
199 }
200 
201