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
21using namespace clang;
22
23/// Describes the kind of underlying data in CXString.
24enum 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
36namespace clang {
37namespace cxstring {
38
39//===----------------------------------------------------------------------===//
40// Basic generation of CXStrings.
41//===----------------------------------------------------------------------===//
42
43CXString createEmpty() {
44 CXString Str;
45 Str.data = "";
46 Str.private_flags = CXS_Unmanaged;
47 return Str;
48}
49
50CXString createNull() {
51 CXString Str;
52 Str.data = nullptr;
53 Str.private_flags = CXS_Unmanaged;
54 return Str;
55}
56
57CXString 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
67CXString 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(s: String);
76 Str.private_flags = CXS_Malloc;
77 return Str;
78}
79
80CXString 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
105CXString createDup(StringRef String) {
106 CXString Result;
107 char *Spelling = static_cast<char *>(llvm::safe_malloc(Sz: String.size() + 1));
108 memmove(dest: Spelling, src: String.data(), n: String.size());
109 Spelling[String.size()] = 0;
110 Result.data = Spelling;
111 Result.private_flags = (unsigned) CXS_Malloc;
112 return Result;
113}
114
115CXString createCXString(CXStringBuf *buf) {
116 CXString Str;
117 Str.data = buf;
118 Str.private_flags = (unsigned) CXS_StringBuf;
119 return Str;
120}
121
122CXStringSet *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(String: Strings[SI]);
128 return Set;
129}
130
131
132//===----------------------------------------------------------------------===//
133// String pools.
134//===----------------------------------------------------------------------===//
135
136CXStringPool::~CXStringPool() {
137 for (std::vector<CXStringBuf *>::iterator I = Pool.begin(), E = Pool.end();
138 I != E; ++I) {
139 delete *I;
140 }
141}
142
143CXStringBuf *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
153CXStringBuf *getCXStringBuf(CXTranslationUnit TU) {
154 return TU->StringPool->getCXStringBuf(TU);
155}
156
157void CXStringBuf::dispose() {
158 TU->StringPool->Pool.push_back(x: this);
159}
160
161bool 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
172const 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
179void 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(ptr: 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
194void clang_disposeStringSet(CXStringSet *set) {
195 for (unsigned SI = 0, SE = set->Count; SI < SE; ++SI)
196 clang_disposeString(string: set->Strings[SI]);
197 delete[] set->Strings;
198 delete set;
199}
200
201