| File: | build/source/llvm/include/llvm/ADT/IntrusiveRefCntPtr.h |
| Warning: | line 191, column 38 Potential memory leak |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
| 1 | //===---- QueryParser.cpp - clang-query command parser --------------------===// | |||
| 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 | #include "QueryParser.h" | |||
| 10 | #include "Query.h" | |||
| 11 | #include "QuerySession.h" | |||
| 12 | #include "clang/ASTMatchers/Dynamic/Parser.h" | |||
| 13 | #include "clang/Basic/CharInfo.h" | |||
| 14 | #include "clang/Tooling/NodeIntrospection.h" | |||
| 15 | #include "llvm/ADT/StringRef.h" | |||
| 16 | #include "llvm/ADT/StringSwitch.h" | |||
| 17 | #include <optional> | |||
| 18 | #include <set> | |||
| 19 | ||||
| 20 | using namespace llvm; | |||
| 21 | using namespace clang::ast_matchers::dynamic; | |||
| 22 | ||||
| 23 | namespace clang { | |||
| 24 | namespace query { | |||
| 25 | ||||
| 26 | // Lex any amount of whitespace followed by a "word" (any sequence of | |||
| 27 | // non-whitespace characters) from the start of region [Begin,End). If no word | |||
| 28 | // is found before End, return StringRef(). Begin is adjusted to exclude the | |||
| 29 | // lexed region. | |||
| 30 | StringRef QueryParser::lexWord() { | |||
| 31 | Line = Line.drop_while([](char c) { | |||
| 32 | // Don't trim newlines. | |||
| 33 | return StringRef(" \t\v\f\r").contains(c); | |||
| 34 | }); | |||
| 35 | ||||
| 36 | if (Line.empty()) | |||
| 37 | // Even though the Line is empty, it contains a pointer and | |||
| 38 | // a (zero) length. The pointer is used in the LexOrCompleteWord | |||
| 39 | // code completion. | |||
| 40 | return Line; | |||
| 41 | ||||
| 42 | StringRef Word; | |||
| 43 | if (Line.front() == '#') | |||
| 44 | Word = Line.substr(0, 1); | |||
| 45 | else | |||
| 46 | Word = Line.take_until(isWhitespace); | |||
| 47 | ||||
| 48 | Line = Line.drop_front(Word.size()); | |||
| 49 | return Word; | |||
| 50 | } | |||
| 51 | ||||
| 52 | // This is the StringSwitch-alike used by lexOrCompleteWord below. See that | |||
| 53 | // function for details. | |||
| 54 | template <typename T> struct QueryParser::LexOrCompleteWord { | |||
| 55 | StringRef Word; | |||
| 56 | StringSwitch<T> Switch; | |||
| 57 | ||||
| 58 | QueryParser *P; | |||
| 59 | // Set to the completion point offset in Word, or StringRef::npos if | |||
| 60 | // completion point not in Word. | |||
| 61 | size_t WordCompletionPos; | |||
| 62 | ||||
| 63 | // Lexes a word and stores it in Word. Returns a LexOrCompleteWord<T> object | |||
| 64 | // that can be used like a llvm::StringSwitch<T>, but adds cases as possible | |||
| 65 | // completions if the lexed word contains the completion point. | |||
| 66 | LexOrCompleteWord(QueryParser *P, StringRef &OutWord) | |||
| 67 | : Word(P->lexWord()), Switch(Word), P(P), | |||
| 68 | WordCompletionPos(StringRef::npos) { | |||
| 69 | OutWord = Word; | |||
| 70 | if (P->CompletionPos && P->CompletionPos <= Word.data() + Word.size()) { | |||
| 71 | if (P->CompletionPos < Word.data()) | |||
| 72 | WordCompletionPos = 0; | |||
| 73 | else | |||
| 74 | WordCompletionPos = P->CompletionPos - Word.data(); | |||
| 75 | } | |||
| 76 | } | |||
| 77 | ||||
| 78 | LexOrCompleteWord &Case(llvm::StringLiteral CaseStr, const T &Value, | |||
| 79 | bool IsCompletion = true) { | |||
| 80 | ||||
| 81 | if (WordCompletionPos == StringRef::npos) | |||
| 82 | Switch.Case(CaseStr, Value); | |||
| 83 | else if (CaseStr.size() != 0 && IsCompletion && WordCompletionPos <= CaseStr.size() && | |||
| 84 | CaseStr.substr(0, WordCompletionPos) == | |||
| 85 | Word.substr(0, WordCompletionPos)) | |||
| 86 | P->Completions.push_back(LineEditor::Completion( | |||
| 87 | (CaseStr.substr(WordCompletionPos) + " ").str(), | |||
| 88 | std::string(CaseStr))); | |||
| 89 | return *this; | |||
| 90 | } | |||
| 91 | ||||
| 92 | T Default(T Value) { return Switch.Default(Value); } | |||
| 93 | }; | |||
| 94 | ||||
| 95 | QueryRef QueryParser::parseSetBool(bool QuerySession::*Var) { | |||
| 96 | StringRef ValStr; | |||
| 97 | unsigned Value = LexOrCompleteWord<unsigned>(this, ValStr) | |||
| 98 | .Case("false", 0) | |||
| 99 | .Case("true", 1) | |||
| 100 | .Default(~0u); | |||
| 101 | if (Value == ~0u) { | |||
| 102 | return new InvalidQuery("expected 'true' or 'false', got '" + ValStr + "'"); | |||
| 103 | } | |||
| 104 | return new SetQuery<bool>(Var, Value); | |||
| 105 | } | |||
| 106 | ||||
| 107 | template <typename QueryType> QueryRef QueryParser::parseSetOutputKind() { | |||
| 108 | StringRef ValStr; | |||
| 109 | bool HasIntrospection = tooling::NodeIntrospection::hasIntrospectionSupport(); | |||
| 110 | unsigned OutKind = | |||
| 111 | LexOrCompleteWord<unsigned>(this, ValStr) | |||
| 112 | .Case("diag", OK_Diag) | |||
| 113 | .Case("print", OK_Print) | |||
| 114 | .Case("detailed-ast", OK_DetailedAST) | |||
| 115 | .Case("srcloc", OK_SrcLoc, /*IsCompletion=*/HasIntrospection) | |||
| 116 | .Case("dump", OK_DetailedAST) | |||
| 117 | .Default(~0u); | |||
| 118 | if (OutKind == ~0u) { | |||
| 119 | return new InvalidQuery("expected 'diag', 'print', 'detailed-ast'" + | |||
| 120 | StringRef(HasIntrospection ? ", 'srcloc'" : "") + | |||
| 121 | " or 'dump', got '" + ValStr + "'"); | |||
| 122 | } | |||
| 123 | ||||
| 124 | switch (OutKind) { | |||
| 125 | case OK_DetailedAST: | |||
| 126 | return new QueryType(&QuerySession::DetailedASTOutput); | |||
| 127 | case OK_Diag: | |||
| 128 | return new QueryType(&QuerySession::DiagOutput); | |||
| 129 | case OK_Print: | |||
| 130 | return new QueryType(&QuerySession::PrintOutput); | |||
| 131 | case OK_SrcLoc: | |||
| 132 | if (HasIntrospection) | |||
| 133 | return new QueryType(&QuerySession::SrcLocOutput); | |||
| 134 | return new InvalidQuery("'srcloc' output support is not available."); | |||
| 135 | } | |||
| 136 | ||||
| 137 | llvm_unreachable("Invalid output kind")::llvm::llvm_unreachable_internal("Invalid output kind", "clang-tools-extra/clang-query/QueryParser.cpp" , 137); | |||
| 138 | } | |||
| 139 | ||||
| 140 | QueryRef QueryParser::parseSetTraversalKind(TraversalKind QuerySession::*Var) { | |||
| 141 | StringRef ValStr; | |||
| 142 | unsigned Value = | |||
| 143 | LexOrCompleteWord<unsigned>(this, ValStr) | |||
| 144 | .Case("AsIs", TK_AsIs) | |||
| 145 | .Case("IgnoreUnlessSpelledInSource", TK_IgnoreUnlessSpelledInSource) | |||
| 146 | .Default(~0u); | |||
| 147 | if (Value == ~0u) { | |||
| 148 | return new InvalidQuery("expected traversal kind, got '" + ValStr + "'"); | |||
| 149 | } | |||
| 150 | return new SetQuery<TraversalKind>(Var, static_cast<TraversalKind>(Value)); | |||
| 151 | } | |||
| 152 | ||||
| 153 | QueryRef QueryParser::endQuery(QueryRef Q) { | |||
| 154 | StringRef Extra = Line; | |||
| 155 | StringRef ExtraTrimmed = Extra.drop_while( | |||
| 156 | [](char c) { return StringRef(" \t\v\f\r").contains(c); }); | |||
| 157 | ||||
| 158 | if ((!ExtraTrimmed.empty() && ExtraTrimmed[0] == '\n') || | |||
| 159 | (ExtraTrimmed.size() >= 2 && ExtraTrimmed[0] == '\r' && | |||
| 160 | ExtraTrimmed[1] == '\n')) | |||
| 161 | Q->RemainingContent = Extra; | |||
| 162 | else { | |||
| 163 | StringRef TrailingWord = lexWord(); | |||
| 164 | if (!TrailingWord.empty() && TrailingWord.front() == '#') { | |||
| 165 | Line = Line.drop_until([](char c) { return c == '\n'; }); | |||
| 166 | Line = Line.drop_while([](char c) { return c == '\n'; }); | |||
| 167 | return endQuery(Q); | |||
| 168 | } | |||
| 169 | if (!TrailingWord.empty()) { | |||
| 170 | return new InvalidQuery("unexpected extra input: '" + Extra + "'"); | |||
| 171 | } | |||
| 172 | } | |||
| 173 | return Q; | |||
| 174 | } | |||
| 175 | ||||
| 176 | namespace { | |||
| 177 | ||||
| 178 | enum ParsedQueryKind { | |||
| 179 | PQK_Invalid, | |||
| 180 | PQK_Comment, | |||
| 181 | PQK_NoOp, | |||
| 182 | PQK_Help, | |||
| 183 | PQK_Let, | |||
| 184 | PQK_Match, | |||
| 185 | PQK_Set, | |||
| 186 | PQK_Unlet, | |||
| 187 | PQK_Quit, | |||
| 188 | PQK_Enable, | |||
| 189 | PQK_Disable | |||
| 190 | }; | |||
| 191 | ||||
| 192 | enum ParsedQueryVariable { | |||
| 193 | PQV_Invalid, | |||
| 194 | PQV_Output, | |||
| 195 | PQV_BindRoot, | |||
| 196 | PQV_PrintMatcher, | |||
| 197 | PQV_Traversal | |||
| 198 | }; | |||
| 199 | ||||
| 200 | QueryRef makeInvalidQueryFromDiagnostics(const Diagnostics &Diag) { | |||
| 201 | std::string ErrStr; | |||
| 202 | llvm::raw_string_ostream OS(ErrStr); | |||
| 203 | Diag.printToStreamFull(OS); | |||
| 204 | return new InvalidQuery(OS.str()); | |||
| 205 | } | |||
| 206 | ||||
| 207 | } // namespace | |||
| 208 | ||||
| 209 | QueryRef QueryParser::completeMatcherExpression() { | |||
| 210 | std::vector<MatcherCompletion> Comps = Parser::completeExpression( | |||
| 211 | Line, CompletionPos - Line.begin(), nullptr, &QS.NamedValues); | |||
| 212 | for (auto I = Comps.begin(), E = Comps.end(); I != E; ++I) { | |||
| 213 | Completions.push_back(LineEditor::Completion(I->TypedText, I->MatcherDecl)); | |||
| 214 | } | |||
| 215 | return QueryRef(); | |||
| 216 | } | |||
| 217 | ||||
| 218 | QueryRef QueryParser::doParse() { | |||
| 219 | StringRef CommandStr; | |||
| 220 | ParsedQueryKind QKind = LexOrCompleteWord<ParsedQueryKind>(this, CommandStr) | |||
| 221 | .Case("", PQK_NoOp) | |||
| 222 | .Case("#", PQK_Comment, /*IsCompletion=*/false) | |||
| 223 | .Case("help", PQK_Help) | |||
| 224 | .Case("l", PQK_Let, /*IsCompletion=*/false) | |||
| 225 | .Case("let", PQK_Let) | |||
| 226 | .Case("m", PQK_Match, /*IsCompletion=*/false) | |||
| 227 | .Case("match", PQK_Match) | |||
| 228 | .Case("q", PQK_Quit, /*IsCompletion=*/false) | |||
| 229 | .Case("quit", PQK_Quit) | |||
| 230 | .Case("set", PQK_Set) | |||
| 231 | .Case("enable", PQK_Enable) | |||
| 232 | .Case("disable", PQK_Disable) | |||
| 233 | .Case("unlet", PQK_Unlet) | |||
| 234 | .Default(PQK_Invalid); | |||
| 235 | ||||
| 236 | switch (QKind) { | |||
| 237 | case PQK_Comment: | |||
| 238 | case PQK_NoOp: | |||
| 239 | Line = Line.drop_until([](char c) { return c == '\n'; }); | |||
| 240 | Line = Line.drop_while([](char c) { return c == '\n'; }); | |||
| 241 | if (Line.empty()) | |||
| 242 | return new NoOpQuery; | |||
| 243 | return doParse(); | |||
| 244 | ||||
| 245 | case PQK_Help: | |||
| 246 | return endQuery(new HelpQuery); | |||
| 247 | ||||
| 248 | case PQK_Quit: | |||
| 249 | return endQuery(new QuitQuery); | |||
| 250 | ||||
| 251 | case PQK_Let: { | |||
| 252 | StringRef Name = lexWord(); | |||
| 253 | ||||
| 254 | if (Name.empty()) | |||
| 255 | return new InvalidQuery("expected variable name"); | |||
| 256 | ||||
| 257 | if (CompletionPos) | |||
| 258 | return completeMatcherExpression(); | |||
| 259 | ||||
| 260 | Diagnostics Diag; | |||
| 261 | ast_matchers::dynamic::VariantValue Value; | |||
| 262 | if (!Parser::parseExpression(Line, nullptr, &QS.NamedValues, &Value, | |||
| 263 | &Diag)) { | |||
| 264 | return makeInvalidQueryFromDiagnostics(Diag); | |||
| 265 | } | |||
| 266 | ||||
| 267 | auto *Q = new LetQuery(Name, Value); | |||
| 268 | Q->RemainingContent = Line; | |||
| 269 | return Q; | |||
| 270 | } | |||
| 271 | ||||
| 272 | case PQK_Match: { | |||
| 273 | if (CompletionPos) | |||
| 274 | return completeMatcherExpression(); | |||
| 275 | ||||
| 276 | Diagnostics Diag; | |||
| 277 | auto MatcherSource = Line.ltrim(); | |||
| 278 | auto OrigMatcherSource = MatcherSource; | |||
| 279 | std::optional<DynTypedMatcher> Matcher = Parser::parseMatcherExpression( | |||
| 280 | MatcherSource, nullptr, &QS.NamedValues, &Diag); | |||
| 281 | if (!Matcher) { | |||
| 282 | return makeInvalidQueryFromDiagnostics(Diag); | |||
| 283 | } | |||
| 284 | auto ActualSource = OrigMatcherSource.slice(0, OrigMatcherSource.size() - | |||
| 285 | MatcherSource.size()); | |||
| 286 | auto *Q = new MatchQuery(ActualSource, *Matcher); | |||
| 287 | Q->RemainingContent = MatcherSource; | |||
| 288 | return Q; | |||
| 289 | } | |||
| 290 | ||||
| 291 | case PQK_Set: { | |||
| 292 | StringRef VarStr; | |||
| 293 | ParsedQueryVariable Var = | |||
| 294 | LexOrCompleteWord<ParsedQueryVariable>(this, VarStr) | |||
| 295 | .Case("output", PQV_Output) | |||
| 296 | .Case("bind-root", PQV_BindRoot) | |||
| 297 | .Case("print-matcher", PQV_PrintMatcher) | |||
| 298 | .Case("traversal", PQV_Traversal) | |||
| 299 | .Default(PQV_Invalid); | |||
| 300 | if (VarStr.empty()) | |||
| 301 | return new InvalidQuery("expected variable name"); | |||
| 302 | if (Var == PQV_Invalid) | |||
| 303 | return new InvalidQuery("unknown variable: '" + VarStr + "'"); | |||
| 304 | ||||
| 305 | QueryRef Q; | |||
| 306 | switch (Var) { | |||
| 307 | case PQV_Output: | |||
| 308 | Q = parseSetOutputKind<SetExclusiveOutputQuery>(); | |||
| 309 | break; | |||
| 310 | case PQV_BindRoot: | |||
| 311 | Q = parseSetBool(&QuerySession::BindRoot); | |||
| 312 | break; | |||
| 313 | case PQV_PrintMatcher: | |||
| 314 | Q = parseSetBool(&QuerySession::PrintMatcher); | |||
| 315 | break; | |||
| 316 | case PQV_Traversal: | |||
| 317 | Q = parseSetTraversalKind(&QuerySession::TK); | |||
| 318 | break; | |||
| 319 | case PQV_Invalid: | |||
| 320 | llvm_unreachable("Invalid query kind")::llvm::llvm_unreachable_internal("Invalid query kind", "clang-tools-extra/clang-query/QueryParser.cpp" , 320); | |||
| 321 | } | |||
| 322 | ||||
| 323 | return endQuery(Q); | |||
| 324 | } | |||
| 325 | case PQK_Enable: | |||
| 326 | case PQK_Disable: { | |||
| 327 | StringRef VarStr; | |||
| 328 | ParsedQueryVariable Var = | |||
| 329 | LexOrCompleteWord<ParsedQueryVariable>(this, VarStr) | |||
| 330 | .Case("output", PQV_Output) | |||
| 331 | .Default(PQV_Invalid); | |||
| 332 | if (VarStr.empty()) | |||
| 333 | return new InvalidQuery("expected variable name"); | |||
| 334 | if (Var == PQV_Invalid) | |||
| 335 | return new InvalidQuery("unknown variable: '" + VarStr + "'"); | |||
| 336 | ||||
| 337 | QueryRef Q; | |||
| 338 | ||||
| 339 | if (QKind == PQK_Enable) | |||
| 340 | Q = parseSetOutputKind<EnableOutputQuery>(); | |||
| 341 | else if (QKind == PQK_Disable) | |||
| 342 | Q = parseSetOutputKind<DisableOutputQuery>(); | |||
| 343 | else | |||
| 344 | llvm_unreachable("Invalid query kind")::llvm::llvm_unreachable_internal("Invalid query kind", "clang-tools-extra/clang-query/QueryParser.cpp" , 344); | |||
| 345 | return endQuery(Q); | |||
| 346 | } | |||
| 347 | ||||
| 348 | case PQK_Unlet: { | |||
| 349 | StringRef Name = lexWord(); | |||
| 350 | ||||
| 351 | if (Name.empty()) | |||
| 352 | return new InvalidQuery("expected variable name"); | |||
| 353 | ||||
| 354 | return endQuery(new LetQuery(Name, VariantValue())); | |||
| 355 | } | |||
| 356 | ||||
| 357 | case PQK_Invalid: | |||
| 358 | return new InvalidQuery("unknown command: " + CommandStr); | |||
| 359 | } | |||
| 360 | ||||
| 361 | llvm_unreachable("Invalid query kind")::llvm::llvm_unreachable_internal("Invalid query kind", "clang-tools-extra/clang-query/QueryParser.cpp" , 361); | |||
| 362 | } | |||
| 363 | ||||
| 364 | QueryRef QueryParser::parse(StringRef Line, const QuerySession &QS) { | |||
| 365 | return QueryParser(Line, QS).doParse(); | |||
| 366 | } | |||
| 367 | ||||
| 368 | std::vector<LineEditor::Completion> | |||
| 369 | QueryParser::complete(StringRef Line, size_t Pos, const QuerySession &QS) { | |||
| 370 | QueryParser P(Line, QS); | |||
| 371 | P.CompletionPos = Line.data() + Pos; | |||
| 372 | ||||
| 373 | P.doParse(); | |||
| ||||
| 374 | return P.Completions; | |||
| 375 | } | |||
| 376 | ||||
| 377 | } // namespace query | |||
| 378 | } // namespace clang |
| 1 | //==- llvm/ADT/IntrusiveRefCntPtr.h - Smart Refcounting Pointer --*- C++ -*-==// | |||
| 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 | /// \file | |||
| 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 | /// ``` | |||
| 22 | /// class MyClass : public RefCountedBase<MyClass> {}; | |||
| 23 | /// | |||
| 24 | /// void foo() { | |||
| 25 | /// // Constructing an IntrusiveRefCntPtr increases the pointee's refcount | |||
| 26 | /// // by 1 (from 0 in this case). | |||
| 27 | /// IntrusiveRefCntPtr<MyClass> Ptr1(new MyClass()); | |||
| 28 | /// | |||
| 29 | /// // Copying an IntrusiveRefCntPtr increases the pointee's refcount by 1. | |||
| 30 | /// IntrusiveRefCntPtr<MyClass> Ptr2(Ptr1); | |||
| 31 | /// | |||
| 32 | /// // Constructing an IntrusiveRefCntPtr has no effect on the object's | |||
| 33 | /// // refcount. After a move, the moved-from pointer is null. | |||
| 34 | /// IntrusiveRefCntPtr<MyClass> Ptr3(std::move(Ptr1)); | |||
| 35 | /// assert(Ptr1 == nullptr); | |||
| 36 | /// | |||
| 37 | /// // Clearing an IntrusiveRefCntPtr decreases the pointee's refcount by 1. | |||
| 38 | /// Ptr2.reset(); | |||
| 39 | /// | |||
| 40 | /// // The object deletes itself when we return from the function, because | |||
| 41 | /// // Ptr3's destructor decrements its refcount to 0. | |||
| 42 | /// } | |||
| 43 | /// ``` | |||
| 44 | /// | |||
| 45 | /// You can use IntrusiveRefCntPtr with isa<T>(), dyn_cast<T>(), etc.: | |||
| 46 | /// | |||
| 47 | /// ``` | |||
| 48 | /// IntrusiveRefCntPtr<MyClass> Ptr(new MyClass()); | |||
| 49 | /// OtherClass *Other = dyn_cast<OtherClass>(Ptr); // Ptr.get() not required | |||
| 50 | /// ``` | |||
| 51 | /// | |||
| 52 | /// IntrusiveRefCntPtr works with any class that | |||
| 53 | /// | |||
| 54 | /// - inherits from (ThreadSafe)RefCountedBase, | |||
| 55 | /// - has Retain() and Release() methods, or | |||
| 56 | /// - specializes IntrusiveRefCntPtrInfo. | |||
| 57 | /// | |||
| 58 | //===----------------------------------------------------------------------===// | |||
| 59 | ||||
| 60 | #ifndef LLVM_ADT_INTRUSIVEREFCNTPTR_H | |||
| 61 | #define LLVM_ADT_INTRUSIVEREFCNTPTR_H | |||
| 62 | ||||
| 63 | #include <atomic> | |||
| 64 | #include <cassert> | |||
| 65 | #include <cstddef> | |||
| 66 | #include <memory> | |||
| 67 | ||||
| 68 | namespace llvm { | |||
| 69 | ||||
| 70 | /// A CRTP mixin class that adds reference counting to a type. | |||
| 71 | /// | |||
| 72 | /// The lifetime of an object which inherits from RefCountedBase is managed by | |||
| 73 | /// calls to Release() and Retain(), which increment and decrement the object's | |||
| 74 | /// refcount, respectively. When a Release() call decrements the refcount to 0, | |||
| 75 | /// the object deletes itself. | |||
| 76 | template <class Derived> class RefCountedBase { | |||
| 77 | mutable unsigned RefCount = 0; | |||
| 78 | ||||
| 79 | protected: | |||
| 80 | RefCountedBase() = default; | |||
| 81 | RefCountedBase(const RefCountedBase &) {} | |||
| 82 | RefCountedBase &operator=(const RefCountedBase &) = delete; | |||
| 83 | ||||
| 84 | #ifndef NDEBUG | |||
| 85 | ~RefCountedBase() { | |||
| 86 | assert(RefCount == 0 &&(static_cast <bool> (RefCount == 0 && "Destruction occurred when there are still references to this." ) ? void (0) : __assert_fail ("RefCount == 0 && \"Destruction occurred when there are still references to this.\"" , "llvm/include/llvm/ADT/IntrusiveRefCntPtr.h", 87, __extension__ __PRETTY_FUNCTION__)) | |||
| 87 | "Destruction occurred when there are still references to this.")(static_cast <bool> (RefCount == 0 && "Destruction occurred when there are still references to this." ) ? void (0) : __assert_fail ("RefCount == 0 && \"Destruction occurred when there are still references to this.\"" , "llvm/include/llvm/ADT/IntrusiveRefCntPtr.h", 87, __extension__ __PRETTY_FUNCTION__)); | |||
| 88 | } | |||
| 89 | #else | |||
| 90 | // Default the destructor in release builds, A trivial destructor may enable | |||
| 91 | // better codegen. | |||
| 92 | ~RefCountedBase() = default; | |||
| 93 | #endif | |||
| 94 | ||||
| 95 | public: | |||
| 96 | void Retain() const { ++RefCount; } | |||
| 97 | ||||
| 98 | void Release() const { | |||
| 99 | 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.\"" , "llvm/include/llvm/ADT/IntrusiveRefCntPtr.h", 99, __extension__ __PRETTY_FUNCTION__)); | |||
| 100 | if (--RefCount == 0) | |||
| 101 | delete static_cast<const Derived *>(this); | |||
| 102 | } | |||
| 103 | }; | |||
| 104 | ||||
| 105 | /// A thread-safe version of \c RefCountedBase. | |||
| 106 | template <class Derived> class ThreadSafeRefCountedBase { | |||
| 107 | mutable std::atomic<int> RefCount{0}; | |||
| 108 | ||||
| 109 | protected: | |||
| 110 | ThreadSafeRefCountedBase() = default; | |||
| 111 | ThreadSafeRefCountedBase(const ThreadSafeRefCountedBase &) {} | |||
| 112 | ThreadSafeRefCountedBase & | |||
| 113 | operator=(const ThreadSafeRefCountedBase &) = delete; | |||
| 114 | ||||
| 115 | #ifndef NDEBUG | |||
| 116 | ~ThreadSafeRefCountedBase() { | |||
| 117 | assert(RefCount == 0 &&(static_cast <bool> (RefCount == 0 && "Destruction occurred when there are still references to this." ) ? void (0) : __assert_fail ("RefCount == 0 && \"Destruction occurred when there are still references to this.\"" , "llvm/include/llvm/ADT/IntrusiveRefCntPtr.h", 118, __extension__ __PRETTY_FUNCTION__)) | |||
| 118 | "Destruction occurred when there are still references to this.")(static_cast <bool> (RefCount == 0 && "Destruction occurred when there are still references to this." ) ? void (0) : __assert_fail ("RefCount == 0 && \"Destruction occurred when there are still references to this.\"" , "llvm/include/llvm/ADT/IntrusiveRefCntPtr.h", 118, __extension__ __PRETTY_FUNCTION__)); | |||
| 119 | } | |||
| 120 | #else | |||
| 121 | // Default the destructor in release builds, A trivial destructor may enable | |||
| 122 | // better codegen. | |||
| 123 | ~ThreadSafeRefCountedBase() = default; | |||
| 124 | #endif | |||
| 125 | ||||
| 126 | public: | |||
| 127 | void Retain() const { RefCount.fetch_add(1, std::memory_order_relaxed); } | |||
| 128 | ||||
| 129 | void Release() const { | |||
| 130 | int NewRefCount = RefCount.fetch_sub(1, std::memory_order_acq_rel) - 1; | |||
| 131 | 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.\"" , "llvm/include/llvm/ADT/IntrusiveRefCntPtr.h", 131, __extension__ __PRETTY_FUNCTION__)); | |||
| 132 | if (NewRefCount == 0) | |||
| 133 | delete static_cast<const Derived *>(this); | |||
| 134 | } | |||
| 135 | }; | |||
| 136 | ||||
| 137 | /// Class you can specialize to provide custom retain/release functionality for | |||
| 138 | /// a type. | |||
| 139 | /// | |||
| 140 | /// Usually specializing this class is not necessary, as IntrusiveRefCntPtr | |||
| 141 | /// works with any type which defines Retain() and Release() functions -- you | |||
| 142 | /// can define those functions yourself if RefCountedBase doesn't work for you. | |||
| 143 | /// | |||
| 144 | /// One case when you might want to specialize this type is if you have | |||
| 145 | /// - Foo.h defines type Foo and includes Bar.h, and | |||
| 146 | /// - Bar.h uses IntrusiveRefCntPtr<Foo> in inline functions. | |||
| 147 | /// | |||
| 148 | /// Because Foo.h includes Bar.h, Bar.h can't include Foo.h in order to pull in | |||
| 149 | /// the declaration of Foo. Without the declaration of Foo, normally Bar.h | |||
| 150 | /// wouldn't be able to use IntrusiveRefCntPtr<Foo>, which wants to call | |||
| 151 | /// T::Retain and T::Release. | |||
| 152 | /// | |||
| 153 | /// To resolve this, Bar.h could include a third header, FooFwd.h, which | |||
| 154 | /// forward-declares Foo and specializes IntrusiveRefCntPtrInfo<Foo>. Then | |||
| 155 | /// Bar.h could use IntrusiveRefCntPtr<Foo>, although it still couldn't call any | |||
| 156 | /// functions on Foo itself, because Foo would be an incomplete type. | |||
| 157 | template <typename T> struct IntrusiveRefCntPtrInfo { | |||
| 158 | static void retain(T *obj) { obj->Retain(); } | |||
| 159 | static void release(T *obj) { obj->Release(); } | |||
| 160 | }; | |||
| 161 | ||||
| 162 | /// A smart pointer to a reference-counted object that inherits from | |||
| 163 | /// RefCountedBase or ThreadSafeRefCountedBase. | |||
| 164 | /// | |||
| 165 | /// This class increments its pointee's reference count when it is created, and | |||
| 166 | /// decrements its refcount when it's destroyed (or is changed to point to a | |||
| 167 | /// different object). | |||
| 168 | template <typename T> class IntrusiveRefCntPtr { | |||
| 169 | T *Obj = nullptr; | |||
| 170 | ||||
| 171 | public: | |||
| 172 | using element_type = T; | |||
| 173 | ||||
| 174 | explicit IntrusiveRefCntPtr() = default; | |||
| 175 | IntrusiveRefCntPtr(T *obj) : Obj(obj) { retain(); } | |||
| 176 | IntrusiveRefCntPtr(const IntrusiveRefCntPtr &S) : Obj(S.Obj) { retain(); } | |||
| 177 | IntrusiveRefCntPtr(IntrusiveRefCntPtr &&S) : Obj(S.Obj) { S.Obj = nullptr; } | |||
| 178 | ||||
| 179 | template <class X, | |||
| 180 | std::enable_if_t<std::is_convertible<X *, T *>::value, bool> = true> | |||
| 181 | IntrusiveRefCntPtr(IntrusiveRefCntPtr<X> S) : Obj(S.get()) { | |||
| 182 | S.Obj = nullptr; | |||
| 183 | } | |||
| 184 | ||||
| 185 | template <class X, | |||
| 186 | std::enable_if_t<std::is_convertible<X *, T *>::value, bool> = true> | |||
| 187 | IntrusiveRefCntPtr(std::unique_ptr<X> S) : Obj(S.release()) { | |||
| 188 | retain(); | |||
| 189 | } | |||
| 190 | ||||
| 191 | ~IntrusiveRefCntPtr() { release(); } | |||
| ||||
| 192 | ||||
| 193 | IntrusiveRefCntPtr &operator=(IntrusiveRefCntPtr S) { | |||
| 194 | swap(S); | |||
| 195 | return *this; | |||
| 196 | } | |||
| 197 | ||||
| 198 | T &operator*() const { return *Obj; } | |||
| 199 | T *operator->() const { return Obj; } | |||
| 200 | T *get() const { return Obj; } | |||
| 201 | explicit operator bool() const { return Obj; } | |||
| 202 | ||||
| 203 | void swap(IntrusiveRefCntPtr &other) { | |||
| 204 | T *tmp = other.Obj; | |||
| 205 | other.Obj = Obj; | |||
| 206 | Obj = tmp; | |||
| 207 | } | |||
| 208 | ||||
| 209 | void reset() { | |||
| 210 | release(); | |||
| 211 | Obj = nullptr; | |||
| 212 | } | |||
| 213 | ||||
| 214 | void resetWithoutRelease() { Obj = nullptr; } | |||
| 215 | ||||
| 216 | private: | |||
| 217 | void retain() { | |||
| 218 | if (Obj) | |||
| 219 | IntrusiveRefCntPtrInfo<T>::retain(Obj); | |||
| 220 | } | |||
| 221 | ||||
| 222 | void release() { | |||
| 223 | if (Obj) | |||
| 224 | IntrusiveRefCntPtrInfo<T>::release(Obj); | |||
| 225 | } | |||
| 226 | ||||
| 227 | template <typename X> friend class IntrusiveRefCntPtr; | |||
| 228 | }; | |||
| 229 | ||||
| 230 | template <class T, class U> | |||
| 231 | inline bool operator==(const IntrusiveRefCntPtr<T> &A, | |||
| 232 | const IntrusiveRefCntPtr<U> &B) { | |||
| 233 | return A.get() == B.get(); | |||
| 234 | } | |||
| 235 | ||||
| 236 | template <class T, class U> | |||
| 237 | inline bool operator!=(const IntrusiveRefCntPtr<T> &A, | |||
| 238 | const IntrusiveRefCntPtr<U> &B) { | |||
| 239 | return A.get() != B.get(); | |||
| 240 | } | |||
| 241 | ||||
| 242 | template <class T, class U> | |||
| 243 | inline bool operator==(const IntrusiveRefCntPtr<T> &A, U *B) { | |||
| 244 | return A.get() == B; | |||
| 245 | } | |||
| 246 | ||||
| 247 | template <class T, class U> | |||
| 248 | inline bool operator!=(const IntrusiveRefCntPtr<T> &A, U *B) { | |||
| 249 | return A.get() != B; | |||
| 250 | } | |||
| 251 | ||||
| 252 | template <class T, class U> | |||
| 253 | inline bool operator==(T *A, const IntrusiveRefCntPtr<U> &B) { | |||
| 254 | return A == B.get(); | |||
| 255 | } | |||
| 256 | ||||
| 257 | template <class T, class U> | |||
| 258 | inline bool operator!=(T *A, const IntrusiveRefCntPtr<U> &B) { | |||
| 259 | return A != B.get(); | |||
| 260 | } | |||
| 261 | ||||
| 262 | template <class T> | |||
| 263 | bool operator==(std::nullptr_t, const IntrusiveRefCntPtr<T> &B) { | |||
| 264 | return !B; | |||
| 265 | } | |||
| 266 | ||||
| 267 | template <class T> | |||
| 268 | bool operator==(const IntrusiveRefCntPtr<T> &A, std::nullptr_t B) { | |||
| 269 | return B == A; | |||
| 270 | } | |||
| 271 | ||||
| 272 | template <class T> | |||
| 273 | bool operator!=(std::nullptr_t A, const IntrusiveRefCntPtr<T> &B) { | |||
| 274 | return !(A == B); | |||
| 275 | } | |||
| 276 | ||||
| 277 | template <class T> | |||
| 278 | bool operator!=(const IntrusiveRefCntPtr<T> &A, std::nullptr_t B) { | |||
| 279 | return !(A == B); | |||
| 280 | } | |||
| 281 | ||||
| 282 | // Make IntrusiveRefCntPtr work with dyn_cast, isa, and the other idioms from | |||
| 283 | // Casting.h. | |||
| 284 | template <typename From> struct simplify_type; | |||
| 285 | ||||
| 286 | template <class T> struct simplify_type<IntrusiveRefCntPtr<T>> { | |||
| 287 | using SimpleType = T *; | |||
| 288 | ||||
| 289 | static SimpleType getSimplifiedValue(IntrusiveRefCntPtr<T> &Val) { | |||
| 290 | return Val.get(); | |||
| 291 | } | |||
| 292 | }; | |||
| 293 | ||||
| 294 | template <class T> struct simplify_type<const IntrusiveRefCntPtr<T>> { | |||
| 295 | using SimpleType = /*const*/ T *; | |||
| 296 | ||||
| 297 | static SimpleType getSimplifiedValue(const IntrusiveRefCntPtr<T> &Val) { | |||
| 298 | return Val.get(); | |||
| 299 | } | |||
| 300 | }; | |||
| 301 | ||||
| 302 | /// Factory function for creating intrusive ref counted pointers. | |||
| 303 | template <typename T, typename... Args> | |||
| 304 | IntrusiveRefCntPtr<T> makeIntrusiveRefCnt(Args &&...A) { | |||
| 305 | return IntrusiveRefCntPtr<T>(new T(std::forward<Args>(A)...)); | |||
| 306 | } | |||
| 307 | ||||
| 308 | } // end namespace llvm | |||
| 309 | ||||
| 310 | #endif // LLVM_ADT_INTRUSIVEREFCNTPTR_H |