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