File: | include/llvm/ADT/IntrusiveRefCntPtr.h |
Warning: | line 157, column 38 Potential leak of memory pointed to by field 'Obj' |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | //===-- clang-format/ClangFormat.cpp - Clang format tool ------------------===// | |||
2 | // | |||
3 | // The LLVM Compiler Infrastructure | |||
4 | // | |||
5 | // This file is distributed under the University of Illinois Open Source | |||
6 | // License. See LICENSE.TXT for details. | |||
7 | // | |||
8 | //===----------------------------------------------------------------------===// | |||
9 | /// | |||
10 | /// \file | |||
11 | /// This file implements a clang-format tool that automatically formats | |||
12 | /// (fragments of) C++ code. | |||
13 | /// | |||
14 | //===----------------------------------------------------------------------===// | |||
15 | ||||
16 | #include "clang/Basic/Diagnostic.h" | |||
17 | #include "clang/Basic/DiagnosticOptions.h" | |||
18 | #include "clang/Basic/FileManager.h" | |||
19 | #include "clang/Basic/SourceManager.h" | |||
20 | #include "clang/Basic/Version.h" | |||
21 | #include "clang/Format/Format.h" | |||
22 | #include "clang/Rewrite/Core/Rewriter.h" | |||
23 | #include "llvm/Support/CommandLine.h" | |||
24 | #include "llvm/Support/FileSystem.h" | |||
25 | #include "llvm/Support/InitLLVM.h" | |||
26 | #include "llvm/Support/Process.h" | |||
27 | ||||
28 | using namespace llvm; | |||
29 | using clang::tooling::Replacements; | |||
30 | ||||
31 | static cl::opt<bool> Help("h", cl::desc("Alias for -help"), cl::Hidden); | |||
32 | ||||
33 | // Mark all our options with this category, everything else (except for -version | |||
34 | // and -help) will be hidden. | |||
35 | static cl::OptionCategory ClangFormatCategory("Clang-format options"); | |||
36 | ||||
37 | static cl::list<unsigned> | |||
38 | Offsets("offset", | |||
39 | cl::desc("Format a range starting at this byte offset.\n" | |||
40 | "Multiple ranges can be formatted by specifying\n" | |||
41 | "several -offset and -length pairs.\n" | |||
42 | "Can only be used with one input file."), | |||
43 | cl::cat(ClangFormatCategory)); | |||
44 | static cl::list<unsigned> | |||
45 | Lengths("length", | |||
46 | cl::desc("Format a range of this length (in bytes).\n" | |||
47 | "Multiple ranges can be formatted by specifying\n" | |||
48 | "several -offset and -length pairs.\n" | |||
49 | "When only a single -offset is specified without\n" | |||
50 | "-length, clang-format will format up to the end\n" | |||
51 | "of the file.\n" | |||
52 | "Can only be used with one input file."), | |||
53 | cl::cat(ClangFormatCategory)); | |||
54 | static cl::list<std::string> | |||
55 | LineRanges("lines", cl::desc("<start line>:<end line> - format a range of\n" | |||
56 | "lines (both 1-based).\n" | |||
57 | "Multiple ranges can be formatted by specifying\n" | |||
58 | "several -lines arguments.\n" | |||
59 | "Can't be used with -offset and -length.\n" | |||
60 | "Can only be used with one input file."), | |||
61 | cl::cat(ClangFormatCategory)); | |||
62 | static cl::opt<std::string> | |||
63 | Style("style", cl::desc(clang::format::StyleOptionHelpDescription), | |||
64 | cl::init(clang::format::DefaultFormatStyle), | |||
65 | cl::cat(ClangFormatCategory)); | |||
66 | static cl::opt<std::string> | |||
67 | FallbackStyle("fallback-style", | |||
68 | cl::desc("The name of the predefined style used as a\n" | |||
69 | "fallback in case clang-format is invoked with\n" | |||
70 | "-style=file, but can not find the .clang-format\n" | |||
71 | "file to use.\n" | |||
72 | "Use -fallback-style=none to skip formatting."), | |||
73 | cl::init(clang::format::DefaultFallbackStyle), | |||
74 | cl::cat(ClangFormatCategory)); | |||
75 | ||||
76 | static cl::opt<std::string> | |||
77 | AssumeFileName("assume-filename", | |||
78 | cl::desc("When reading from stdin, clang-format assumes this\n" | |||
79 | "filename to look for a style config file (with\n" | |||
80 | "-style=file) and to determine the language."), | |||
81 | cl::init("<stdin>"), cl::cat(ClangFormatCategory)); | |||
82 | ||||
83 | static cl::opt<bool> Inplace("i", | |||
84 | cl::desc("Inplace edit <file>s, if specified."), | |||
85 | cl::cat(ClangFormatCategory)); | |||
86 | ||||
87 | static cl::opt<bool> OutputXML("output-replacements-xml", | |||
88 | cl::desc("Output replacements as XML."), | |||
89 | cl::cat(ClangFormatCategory)); | |||
90 | static cl::opt<bool> | |||
91 | DumpConfig("dump-config", | |||
92 | cl::desc("Dump configuration options to stdout and exit.\n" | |||
93 | "Can be used with -style option."), | |||
94 | cl::cat(ClangFormatCategory)); | |||
95 | static cl::opt<unsigned> | |||
96 | Cursor("cursor", | |||
97 | cl::desc("The position of the cursor when invoking\n" | |||
98 | "clang-format from an editor integration"), | |||
99 | cl::init(0), cl::cat(ClangFormatCategory)); | |||
100 | ||||
101 | static cl::opt<bool> SortIncludes( | |||
102 | "sort-includes", | |||
103 | cl::desc("If set, overrides the include sorting behavior determined by the " | |||
104 | "SortIncludes style flag"), | |||
105 | cl::cat(ClangFormatCategory)); | |||
106 | ||||
107 | static cl::opt<bool> | |||
108 | Verbose("verbose", cl::desc("If set, shows the list of processed files"), | |||
109 | cl::cat(ClangFormatCategory)); | |||
110 | ||||
111 | static cl::list<std::string> FileNames(cl::Positional, cl::desc("[<file> ...]"), | |||
112 | cl::cat(ClangFormatCategory)); | |||
113 | ||||
114 | namespace clang { | |||
115 | namespace format { | |||
116 | ||||
117 | static FileID createInMemoryFile(StringRef FileName, MemoryBuffer *Source, | |||
118 | SourceManager &Sources, FileManager &Files, | |||
119 | vfs::InMemoryFileSystem *MemFS) { | |||
120 | MemFS->addFileNoOwn(FileName, 0, Source); | |||
121 | return Sources.createFileID(Files.getFile(FileName), SourceLocation(), | |||
122 | SrcMgr::C_User); | |||
123 | } | |||
124 | ||||
125 | // Parses <start line>:<end line> input to a pair of line numbers. | |||
126 | // Returns true on error. | |||
127 | static bool parseLineRange(StringRef Input, unsigned &FromLine, | |||
128 | unsigned &ToLine) { | |||
129 | std::pair<StringRef, StringRef> LineRange = Input.split(':'); | |||
130 | return LineRange.first.getAsInteger(0, FromLine) || | |||
131 | LineRange.second.getAsInteger(0, ToLine); | |||
132 | } | |||
133 | ||||
134 | static bool fillRanges(MemoryBuffer *Code, | |||
135 | std::vector<tooling::Range> &Ranges) { | |||
136 | IntrusiveRefCntPtr<vfs::InMemoryFileSystem> InMemoryFileSystem( | |||
137 | new vfs::InMemoryFileSystem); | |||
138 | FileManager Files(FileSystemOptions(), InMemoryFileSystem); | |||
139 | DiagnosticsEngine Diagnostics( | |||
140 | IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs), | |||
141 | new DiagnosticOptions); | |||
142 | SourceManager Sources(Diagnostics, Files); | |||
143 | FileID ID = createInMemoryFile("<irrelevant>", Code, Sources, Files, | |||
144 | InMemoryFileSystem.get()); | |||
145 | if (!LineRanges.empty()) { | |||
146 | if (!Offsets.empty() || !Lengths.empty()) { | |||
147 | errs() << "error: cannot use -lines with -offset/-length\n"; | |||
148 | return true; | |||
149 | } | |||
150 | ||||
151 | for (unsigned i = 0, e = LineRanges.size(); i < e; ++i) { | |||
152 | unsigned FromLine, ToLine; | |||
153 | if (parseLineRange(LineRanges[i], FromLine, ToLine)) { | |||
154 | errs() << "error: invalid <start line>:<end line> pair\n"; | |||
155 | return true; | |||
156 | } | |||
157 | if (FromLine > ToLine) { | |||
158 | errs() << "error: start line should be less than end line\n"; | |||
159 | return true; | |||
160 | } | |||
161 | SourceLocation Start = Sources.translateLineCol(ID, FromLine, 1); | |||
162 | SourceLocation End = Sources.translateLineCol(ID, ToLine, UINT_MAX(2147483647 *2U +1U)); | |||
163 | if (Start.isInvalid() || End.isInvalid()) | |||
164 | return true; | |||
165 | unsigned Offset = Sources.getFileOffset(Start); | |||
166 | unsigned Length = Sources.getFileOffset(End) - Offset; | |||
167 | Ranges.push_back(tooling::Range(Offset, Length)); | |||
168 | } | |||
169 | return false; | |||
170 | } | |||
171 | ||||
172 | if (Offsets.empty()) | |||
173 | Offsets.push_back(0); | |||
174 | if (Offsets.size() != Lengths.size() && | |||
175 | !(Offsets.size() == 1 && Lengths.empty())) { | |||
176 | errs() << "error: number of -offset and -length arguments must match.\n"; | |||
177 | return true; | |||
178 | } | |||
179 | for (unsigned i = 0, e = Offsets.size(); i != e; ++i) { | |||
180 | if (Offsets[i] >= Code->getBufferSize()) { | |||
181 | errs() << "error: offset " << Offsets[i] << " is outside the file\n"; | |||
182 | return true; | |||
183 | } | |||
184 | SourceLocation Start = | |||
185 | Sources.getLocForStartOfFile(ID).getLocWithOffset(Offsets[i]); | |||
186 | SourceLocation End; | |||
187 | if (i < Lengths.size()) { | |||
188 | if (Offsets[i] + Lengths[i] > Code->getBufferSize()) { | |||
189 | errs() << "error: invalid length " << Lengths[i] | |||
190 | << ", offset + length (" << Offsets[i] + Lengths[i] | |||
191 | << ") is outside the file.\n"; | |||
192 | return true; | |||
193 | } | |||
194 | End = Start.getLocWithOffset(Lengths[i]); | |||
195 | } else { | |||
196 | End = Sources.getLocForEndOfFile(ID); | |||
197 | } | |||
198 | unsigned Offset = Sources.getFileOffset(Start); | |||
199 | unsigned Length = Sources.getFileOffset(End) - Offset; | |||
200 | Ranges.push_back(tooling::Range(Offset, Length)); | |||
201 | } | |||
202 | return false; | |||
203 | } | |||
204 | ||||
205 | static void outputReplacementXML(StringRef Text) { | |||
206 | // FIXME: When we sort includes, we need to make sure the stream is correct | |||
207 | // utf-8. | |||
208 | size_t From = 0; | |||
209 | size_t Index; | |||
210 | while ((Index = Text.find_first_of("\n\r<&", From)) != StringRef::npos) { | |||
211 | outs() << Text.substr(From, Index - From); | |||
212 | switch (Text[Index]) { | |||
213 | case '\n': | |||
214 | outs() << " "; | |||
215 | break; | |||
216 | case '\r': | |||
217 | outs() << " "; | |||
218 | break; | |||
219 | case '<': | |||
220 | outs() << "<"; | |||
221 | break; | |||
222 | case '&': | |||
223 | outs() << "&"; | |||
224 | break; | |||
225 | default: | |||
226 | llvm_unreachable("Unexpected character encountered!")::llvm::llvm_unreachable_internal("Unexpected character encountered!" , "/build/llvm-toolchain-snapshot-7~svn338205/tools/clang/tools/clang-format/ClangFormat.cpp" , 226); | |||
227 | } | |||
228 | From = Index + 1; | |||
229 | } | |||
230 | outs() << Text.substr(From); | |||
231 | } | |||
232 | ||||
233 | static void outputReplacementsXML(const Replacements &Replaces) { | |||
234 | for (const auto &R : Replaces) { | |||
235 | outs() << "<replacement " | |||
236 | << "offset='" << R.getOffset() << "' " | |||
237 | << "length='" << R.getLength() << "'>"; | |||
238 | outputReplacementXML(R.getReplacementText()); | |||
239 | outs() << "</replacement>\n"; | |||
240 | } | |||
241 | } | |||
242 | ||||
243 | // Returns true on error. | |||
244 | static bool format(StringRef FileName) { | |||
245 | if (!OutputXML && Inplace && FileName == "-") { | |||
246 | errs() << "error: cannot use -i when reading from stdin.\n"; | |||
247 | return false; | |||
248 | } | |||
249 | // On Windows, overwriting a file with an open file mapping doesn't work, | |||
250 | // so read the whole file into memory when formatting in-place. | |||
251 | ErrorOr<std::unique_ptr<MemoryBuffer>> CodeOrErr = | |||
252 | !OutputXML && Inplace ? MemoryBuffer::getFileAsStream(FileName) : | |||
253 | MemoryBuffer::getFileOrSTDIN(FileName); | |||
254 | if (std::error_code EC = CodeOrErr.getError()) { | |||
255 | errs() << EC.message() << "\n"; | |||
256 | return true; | |||
257 | } | |||
258 | std::unique_ptr<llvm::MemoryBuffer> Code = std::move(CodeOrErr.get()); | |||
259 | if (Code->getBufferSize() == 0) | |||
260 | return false; // Empty files are formatted correctly. | |||
261 | std::vector<tooling::Range> Ranges; | |||
262 | if (fillRanges(Code.get(), Ranges)) | |||
263 | return true; | |||
264 | StringRef AssumedFileName = (FileName == "-") ? AssumeFileName : FileName; | |||
265 | ||||
266 | llvm::Expected<FormatStyle> FormatStyle = | |||
267 | getStyle(Style, AssumedFileName, FallbackStyle, Code->getBuffer()); | |||
268 | if (!FormatStyle) { | |||
269 | llvm::errs() << llvm::toString(FormatStyle.takeError()) << "\n"; | |||
270 | return true; | |||
271 | } | |||
272 | ||||
273 | if (SortIncludes.getNumOccurrences() != 0) | |||
274 | FormatStyle->SortIncludes = SortIncludes; | |||
275 | unsigned CursorPosition = Cursor; | |||
276 | Replacements Replaces = sortIncludes(*FormatStyle, Code->getBuffer(), Ranges, | |||
277 | AssumedFileName, &CursorPosition); | |||
278 | auto ChangedCode = tooling::applyAllReplacements(Code->getBuffer(), Replaces); | |||
279 | if (!ChangedCode) { | |||
280 | llvm::errs() << llvm::toString(ChangedCode.takeError()) << "\n"; | |||
281 | return true; | |||
282 | } | |||
283 | // Get new affected ranges after sorting `#includes`. | |||
284 | Ranges = tooling::calculateRangesAfterReplacements(Replaces, Ranges); | |||
285 | FormattingAttemptStatus Status; | |||
286 | Replacements FormatChanges = reformat(*FormatStyle, *ChangedCode, Ranges, | |||
287 | AssumedFileName, &Status); | |||
288 | Replaces = Replaces.merge(FormatChanges); | |||
289 | if (OutputXML) { | |||
290 | outs() << "<?xml version='1.0'?>\n<replacements " | |||
291 | "xml:space='preserve' incomplete_format='" | |||
292 | << (Status.FormatComplete ? "false" : "true") << "'"; | |||
293 | if (!Status.FormatComplete) | |||
294 | outs() << " line='" << Status.Line << "'"; | |||
295 | outs() << ">\n"; | |||
296 | if (Cursor.getNumOccurrences() != 0) | |||
297 | outs() << "<cursor>" | |||
298 | << FormatChanges.getShiftedCodePosition(CursorPosition) | |||
299 | << "</cursor>\n"; | |||
300 | ||||
301 | outputReplacementsXML(Replaces); | |||
302 | outs() << "</replacements>\n"; | |||
303 | } else { | |||
304 | IntrusiveRefCntPtr<vfs::InMemoryFileSystem> InMemoryFileSystem( | |||
305 | new vfs::InMemoryFileSystem); | |||
306 | FileManager Files(FileSystemOptions(), InMemoryFileSystem); | |||
307 | DiagnosticsEngine Diagnostics( | |||
308 | IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs), | |||
309 | new DiagnosticOptions); | |||
310 | SourceManager Sources(Diagnostics, Files); | |||
311 | FileID ID = createInMemoryFile(AssumedFileName, Code.get(), Sources, Files, | |||
312 | InMemoryFileSystem.get()); | |||
313 | Rewriter Rewrite(Sources, LangOptions()); | |||
314 | tooling::applyAllReplacements(Replaces, Rewrite); | |||
315 | if (Inplace) { | |||
316 | if (Rewrite.overwriteChangedFiles()) | |||
317 | return true; | |||
318 | } else { | |||
319 | if (Cursor.getNumOccurrences() != 0) { | |||
320 | outs() << "{ \"Cursor\": " | |||
321 | << FormatChanges.getShiftedCodePosition(CursorPosition) | |||
322 | << ", \"IncompleteFormat\": " | |||
323 | << (Status.FormatComplete ? "false" : "true"); | |||
324 | if (!Status.FormatComplete) | |||
325 | outs() << ", \"Line\": " << Status.Line; | |||
326 | outs() << " }\n"; | |||
327 | } | |||
328 | Rewrite.getEditBuffer(ID).write(outs()); | |||
329 | } | |||
330 | } | |||
331 | return false; | |||
332 | } | |||
333 | ||||
334 | } // namespace format | |||
335 | } // namespace clang | |||
336 | ||||
337 | static void PrintVersion(raw_ostream &OS) { | |||
338 | OS << clang::getClangToolFullVersion("clang-format") << '\n'; | |||
339 | } | |||
340 | ||||
341 | int main(int argc, const char **argv) { | |||
342 | llvm::InitLLVM X(argc, argv); | |||
343 | ||||
344 | cl::HideUnrelatedOptions(ClangFormatCategory); | |||
345 | ||||
346 | cl::SetVersionPrinter(PrintVersion); | |||
347 | cl::ParseCommandLineOptions( | |||
348 | argc, argv, | |||
349 | "A tool to format C/C++/Java/JavaScript/Objective-C/Protobuf code.\n\n" | |||
350 | "If no arguments are specified, it formats the code from standard input\n" | |||
351 | "and writes the result to the standard output.\n" | |||
352 | "If <file>s are given, it reformats the files. If -i is specified\n" | |||
353 | "together with <file>s, the files are edited in-place. Otherwise, the\n" | |||
354 | "result is written to the standard output.\n"); | |||
355 | ||||
356 | if (Help) { | |||
| ||||
357 | cl::PrintHelpMessage(); | |||
358 | return 0; | |||
359 | } | |||
360 | ||||
361 | if (DumpConfig) { | |||
362 | StringRef FileName; | |||
363 | std::unique_ptr<llvm::MemoryBuffer> Code; | |||
364 | if (FileNames.empty()) { | |||
365 | // We can't read the code to detect the language if there's no | |||
366 | // file name, so leave Code empty here. | |||
367 | FileName = AssumeFileName; | |||
368 | } else { | |||
369 | // Read in the code in case the filename alone isn't enough to | |||
370 | // detect the language. | |||
371 | ErrorOr<std::unique_ptr<MemoryBuffer>> CodeOrErr = | |||
372 | MemoryBuffer::getFileOrSTDIN(FileNames[0]); | |||
373 | if (std::error_code EC = CodeOrErr.getError()) { | |||
374 | llvm::errs() << EC.message() << "\n"; | |||
375 | return 1; | |||
376 | } | |||
377 | FileName = (FileNames[0] == "-") ? AssumeFileName : FileNames[0]; | |||
378 | Code = std::move(CodeOrErr.get()); | |||
379 | } | |||
380 | llvm::Expected<clang::format::FormatStyle> FormatStyle = | |||
381 | clang::format::getStyle(Style, FileName, FallbackStyle, | |||
382 | Code ? Code->getBuffer() : ""); | |||
383 | if (!FormatStyle) { | |||
384 | llvm::errs() << llvm::toString(FormatStyle.takeError()) << "\n"; | |||
385 | return 1; | |||
386 | } | |||
387 | std::string Config = clang::format::configurationAsText(*FormatStyle); | |||
388 | outs() << Config << "\n"; | |||
389 | return 0; | |||
390 | } | |||
391 | ||||
392 | bool Error = false; | |||
393 | if (FileNames.empty()) { | |||
394 | Error = clang::format::format("-"); | |||
395 | return Error ? 1 : 0; | |||
396 | } | |||
397 | if (FileNames.size() != 1 && (!Offsets.empty() || !Lengths.empty() || !LineRanges.empty())) { | |||
398 | errs() << "error: -offset, -length and -lines can only be used for " | |||
399 | "single file.\n"; | |||
400 | return 1; | |||
401 | } | |||
402 | for (const auto &FileName : FileNames) { | |||
403 | if (Verbose) | |||
404 | errs() << "Formatting " << FileName << "\n"; | |||
405 | Error |= clang::format::format(FileName); | |||
406 | } | |||
407 | return Error ? 1 : 0; | |||
408 | } |
1 | //==- llvm/ADT/IntrusiveRefCntPtr.h - Smart Refcounting Pointer --*- C++ -*-==// | |||
2 | // | |||
3 | // The LLVM Compiler Infrastructure | |||
4 | // | |||
5 | // This file is distributed under the University of Illinois Open Source | |||
6 | // License. See LICENSE.TXT for details. | |||
7 | // | |||
8 | //===----------------------------------------------------------------------===// | |||
9 | // | |||
10 | // This file defines the RefCountedBase, ThreadSafeRefCountedBase, and | |||
11 | // IntrusiveRefCntPtr classes. | |||
12 | // | |||
13 | // IntrusiveRefCntPtr is a smart pointer to an object which maintains a | |||
14 | // reference count. (ThreadSafe)RefCountedBase is a mixin class that adds a | |||
15 | // refcount member variable and methods for updating the refcount. An object | |||
16 | // that inherits from (ThreadSafe)RefCountedBase deletes itself when its | |||
17 | // refcount hits zero. | |||
18 | // | |||
19 | // For example: | |||
20 | // | |||
21 | // class MyClass : public RefCountedBase<MyClass> {}; | |||
22 | // | |||
23 | // void foo() { | |||
24 | // // Constructing an IntrusiveRefCntPtr increases the pointee's refcount by | |||
25 | // // 1 (from 0 in this case). | |||
26 | // IntrusiveRefCntPtr<MyClass> Ptr1(new MyClass()); | |||
27 | // | |||
28 | // // Copying an IntrusiveRefCntPtr increases the pointee's refcount by 1. | |||
29 | // IntrusiveRefCntPtr<MyClass> Ptr2(Ptr1); | |||
30 | // | |||
31 | // // Constructing an IntrusiveRefCntPtr has no effect on the object's | |||
32 | // // refcount. After a move, the moved-from pointer is null. | |||
33 | // IntrusiveRefCntPtr<MyClass> Ptr3(std::move(Ptr1)); | |||
34 | // assert(Ptr1 == nullptr); | |||
35 | // | |||
36 | // // Clearing an IntrusiveRefCntPtr decreases the pointee's refcount by 1. | |||
37 | // Ptr2.reset(); | |||
38 | // | |||
39 | // // The object deletes itself when we return from the function, because | |||
40 | // // Ptr3's destructor decrements its refcount to 0. | |||
41 | // } | |||
42 | // | |||
43 | // You can use IntrusiveRefCntPtr with isa<T>(), dyn_cast<T>(), etc.: | |||
44 | // | |||
45 | // IntrusiveRefCntPtr<MyClass> Ptr(new MyClass()); | |||
46 | // OtherClass *Other = dyn_cast<OtherClass>(Ptr); // Ptr.get() not required | |||
47 | // | |||
48 | // IntrusiveRefCntPtr works with any class that | |||
49 | // | |||
50 | // - inherits from (ThreadSafe)RefCountedBase, | |||
51 | // - has Retain() and Release() methods, or | |||
52 | // - specializes IntrusiveRefCntPtrInfo. | |||
53 | // | |||
54 | //===----------------------------------------------------------------------===// | |||
55 | ||||
56 | #ifndef LLVM_ADT_INTRUSIVEREFCNTPTR_H | |||
57 | #define LLVM_ADT_INTRUSIVEREFCNTPTR_H | |||
58 | ||||
59 | #include <atomic> | |||
60 | #include <cassert> | |||
61 | #include <cstddef> | |||
62 | ||||
63 | namespace llvm { | |||
64 | ||||
65 | /// A CRTP mixin class that adds reference counting to a type. | |||
66 | /// | |||
67 | /// The lifetime of an object which inherits from RefCountedBase is managed by | |||
68 | /// calls to Release() and Retain(), which increment and decrement the object's | |||
69 | /// refcount, respectively. When a Release() call decrements the refcount to 0, | |||
70 | /// the object deletes itself. | |||
71 | template <class Derived> class RefCountedBase { | |||
72 | mutable unsigned RefCount = 0; | |||
73 | ||||
74 | public: | |||
75 | RefCountedBase() = default; | |||
76 | RefCountedBase(const RefCountedBase &) {} | |||
77 | ||||
78 | void Retain() const { ++RefCount; } | |||
79 | ||||
80 | void Release() const { | |||
81 | assert(RefCount > 0 && "Reference count is already zero.")(static_cast <bool> (RefCount > 0 && "Reference count is already zero." ) ? void (0) : __assert_fail ("RefCount > 0 && \"Reference count is already zero.\"" , "/build/llvm-toolchain-snapshot-7~svn338205/include/llvm/ADT/IntrusiveRefCntPtr.h" , 81, __extension__ __PRETTY_FUNCTION__)); | |||
82 | if (--RefCount == 0) | |||
83 | delete static_cast<const Derived *>(this); | |||
84 | } | |||
85 | }; | |||
86 | ||||
87 | /// A thread-safe version of \c RefCountedBase. | |||
88 | template <class Derived> class ThreadSafeRefCountedBase { | |||
89 | mutable std::atomic<int> RefCount; | |||
90 | ||||
91 | protected: | |||
92 | ThreadSafeRefCountedBase() : RefCount(0) {} | |||
93 | ||||
94 | public: | |||
95 | void Retain() const { RefCount.fetch_add(1, std::memory_order_relaxed); } | |||
96 | ||||
97 | void Release() const { | |||
98 | int NewRefCount = RefCount.fetch_sub(1, std::memory_order_acq_rel) - 1; | |||
99 | assert(NewRefCount >= 0 && "Reference count was already zero.")(static_cast <bool> (NewRefCount >= 0 && "Reference count was already zero." ) ? void (0) : __assert_fail ("NewRefCount >= 0 && \"Reference count was already zero.\"" , "/build/llvm-toolchain-snapshot-7~svn338205/include/llvm/ADT/IntrusiveRefCntPtr.h" , 99, __extension__ __PRETTY_FUNCTION__)); | |||
100 | if (NewRefCount == 0) | |||
101 | delete static_cast<const Derived *>(this); | |||
102 | } | |||
103 | }; | |||
104 | ||||
105 | /// Class you can specialize to provide custom retain/release functionality for | |||
106 | /// a type. | |||
107 | /// | |||
108 | /// Usually specializing this class is not necessary, as IntrusiveRefCntPtr | |||
109 | /// works with any type which defines Retain() and Release() functions -- you | |||
110 | /// can define those functions yourself if RefCountedBase doesn't work for you. | |||
111 | /// | |||
112 | /// One case when you might want to specialize this type is if you have | |||
113 | /// - Foo.h defines type Foo and includes Bar.h, and | |||
114 | /// - Bar.h uses IntrusiveRefCntPtr<Foo> in inline functions. | |||
115 | /// | |||
116 | /// Because Foo.h includes Bar.h, Bar.h can't include Foo.h in order to pull in | |||
117 | /// the declaration of Foo. Without the declaration of Foo, normally Bar.h | |||
118 | /// wouldn't be able to use IntrusiveRefCntPtr<Foo>, which wants to call | |||
119 | /// T::Retain and T::Release. | |||
120 | /// | |||
121 | /// To resolve this, Bar.h could include a third header, FooFwd.h, which | |||
122 | /// forward-declares Foo and specializes IntrusiveRefCntPtrInfo<Foo>. Then | |||
123 | /// Bar.h could use IntrusiveRefCntPtr<Foo>, although it still couldn't call any | |||
124 | /// functions on Foo itself, because Foo would be an incomplete type. | |||
125 | template <typename T> struct IntrusiveRefCntPtrInfo { | |||
126 | static void retain(T *obj) { obj->Retain(); } | |||
127 | static void release(T *obj) { obj->Release(); } | |||
128 | }; | |||
129 | ||||
130 | /// A smart pointer to a reference-counted object that inherits from | |||
131 | /// RefCountedBase or ThreadSafeRefCountedBase. | |||
132 | /// | |||
133 | /// This class increments its pointee's reference count when it is created, and | |||
134 | /// decrements its refcount when it's destroyed (or is changed to point to a | |||
135 | /// different object). | |||
136 | template <typename T> class IntrusiveRefCntPtr { | |||
137 | T *Obj = nullptr; | |||
138 | ||||
139 | public: | |||
140 | using element_type = T; | |||
141 | ||||
142 | explicit IntrusiveRefCntPtr() = default; | |||
143 | IntrusiveRefCntPtr(T *obj) : Obj(obj) { retain(); } | |||
144 | IntrusiveRefCntPtr(const IntrusiveRefCntPtr &S) : Obj(S.Obj) { retain(); } | |||
145 | IntrusiveRefCntPtr(IntrusiveRefCntPtr &&S) : Obj(S.Obj) { S.Obj = nullptr; } | |||
146 | ||||
147 | template <class X> | |||
148 | IntrusiveRefCntPtr(IntrusiveRefCntPtr<X> &&S) : Obj(S.get()) { | |||
149 | S.Obj = nullptr; | |||
150 | } | |||
151 | ||||
152 | template <class X> | |||
153 | IntrusiveRefCntPtr(const IntrusiveRefCntPtr<X> &S) : Obj(S.get()) { | |||
154 | retain(); | |||
155 | } | |||
156 | ||||
157 | ~IntrusiveRefCntPtr() { release(); } | |||
| ||||
158 | ||||
159 | IntrusiveRefCntPtr &operator=(IntrusiveRefCntPtr S) { | |||
160 | swap(S); | |||
161 | return *this; | |||
162 | } | |||
163 | ||||
164 | T &operator*() const { return *Obj; } | |||
165 | T *operator->() const { return Obj; } | |||
166 | T *get() const { return Obj; } | |||
167 | explicit operator bool() const { return Obj; } | |||
168 | ||||
169 | void swap(IntrusiveRefCntPtr &other) { | |||
170 | T *tmp = other.Obj; | |||
171 | other.Obj = Obj; | |||
172 | Obj = tmp; | |||
173 | } | |||
174 | ||||
175 | void reset() { | |||
176 | release(); | |||
177 | Obj = nullptr; | |||
178 | } | |||
179 | ||||
180 | void resetWithoutRelease() { Obj = nullptr; } | |||
181 | ||||
182 | private: | |||
183 | void retain() { | |||
184 | if (Obj) | |||
185 | IntrusiveRefCntPtrInfo<T>::retain(Obj); | |||
186 | } | |||
187 | ||||
188 | void release() { | |||
189 | if (Obj) | |||
190 | IntrusiveRefCntPtrInfo<T>::release(Obj); | |||
191 | } | |||
192 | ||||
193 | template <typename X> friend class IntrusiveRefCntPtr; | |||
194 | }; | |||
195 | ||||
196 | template <class T, class U> | |||
197 | inline bool operator==(const IntrusiveRefCntPtr<T> &A, | |||
198 | const IntrusiveRefCntPtr<U> &B) { | |||
199 | return A.get() == B.get(); | |||
200 | } | |||
201 | ||||
202 | template <class T, class U> | |||
203 | inline bool operator!=(const IntrusiveRefCntPtr<T> &A, | |||
204 | const IntrusiveRefCntPtr<U> &B) { | |||
205 | return A.get() != B.get(); | |||
206 | } | |||
207 | ||||
208 | template <class T, class U> | |||
209 | inline bool operator==(const IntrusiveRefCntPtr<T> &A, U *B) { | |||
210 | return A.get() == B; | |||
211 | } | |||
212 | ||||
213 | template <class T, class U> | |||
214 | inline bool operator!=(const IntrusiveRefCntPtr<T> &A, U *B) { | |||
215 | return A.get() != B; | |||
216 | } | |||
217 | ||||
218 | template <class T, class U> | |||
219 | inline bool operator==(T *A, const IntrusiveRefCntPtr<U> &B) { | |||
220 | return A == B.get(); | |||
221 | } | |||
222 | ||||
223 | template <class T, class U> | |||
224 | inline bool operator!=(T *A, const IntrusiveRefCntPtr<U> &B) { | |||
225 | return A != B.get(); | |||
226 | } | |||
227 | ||||
228 | template <class T> | |||
229 | bool operator==(std::nullptr_t A, const IntrusiveRefCntPtr<T> &B) { | |||
230 | return !B; | |||
231 | } | |||
232 | ||||
233 | template <class T> | |||
234 | bool operator==(const IntrusiveRefCntPtr<T> &A, std::nullptr_t B) { | |||
235 | return B == A; | |||
236 | } | |||
237 | ||||
238 | template <class T> | |||
239 | bool operator!=(std::nullptr_t A, const IntrusiveRefCntPtr<T> &B) { | |||
240 | return !(A == B); | |||
241 | } | |||
242 | ||||
243 | template <class T> | |||
244 | bool operator!=(const IntrusiveRefCntPtr<T> &A, std::nullptr_t B) { | |||
245 | return !(A == B); | |||
246 | } | |||
247 | ||||
248 | // Make IntrusiveRefCntPtr work with dyn_cast, isa, and the other idioms from | |||
249 | // Casting.h. | |||
250 | template <typename From> struct simplify_type; | |||
251 | ||||
252 | template <class T> struct simplify_type<IntrusiveRefCntPtr<T>> { | |||
253 | using SimpleType = T *; | |||
254 | ||||
255 | static SimpleType getSimplifiedValue(IntrusiveRefCntPtr<T> &Val) { | |||
256 | return Val.get(); | |||
257 | } | |||
258 | }; | |||
259 | ||||
260 | template <class T> struct simplify_type<const IntrusiveRefCntPtr<T>> { | |||
261 | using SimpleType = /*const*/ T *; | |||
262 | ||||
263 | static SimpleType getSimplifiedValue(const IntrusiveRefCntPtr<T> &Val) { | |||
264 | return Val.get(); | |||
265 | } | |||
266 | }; | |||
267 | ||||
268 | } // end namespace llvm | |||
269 | ||||
270 | #endif // LLVM_ADT_INTRUSIVEREFCNTPTR_H |