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 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
createDup(StringRef String)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
createCXString(CXStringBuf * buf)106 CXString createCXString(CXStringBuf *buf) {
107 CXString Str;
108 Str.data = buf;
109 Str.private_flags = (unsigned) CXS_StringBuf;
110 return Str;
111 }
112
createSet(const std::vector<std::string> & Strings)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
~CXStringPool()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
getCXStringBuf(CXTranslationUnit TU)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
getCXStringBuf(CXTranslationUnit TU)144 CXStringBuf *getCXStringBuf(CXTranslationUnit TU) {
145 return TU->StringPool->getCXStringBuf(TU);
146 }
147
dispose()148 void CXStringBuf::dispose() {
149 TU->StringPool->Pool.push_back(this);
150 }
151
isManagedByPool(CXString str)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
clang_getCString(CXString string)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
clang_disposeString(CXString string)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
clang_disposeStringSet(CXStringSet * set)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