/Users/buildslave/jenkins/workspace/coverage/llvm-project/clang/tools/libclang/CXString.cpp
Line | Count | Source (jump to first uncovered line) |
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 | 193k | CXString createEmpty() { |
44 | 193k | CXString Str; |
45 | 193k | Str.data = ""; |
46 | 193k | Str.private_flags = CXS_Unmanaged; |
47 | 193k | return Str; |
48 | 193k | } |
49 | | |
50 | 138k | CXString createNull() { |
51 | 138k | CXString Str; |
52 | 138k | Str.data = nullptr; |
53 | 138k | Str.private_flags = CXS_Unmanaged; |
54 | 138k | return Str; |
55 | 138k | } |
56 | | |
57 | 557k | CXString createRef(const char *String) { |
58 | 557k | if (String && String[0] == '\0'436k ) |
59 | 4 | return createEmpty(); |
60 | | |
61 | 557k | CXString Str; |
62 | 557k | Str.data = String; |
63 | 557k | Str.private_flags = CXS_Unmanaged; |
64 | 557k | return Str; |
65 | 557k | } |
66 | | |
67 | 0 | CXString createDup(const char *String) { |
68 | 0 | if (!String) |
69 | 0 | return createNull(); |
70 | | |
71 | 0 | if (String[0] == '\0') |
72 | 0 | return createEmpty(); |
73 | | |
74 | 0 | CXString Str; |
75 | 0 | Str.data = strdup(String); |
76 | 0 | Str.private_flags = CXS_Malloc; |
77 | 0 | return Str; |
78 | 0 | } |
79 | | |
80 | 147k | 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 | 147k | if (!String.empty() && String.data()[String.size()] != 021.7k ) |
88 | 3.36k | return createDup(String); |
89 | | |
90 | 144k | CXString Result; |
91 | 144k | Result.data = String.data(); |
92 | 144k | Result.private_flags = (unsigned) CXS_Unmanaged; |
93 | 144k | return Result; |
94 | 147k | } |
95 | | |
96 | 47.2k | CXString createDup(StringRef String) { |
97 | 47.2k | CXString Result; |
98 | 47.2k | char *Spelling = static_cast<char *>(llvm::safe_malloc(String.size() + 1)); |
99 | 47.2k | memmove(Spelling, String.data(), String.size()); |
100 | 47.2k | Spelling[String.size()] = 0; |
101 | 47.2k | Result.data = Spelling; |
102 | 47.2k | Result.private_flags = (unsigned) CXS_Malloc; |
103 | 47.2k | return Result; |
104 | 47.2k | } |
105 | | |
106 | 3.41k | CXString createCXString(CXStringBuf *buf) { |
107 | 3.41k | CXString Str; |
108 | 3.41k | Str.data = buf; |
109 | 3.41k | Str.private_flags = (unsigned) CXS_StringBuf; |
110 | 3.41k | return Str; |
111 | 3.41k | } |
112 | | |
113 | 64 | CXStringSet *createSet(const std::vector<std::string> &Strings) { |
114 | 64 | CXStringSet *Set = new CXStringSet; |
115 | 64 | Set->Count = Strings.size(); |
116 | 64 | Set->Strings = new CXString[Set->Count]; |
117 | 131 | for (unsigned SI = 0, SE = Set->Count; SI < SE; ++SI67 ) |
118 | 67 | Set->Strings[SI] = createDup(Strings[SI]); |
119 | 64 | return Set; |
120 | 64 | } |
121 | | |
122 | | |
123 | | //===----------------------------------------------------------------------===// |
124 | | // String pools. |
125 | | //===----------------------------------------------------------------------===// |
126 | | |
127 | 1.04k | CXStringPool::~CXStringPool() { |
128 | 1.04k | for (std::vector<CXStringBuf *>::iterator I = Pool.begin(), E = Pool.end(); |
129 | 1.18k | I != E; ++I132 ) { |
130 | 132 | delete *I; |
131 | 132 | } |
132 | 1.04k | } |
133 | | |
134 | 3.47k | CXStringBuf *CXStringPool::getCXStringBuf(CXTranslationUnit TU) { |
135 | 3.47k | if (Pool.empty()) |
136 | 132 | return new CXStringBuf(TU); |
137 | | |
138 | 3.34k | CXStringBuf *Buf = Pool.back(); |
139 | 3.34k | Buf->Data.clear(); |
140 | 3.34k | Pool.pop_back(); |
141 | 3.34k | return Buf; |
142 | 3.47k | } |
143 | | |
144 | 3.47k | CXStringBuf *getCXStringBuf(CXTranslationUnit TU) { |
145 | 3.47k | return TU->StringPool->getCXStringBuf(TU); |
146 | 3.47k | } |
147 | | |
148 | 3.47k | void CXStringBuf::dispose() { |
149 | 3.47k | TU->StringPool->Pool.push_back(this); |
150 | 3.47k | } |
151 | | |
152 | 0 | bool isManagedByPool(CXString str) { |
153 | 0 | return ((CXStringFlag) str.private_flags) == CXS_StringBuf; |
154 | 0 | } |
155 | | |
156 | | } // end namespace cxstring |
157 | | } // end namespace clang |
158 | | |
159 | | //===----------------------------------------------------------------------===// |
160 | | // libClang public APIs. |
161 | | //===----------------------------------------------------------------------===// |
162 | | |
163 | 798k | const char *clang_getCString(CXString string) { |
164 | 798k | if (string.private_flags == (unsigned) CXS_StringBuf) { |
165 | 3.41k | return static_cast<const cxstring::CXStringBuf *>(string.data)->Data.data(); |
166 | 3.41k | } |
167 | 795k | return static_cast<const char *>(string.data); |
168 | 798k | } |
169 | | |
170 | 1.08M | void clang_disposeString(CXString string) { |
171 | 1.08M | switch ((CXStringFlag) string.private_flags) { |
172 | 1.03M | case CXS_Unmanaged: |
173 | 1.03M | break; |
174 | 47.2k | case CXS_Malloc: |
175 | 47.2k | if (string.data) |
176 | 47.2k | free(const_cast<void *>(string.data)); |
177 | 47.2k | break; |
178 | 3.41k | case CXS_StringBuf: |
179 | 3.41k | static_cast<cxstring::CXStringBuf *>( |
180 | 3.41k | const_cast<void *>(string.data))->dispose(); |
181 | 3.41k | break; |
182 | 1.08M | } |
183 | 1.08M | } |
184 | | |
185 | 64 | void clang_disposeStringSet(CXStringSet *set) { |
186 | 131 | for (unsigned SI = 0, SE = set->Count; SI < SE; ++SI67 ) |
187 | 67 | clang_disposeString(set->Strings[SI]); |
188 | 64 | delete[] set->Strings; |
189 | 64 | delete set; |
190 | 64 | } |
191 | | |