Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/libcst/matchers/_matcher_base.py: 41%

574 statements  

« prev     ^ index     » next       coverage.py v7.3.1, created at 2023-09-25 06:43 +0000

1# Copyright (c) Meta Platforms, Inc. and affiliates. 

2# 

3# This source code is licensed under the MIT license found in the 

4# LICENSE file in the root directory of this source tree. 

5 

6import collections.abc 

7import inspect 

8import re 

9from abc import ABCMeta 

10from dataclasses import dataclass, fields 

11from enum import auto, Enum 

12from typing import ( 

13 Callable, 

14 cast, 

15 Dict, 

16 Generic, 

17 Iterator, 

18 List, 

19 Mapping, 

20 NoReturn, 

21 Optional, 

22 Pattern, 

23 Sequence, 

24 Tuple, 

25 Type, 

26 TypeVar, 

27 Union, 

28) 

29 

30import libcst 

31import libcst.metadata as meta 

32from libcst import FlattenSentinel, MaybeSentinel, RemovalSentinel 

33from libcst._metadata_dependent import LazyValue 

34 

35 

36class DoNotCareSentinel(Enum): 

37 """ 

38 A sentinel that is used in matcher classes to indicate that a caller 

39 does not care what this value is. We recommend that you do not use this 

40 directly, and instead use the :func:`DoNotCare` helper. You do not 

41 need to use this for concrete matcher attributes since :func:`DoNotCare` 

42 is already the default. 

43 """ 

44 

45 DEFAULT = auto() 

46 

47 def __repr__(self) -> str: 

48 return "DoNotCare()" 

49 

50 

51_MatcherT = TypeVar("_MatcherT", covariant=True) 

52_MatchIfTrueT = TypeVar("_MatchIfTrueT", covariant=True) 

53_BaseMatcherNodeSelfT = TypeVar("_BaseMatcherNodeSelfT", bound="BaseMatcherNode") 

54_OtherNodeT = TypeVar("_OtherNodeT") 

55_MetadataValueT = TypeVar("_MetadataValueT") 

56_MatcherTypeT = TypeVar("_MatcherTypeT", bound=Type["BaseMatcherNode"]) 

57_OtherNodeMatcherTypeT = TypeVar( 

58 "_OtherNodeMatcherTypeT", bound=Type["BaseMatcherNode"] 

59) 

60 

61 

62_METADATA_MISSING_SENTINEL = object() 

63 

64 

65class AbstractBaseMatcherNodeMeta(ABCMeta): 

66 """ 

67 Metaclass that all matcher nodes uses. Allows chaining 2 node type 

68 together with an bitwise-or operator to produce an :class:`TypeOf` 

69 matcher. 

70 """ 

71 

72 # pyre-fixme[14]: `__or__` overrides method defined in `type` inconsistently. 

73 # pyre-fixme[15]: `__or__` overrides method defined in `type` inconsistently. 

74 def __or__(self, node: Type["BaseMatcherNode"]) -> "TypeOf[Type[BaseMatcherNode]]": 

75 return TypeOf(self, node) 

76 

77 

78class BaseMatcherNode: 

79 """ 

80 Base class that all concrete matchers subclass from. :class:`OneOf` and 

81 :class:`AllOf` also subclass from this in order to allow them to be used in 

82 any place that a concrete matcher is allowed. This means that, for example, 

83 you can call :func:`matches` with a concrete matcher, or a :class:`OneOf` with 

84 several concrete matchers as options. 

85 """ 

86 

87 # pyre-fixme[14]: `__or__` overrides method defined in `type` inconsistently. 

88 # pyre-fixme[15]: `__or__` overrides method defined in `type` inconsistently. 

89 def __or__( 

90 self: _BaseMatcherNodeSelfT, other: _OtherNodeT 

91 ) -> "OneOf[Union[_BaseMatcherNodeSelfT, _OtherNodeT]]": 

92 # Without a cast, pyre thinks that the below OneOf is type OneOf[object] 

93 # even though it has the types passed into it. 

94 return cast( 

95 OneOf[Union[_BaseMatcherNodeSelfT, _OtherNodeT]], OneOf(self, other) 

96 ) 

97 

98 def __and__( 

99 self: _BaseMatcherNodeSelfT, other: _OtherNodeT 

100 ) -> "AllOf[Union[_BaseMatcherNodeSelfT, _OtherNodeT]]": 

101 # Without a cast, pyre thinks that the below AllOf is type AllOf[object] 

102 # even though it has the types passed into it. 

103 return cast( 

104 AllOf[Union[_BaseMatcherNodeSelfT, _OtherNodeT]], AllOf(self, other) 

105 ) 

106 

107 def __invert__(self: _BaseMatcherNodeSelfT) -> "_BaseMatcherNodeSelfT": 

108 return cast(_BaseMatcherNodeSelfT, _InverseOf(self)) 

109 

110 

111def DoNotCare() -> DoNotCareSentinel: 

112 """ 

113 Used when you want to match exactly one node, but you do not care what node it is. 

114 Useful inside sequences such as a :class:`libcst.matchers.Call`'s args attribte. 

115 You do not need to use this for concrete matcher attributes since :func:`DoNotCare` 

116 is already the default. 

117 

118 For example, the following matcher would match against any function calls with 

119 three arguments, regardless of the arguments themselves and regardless of the 

120 function name that we were calling:: 

121 

122 m.Call(args=[m.DoNotCare(), m.DoNotCare(), m.DoNotCare()]) 

123 """ 

124 return DoNotCareSentinel.DEFAULT 

125 

126 

127class TypeOf(Generic[_MatcherTypeT], BaseMatcherNode): 

128 """ 

129 Matcher that matches any one of the given types. Useful when you want to work 

130 with trees where a common property might belong to more than a single type. 

131 

132 For example, if you want either a binary operation or a boolean operation 

133 where the left side has a name ``foo``:: 

134 

135 m.TypeOf(m.BinaryOperation, m.BooleanOperation)(left = m.Name("foo")) 

136 

137 Or you could use the shorthand, like:: 

138 

139 (m.BinaryOperation | m.BooleanOperation)(left = m.Name("foo")) 

140 

141 Also :class:`TypeOf` matchers can be used with initalizing in the default 

142 state of other node matchers (without passing any extra patterns):: 

143 

144 m.Name | m.SimpleString 

145 

146 The will be equal to:: 

147 

148 m.OneOf(m.Name(), m.SimpleString()) 

149 """ 

150 

151 def __init__(self, *options: Union[_MatcherTypeT, "TypeOf[_MatcherTypeT]"]) -> None: 

152 actual_options: List[_MatcherTypeT] = [] 

153 for option in options: 

154 if isinstance(option, TypeOf): 

155 if option.initalized: 

156 raise Exception( 

157 "Cannot chain an uninitalized TypeOf with an initalized one" 

158 ) 

159 actual_options.extend(option._raw_options) 

160 else: 

161 actual_options.append(option) 

162 

163 self._initalized = False 

164 self._call_items: Tuple[Tuple[object, ...], Dict[str, object]] = ((), {}) 

165 self._raw_options: Tuple[_MatcherTypeT, ...] = tuple(actual_options) 

166 

167 @property 

168 def initalized(self) -> bool: 

169 return self._initalized 

170 

171 @property 

172 def options(self) -> Iterator[BaseMatcherNode]: 

173 for option in self._raw_options: 

174 args, kwargs = self._call_items 

175 matcher_pattern = option(*args, **kwargs) 

176 yield matcher_pattern 

177 

178 def __call__(self, *args: object, **kwargs: object) -> BaseMatcherNode: 

179 self._initalized = True 

180 self._call_items = (args, kwargs) 

181 return self 

182 

183 # pyre-fixme[14]: `__or__` overrides method defined in `type` inconsistently. 

184 # pyre-fixme[15]: `__or__` overrides method defined in `type` inconsistently. 

185 def __or__( 

186 self, other: _OtherNodeMatcherTypeT 

187 ) -> "TypeOf[Union[_MatcherTypeT, _OtherNodeMatcherTypeT]]": 

188 return TypeOf[Union[_MatcherTypeT, _OtherNodeMatcherTypeT]](self, other) 

189 

190 # pyre-fixme[14]: `__and__` overrides method defined in `BaseMatcherNode` 

191 # inconsistently. 

192 def __and__(self, other: _OtherNodeMatcherTypeT) -> NoReturn: 

193 left, right = type(self).__name__, other.__name__ 

194 raise TypeError( 

195 f"TypeError: unsupported operand type(s) for &: {left!r} and {right!r}" 

196 ) 

197 

198 def __invert__(self) -> "AllOf[BaseMatcherNode]": 

199 return AllOf(*map(DoesNotMatch, self.options)) 

200 

201 def __repr__(self) -> str: 

202 types = ", ".join(repr(option) for option in self._raw_options) 

203 return f"TypeOf({types}, initalized = {self.initalized})" 

204 

205 

206class OneOf(Generic[_MatcherT], BaseMatcherNode): 

207 """ 

208 Matcher that matches any one of its options. Useful when you want to match 

209 against one of several options for a single node. You can also construct a 

210 :class:`OneOf` matcher by using Python's bitwise or operator with concrete 

211 matcher classes. 

212 

213 For example, you could match against ``True``/``False`` like:: 

214 

215 m.OneOf(m.Name("True"), m.Name("False")) 

216 

217 Or you could use the shorthand, like:: 

218 

219 m.Name("True") | m.Name("False") 

220 

221 """ 

222 

223 def __init__(self, *options: Union[_MatcherT, "OneOf[_MatcherT]"]) -> None: 

224 actual_options: List[_MatcherT] = [] 

225 for option in options: 

226 if isinstance(option, AllOf): 

227 raise Exception("Cannot use AllOf and OneOf in combination!") 

228 elif isinstance(option, (OneOf, TypeOf)): 

229 actual_options.extend(option.options) 

230 else: 

231 actual_options.append(option) 

232 self._options: Sequence[_MatcherT] = tuple(actual_options) 

233 

234 @property 

235 def options(self) -> Sequence[_MatcherT]: 

236 """ 

237 The normalized list of options that we can choose from to satisfy a 

238 :class:`OneOf` matcher. If any of these matchers are true, the 

239 :class:`OneOf` matcher will also be considered a match. 

240 """ 

241 return self._options 

242 

243 # pyre-fixme[14]: `__or__` overrides method defined in `type` inconsistently. 

244 # pyre-fixme[15]: `__or__` overrides method defined in `type` inconsistently. 

245 def __or__(self, other: _OtherNodeT) -> "OneOf[Union[_MatcherT, _OtherNodeT]]": 

246 # Without a cast, pyre thinks that the below OneOf is type OneOf[object] 

247 # even though it has the types passed into it. 

248 return cast(OneOf[Union[_MatcherT, _OtherNodeT]], OneOf(self, other)) 

249 

250 def __and__(self, other: _OtherNodeT) -> NoReturn: 

251 raise Exception("Cannot use AllOf and OneOf in combination!") 

252 

253 def __invert__(self) -> "AllOf[_MatcherT]": 

254 # Invert using De Morgan's Law so we don't have to complicate types. 

255 return cast(AllOf[_MatcherT], AllOf(*[DoesNotMatch(m) for m in self._options])) 

256 

257 def __repr__(self) -> str: 

258 return f"OneOf({', '.join([repr(o) for o in self._options])})" 

259 

260 

261class AllOf(Generic[_MatcherT], BaseMatcherNode): 

262 """ 

263 Matcher that matches all of its options. Useful when you want to match 

264 against a concrete matcher and a :class:`MatchIfTrue` at the same time. Also 

265 useful when you want to match against a concrete matcher and a 

266 :func:`DoesNotMatch` at the same time. You can also construct a 

267 :class:`AllOf` matcher by using Python's bitwise and operator with concrete 

268 matcher classes. 

269 

270 For example, you could match against ``True`` in a roundabout way like:: 

271 

272 m.AllOf(m.Name(), m.Name("True")) 

273 

274 Or you could use the shorthand, like:: 

275 

276 m.Name() & m.Name("True") 

277 

278 Similar to :class:`OneOf`, this can be used in place of any concrete matcher. 

279 

280 Real-world cases where :class:`AllOf` is useful are hard to come by but they 

281 are still provided for the limited edge cases in which they make sense. In 

282 the example above, we are redundantly matching against any LibCST 

283 :class:`~libcst.Name` node as well as LibCST :class:`~libcst.Name` nodes that 

284 have the ``value`` of ``True``. We could drop the first option entirely and 

285 get the same result. Often, if you are using a :class:`AllOf`, 

286 you can refactor your code to be simpler. 

287 

288 For example, the following matches any function call to ``foo``, and 

289 any function call which takes zero arguments:: 

290 

291 m.AllOf(m.Call(func=m.Name("foo")), m.Call(args=())) 

292 

293 This could be refactored into the following equivalent concrete matcher:: 

294 

295 m.Call(func=m.Name("foo"), args=()) 

296 

297 """ 

298 

299 def __init__(self, *options: Union[_MatcherT, "AllOf[_MatcherT]"]) -> None: 

300 actual_options: List[_MatcherT] = [] 

301 for option in options: 

302 if isinstance(option, OneOf): 

303 raise Exception("Cannot use AllOf and OneOf in combination!") 

304 elif isinstance(option, TypeOf): 

305 raise Exception("Cannot use AllOf and TypeOf in combination!") 

306 elif isinstance(option, AllOf): 

307 actual_options.extend(option.options) 

308 else: 

309 actual_options.append(option) 

310 self._options: Sequence[_MatcherT] = tuple(actual_options) 

311 

312 @property 

313 def options(self) -> Sequence[_MatcherT]: 

314 """ 

315 The normalized list of options that we can choose from to satisfy a 

316 :class:`AllOf` matcher. If all of these matchers are true, the 

317 :class:`AllOf` matcher will also be considered a match. 

318 """ 

319 return self._options 

320 

321 # pyre-fixme[14]: `__or__` overrides method defined in `type` inconsistently. 

322 # pyre-fixme[15]: `__or__` overrides method defined in `type` inconsistently. 

323 def __or__(self, other: _OtherNodeT) -> NoReturn: 

324 raise Exception("Cannot use AllOf and OneOf in combination!") 

325 

326 def __and__(self, other: _OtherNodeT) -> "AllOf[Union[_MatcherT, _OtherNodeT]]": 

327 # Without a cast, pyre thinks that the below AllOf is type AllOf[object] 

328 # even though it has the types passed into it. 

329 return cast(AllOf[Union[_MatcherT, _OtherNodeT]], AllOf(self, other)) 

330 

331 def __invert__(self) -> "OneOf[_MatcherT]": 

332 # Invert using De Morgan's Law so we don't have to complicate types. 

333 return cast(OneOf[_MatcherT], OneOf(*[DoesNotMatch(m) for m in self._options])) 

334 

335 def __repr__(self) -> str: 

336 return f"AllOf({', '.join([repr(o) for o in self._options])})" 

337 

338 

339class _InverseOf(Generic[_MatcherT]): 

340 """ 

341 Matcher that inverts the match result of its child. You can also construct a 

342 :class:`_InverseOf` matcher by using Python's bitwise invert operator with concrete 

343 matcher classes or any special matcher. 

344 

345 Note that you should refrain from constructing a :class:`_InverseOf` directly, and 

346 should instead use the :func:`DoesNotMatch` helper function. 

347 

348 For example, the following matches against any identifier that isn't 

349 ``True``/``False``:: 

350 

351 m.DoesNotMatch(m.OneOf(m.Name("True"), m.Name("False"))) 

352 

353 Or you could use the shorthand, like: 

354 

355 ~(m.Name("True") | m.Name("False")) 

356 

357 """ 

358 

359 def __init__(self, matcher: _MatcherT) -> None: 

360 self._matcher: _MatcherT = matcher 

361 

362 @property 

363 def matcher(self) -> _MatcherT: 

364 """ 

365 The matcher that we will evaluate and invert. If this matcher is true, then 

366 :class:`_InverseOf` will be considered not a match, and vice-versa. 

367 """ 

368 return self._matcher 

369 

370 # pyre-fixme[14]: `__or__` overrides method defined in `type` inconsistently. 

371 # pyre-fixme[15]: `__or__` overrides method defined in `type` inconsistently. 

372 def __or__(self, other: _OtherNodeT) -> "OneOf[Union[_MatcherT, _OtherNodeT]]": 

373 # Without a cast, pyre thinks that the below OneOf is type OneOf[object] 

374 # even though it has the types passed into it. 

375 return cast(OneOf[Union[_MatcherT, _OtherNodeT]], OneOf(self, other)) 

376 

377 def __and__(self, other: _OtherNodeT) -> "AllOf[Union[_MatcherT, _OtherNodeT]]": 

378 # Without a cast, pyre thinks that the below AllOf is type AllOf[object] 

379 # even though it has the types passed into it. 

380 return cast(AllOf[Union[_MatcherT, _OtherNodeT]], AllOf(self, other)) 

381 

382 def __getattr__(self, key: str) -> object: 

383 # We lie about types to make _InverseOf appear transparent. So, its conceivable 

384 # that somebody might try to dereference an attribute on the _MatcherT wrapped 

385 # node and become surprised that it doesn't work. 

386 return getattr(self._matcher, key) 

387 

388 def __invert__(self) -> _MatcherT: 

389 return self._matcher 

390 

391 def __repr__(self) -> str: 

392 return f"DoesNotMatch({repr(self._matcher)})" 

393 

394 

395class _ExtractMatchingNode(Generic[_MatcherT]): 

396 """ 

397 Transparent pass-through matcher that captures the node which matches its children, 

398 making it available to the caller of :func:`extract` or :func:`extractall`. 

399 

400 Note that you should refrain from constructing a :class:`_ExtractMatchingNode` 

401 directly, and should instead use the :func:`SaveMatchedNode` helper function. 

402 

403 For example, the following will match against any binary operation whose left 

404 and right operands are not integers, saving those expressions for later inspection. 

405 If used inside :func:`extract` or :func:`extractall`, the resulting dictionary will 

406 contain the keys ``left_operand`` and ``right_operand``. 

407 

408 m.BinaryOperation( 

409 left=m.SaveMatchedNode( 

410 m.DoesNotMatch(m.Integer()), 

411 "left_operand", 

412 ), 

413 right=m.SaveMatchedNode( 

414 m.DoesNotMatch(m.Integer()), 

415 "right_operand", 

416 ), 

417 ) 

418 """ 

419 

420 def __init__(self, matcher: _MatcherT, name: str) -> None: 

421 self._matcher: _MatcherT = matcher 

422 self._name: str = name 

423 

424 @property 

425 def matcher(self) -> _MatcherT: 

426 """ 

427 The matcher that we will evaluate and capture matching LibCST nodes for. 

428 If this matcher is true, then :class:`_ExtractMatchingNode` will be considered 

429 a match and will save the node which matched. 

430 """ 

431 return self._matcher 

432 

433 @property 

434 def name(self) -> str: 

435 """ 

436 The name we will call our captured LibCST node inside the resulting dictionary 

437 returned by :func:`extract` or :func:`extractall`. 

438 """ 

439 return self._name 

440 

441 # pyre-fixme[14]: `__or__` overrides method defined in `type` inconsistently. 

442 # pyre-fixme[15]: `__or__` overrides method defined in `type` inconsistently. 

443 def __or__(self, other: _OtherNodeT) -> "OneOf[Union[_MatcherT, _OtherNodeT]]": 

444 # Without a cast, pyre thinks that the below OneOf is type OneOf[object] 

445 # even though it has the types passed into it. 

446 return cast(OneOf[Union[_MatcherT, _OtherNodeT]], OneOf(self, other)) 

447 

448 def __and__(self, other: _OtherNodeT) -> "AllOf[Union[_MatcherT, _OtherNodeT]]": 

449 # This doesn't make sense. If we have multiple SaveMatchedNode captures 

450 # that are captured with an and, either all of them will be assigned the 

451 # same node, or none of them. It makes more sense to move the SaveMatchedNode 

452 # up to wrap the AllOf. 

453 raise Exception( 

454 ( 

455 "Cannot use AllOf with SavedMatchedNode children! Instead, you should " 

456 + "use SaveMatchedNode(AllOf(options...))." 

457 ) 

458 ) 

459 

460 def __getattr__(self, key: str) -> object: 

461 # We lie about types to make _ExtractMatchingNode appear transparent. So, 

462 # its conceivable that somebody might try to dereference an attribute on 

463 # the _MatcherT wrapped node and become surprised that it doesn't work. 

464 return getattr(self._matcher, key) 

465 

466 def __invert__(self) -> "_MatcherT": 

467 # This doesn't make sense. We don't want to capture a node only if it 

468 # doesn't match, since this will never capture anything. 

469 raise Exception( 

470 ( 

471 "Cannot invert a SaveMatchedNode. Instead you should wrap SaveMatchedNode " 

472 + "around your inversion itself" 

473 ) 

474 ) 

475 

476 def __repr__(self) -> str: 

477 return ( 

478 f"SaveMatchedNode(matcher={repr(self._matcher)}, name={repr(self._name)})" 

479 ) 

480 

481 

482class MatchIfTrue(Generic[_MatchIfTrueT]): 

483 """ 

484 Matcher that matches if its child callable returns ``True``. The child callable 

485 should take one argument which is the attribute on the LibCST node we are 

486 trying to match against. This is useful if you want to do complex logic to 

487 determine if an attribute should match or not. One example of this is the 

488 :func:`MatchRegex` matcher build on top of :class:`MatchIfTrue` which takes a 

489 regular expression and matches any string attribute where a regex match is found. 

490 

491 For example, to match on any identifier spelled with the letter ``e``:: 

492 

493 m.Name(value=m.MatchIfTrue(lambda value: "e" in value)) 

494 

495 This can be used in place of any concrete matcher as long as it is not the 

496 root matcher. Calling :func:`matches` directly on a :class:`MatchIfTrue` is 

497 redundant since you can just call the child callable directly with the node 

498 you are passing to :func:`matches`. 

499 """ 

500 

501 _func: Callable[[_MatchIfTrueT], bool] 

502 

503 def __init__(self, func: Callable[[_MatchIfTrueT], bool]) -> None: 

504 self._func = func 

505 

506 @property 

507 def func(self) -> Callable[[_MatchIfTrueT], bool]: 

508 """ 

509 The function that we will call with a LibCST node in order to determine 

510 if we match. If the function returns ``True`` then we consider ourselves 

511 to be a match. 

512 """ 

513 return self._func 

514 

515 # pyre-fixme[14]: `__or__` overrides method defined in `type` inconsistently. 

516 # pyre-fixme[15]: `__or__` overrides method defined in `type` inconsistently. 

517 def __or__( 

518 self, other: _OtherNodeT 

519 ) -> "OneOf[Union[MatchIfTrue[_MatchIfTrueT], _OtherNodeT]]": 

520 # Without a cast, pyre thinks that the below OneOf is type OneOf[object] 

521 # even though it has the types passed into it. 

522 return cast( 

523 OneOf[Union[MatchIfTrue[_MatchIfTrueT], _OtherNodeT]], OneOf(self, other) 

524 ) 

525 

526 def __and__( 

527 self, other: _OtherNodeT 

528 ) -> "AllOf[Union[MatchIfTrue[_MatchIfTrueT], _OtherNodeT]]": 

529 # Without a cast, pyre thinks that the below AllOf is type AllOf[object] 

530 # even though it has the types passed into it. 

531 return cast( 

532 AllOf[Union[MatchIfTrue[_MatchIfTrueT], _OtherNodeT]], AllOf(self, other) 

533 ) 

534 

535 def __invert__(self) -> "MatchIfTrue[_MatchIfTrueT]": 

536 # Construct a wrapped version of MatchIfTrue for typing simplicity. 

537 # Without the cast, pyre doesn't seem to think the lambda is valid. 

538 return MatchIfTrue(lambda val: not self._func(val)) 

539 

540 def __repr__(self) -> str: 

541 return f"MatchIfTrue({repr(self._func)})" 

542 

543 

544def MatchRegex(regex: Union[str, Pattern[str]]) -> MatchIfTrue[str]: 

545 """ 

546 Used as a convenience wrapper to :class:`MatchIfTrue` which allows for 

547 matching a string attribute against a regex. ``regex`` can be any regular 

548 expression string or a compiled ``Pattern``. This uses Python's re module 

549 under the hood and is compatible with syntax documented on 

550 `docs.python.org <https://docs.python.org/3/library/re.html>`_. 

551 

552 For example, to match against any identifier that is at least one character 

553 long and only contains alphabetical characters:: 

554 

555 m.Name(value=m.MatchRegex(r'[A-Za-z]+')) 

556 

557 This can be used in place of any string literal when constructing a concrete 

558 matcher. 

559 """ 

560 

561 def _match_func(value: object) -> bool: 

562 if isinstance(value, str): 

563 # pyre-ignore Pyre doesn't think a 'Pattern' can be passed to fullmatch. 

564 return bool(re.fullmatch(regex, value)) 

565 else: 

566 return False 

567 

568 return MatchIfTrue(_match_func) 

569 

570 

571class _BaseMetadataMatcher: 

572 """ 

573 Class that's only around for typing purposes. 

574 """ 

575 

576 pass 

577 

578 

579class MatchMetadata(_BaseMetadataMatcher): 

580 """ 

581 Matcher that looks up the metadata on the current node using the provided 

582 metadata provider and compares the value on the node against the value provided 

583 to :class:`MatchMetadata`. 

584 If the metadata provider is unresolved, a :class:`LookupError` exeption will be 

585 raised and ask you to provide a :class:`~libcst.metadata.MetadataWrapper`. 

586 If the metadata value does not exist for a particular node, :class:`MatchMetadata` 

587 will be considered not a match. 

588 

589 For example, to match against any function call which has one parameter which 

590 is used in a load expression context:: 

591 

592 m.Call( 

593 args=[ 

594 m.Arg( 

595 m.MatchMetadata( 

596 meta.ExpressionContextProvider, 

597 meta.ExpressionContext.LOAD, 

598 ) 

599 ) 

600 ] 

601 ) 

602 

603 To match against any :class:`~libcst.Name` node for the identifier ``foo`` 

604 which is the target of an assignment:: 

605 

606 m.Name( 

607 value="foo", 

608 metadata=m.MatchMetadata( 

609 meta.ExpressionContextProvider, 

610 meta.ExpressionContext.STORE, 

611 ) 

612 ) 

613 

614 This can be used in place of any concrete matcher as long as it is not the 

615 root matcher. Calling :func:`matches` directly on a :class:`MatchMetadata` is 

616 redundant since you can just check the metadata on the root node that you 

617 are passing to :func:`matches`. 

618 """ 

619 

620 def __init__( 

621 self, 

622 key: Type[meta.BaseMetadataProvider[_MetadataValueT]], 

623 value: _MetadataValueT, 

624 ) -> None: 

625 self._key: Type[meta.BaseMetadataProvider[_MetadataValueT]] = key 

626 self._value: _MetadataValueT = value 

627 

628 @property 

629 def key(self) -> meta.ProviderT: 

630 """ 

631 The metadata provider that we will use to fetch values when identifying whether 

632 a node matches this matcher. We compare the value returned from the metadata 

633 provider to the value provided in ``value`` when determining a match. 

634 """ 

635 return self._key 

636 

637 @property 

638 def value(self) -> object: 

639 """ 

640 The value that we will compare against the return from the metadata provider 

641 for each node when determining a match. 

642 """ 

643 return self._value 

644 

645 # pyre-fixme[14]: `__or__` overrides method defined in `type` inconsistently. 

646 # pyre-fixme[15]: `__or__` overrides method defined in `type` inconsistently. 

647 def __or__(self, other: _OtherNodeT) -> "OneOf[Union[MatchMetadata, _OtherNodeT]]": 

648 # Without the cast, pyre doesn't know this is valid 

649 return cast(OneOf[Union[MatchMetadata, _OtherNodeT]], OneOf(self, other)) 

650 

651 def __and__(self, other: _OtherNodeT) -> "AllOf[Union[MatchMetadata, _OtherNodeT]]": 

652 # Without the cast, pyre doesn't know this is valid 

653 return cast(AllOf[Union[MatchMetadata, _OtherNodeT]], AllOf(self, other)) 

654 

655 def __invert__(self) -> "MatchMetadata": 

656 # We intentionally lie here, for the same reason given in the documentation 

657 # for DoesNotMatch. 

658 return cast(MatchMetadata, _InverseOf(self)) 

659 

660 def __repr__(self) -> str: 

661 return f"MatchMetadata(key={repr(self._key)}, value={repr(self._value)})" 

662 

663 

664class MatchMetadataIfTrue(_BaseMetadataMatcher): 

665 """ 

666 Matcher that looks up the metadata on the current node using the provided 

667 metadata provider and passes it to a callable which can inspect the metadata 

668 further, returning ``True`` if the matcher should be considered a match. 

669 If the metadata provider is unresolved, a :class:`LookupError` exeption will be 

670 raised and ask you to provide a :class:`~libcst.metadata.MetadataWrapper`. 

671 If the metadata value does not exist for a particular node, 

672 :class:`MatchMetadataIfTrue` will be considered not a match. 

673 

674 For example, to match against any arg whose qualified name might be 

675 ``typing.Dict``:: 

676 

677 m.Call( 

678 args=[ 

679 m.Arg( 

680 m.MatchMetadataIfTrue( 

681 meta.QualifiedNameProvider, 

682 lambda qualnames: any(n.name == "typing.Dict" for n in qualnames) 

683 ) 

684 ) 

685 ] 

686 ) 

687 

688 To match against any :class:`~libcst.Name` node for the identifier ``foo`` 

689 as long as that identifier is found at the beginning of an unindented line:: 

690 

691 m.Name( 

692 value="foo", 

693 metadata=m.MatchMetadataIfTrue( 

694 meta.PositionProvider, 

695 lambda position: position.start.column == 0, 

696 ) 

697 ) 

698 

699 This can be used in place of any concrete matcher as long as it is not the 

700 root matcher. Calling :func:`matches` directly on a :class:`MatchMetadataIfTrue` 

701 is redundant since you can just check the metadata on the root node that you 

702 are passing to :func:`matches`. 

703 """ 

704 

705 def __init__( 

706 self, 

707 key: Type[meta.BaseMetadataProvider[_MetadataValueT]], 

708 func: Callable[[_MetadataValueT], bool], 

709 ) -> None: 

710 self._key: Type[meta.BaseMetadataProvider[_MetadataValueT]] = key 

711 self._func: Callable[[_MetadataValueT], bool] = func 

712 

713 @property 

714 def key(self) -> meta.ProviderT: 

715 """ 

716 The metadata provider that we will use to fetch values when identifying whether 

717 a node matches this matcher. We pass the value returned from the metadata 

718 provider to the callable given to us in ``func``. 

719 """ 

720 return self._key 

721 

722 @property 

723 def func(self) -> Callable[[object], bool]: 

724 """ 

725 The function that we will call with a value retrieved from the metadata provider 

726 provided in ``key``. If the function returns ``True`` then we consider ourselves 

727 to be a match. 

728 """ 

729 return self._func 

730 

731 # pyre-fixme[14]: `__or__` overrides method defined in `type` inconsistently. 

732 # pyre-fixme[15]: `__or__` overrides method defined in `type` inconsistently. 

733 def __or__( 

734 self, other: _OtherNodeT 

735 ) -> "OneOf[Union[MatchMetadataIfTrue, _OtherNodeT]]": 

736 # Without the cast, pyre doesn't know this is valid 

737 return cast(OneOf[Union[MatchMetadataIfTrue, _OtherNodeT]], OneOf(self, other)) 

738 

739 def __and__( 

740 self, other: _OtherNodeT 

741 ) -> "AllOf[Union[MatchMetadataIfTrue, _OtherNodeT]]": 

742 # Without the cast, pyre doesn't know this is valid 

743 return cast(AllOf[Union[MatchMetadataIfTrue, _OtherNodeT]], AllOf(self, other)) 

744 

745 def __invert__(self) -> "MatchMetadataIfTrue": 

746 # Construct a wrapped version of MatchMetadataIfTrue for typing simplicity. 

747 return MatchMetadataIfTrue(self._key, lambda val: not self._func(val)) 

748 

749 def __repr__(self) -> str: 

750 return f"MatchMetadataIfTrue(key={repr(self._key)}, func={repr(self._func)})" 

751 

752 

753class _BaseWildcardNode: 

754 """ 

755 A typing-only class for internal helpers in this module to be able to 

756 specify that they take a wildcard node type. 

757 """ 

758 

759 pass 

760 

761 

762class AtLeastN(Generic[_MatcherT], _BaseWildcardNode): 

763 """ 

764 Matcher that matches ``n`` or more LibCST nodes in a row in a sequence. 

765 :class:`AtLeastN` defaults to matching against the :func:`DoNotCare` matcher, 

766 so if you do not specify a matcher as a child, :class:`AtLeastN` 

767 will match only by count. If you do specify a matcher as a child, 

768 :class:`AtLeastN` will instead make sure that each LibCST node matches the 

769 matcher supplied. 

770 

771 For example, this will match all function calls with at least 3 arguments:: 

772 

773 m.Call(args=[m.AtLeastN(n=3)]) 

774 

775 This will match all function calls with 3 or more integer arguments:: 

776 

777 m.Call(args=[m.AtLeastN(n=3, matcher=m.Arg(m.Integer()))]) 

778 

779 You can combine sequence matchers with concrete matchers and special matchers 

780 and it will behave as you expect. For example, this will match all function 

781 calls that have 2 or more integer arguments in a row, followed by any arbitrary 

782 argument:: 

783 

784 m.Call(args=[m.AtLeastN(n=2, matcher=m.Arg(m.Integer())), m.DoNotCare()]) 

785 

786 And finally, this will match all function calls that have at least 5 

787 arguments, the final one being an integer:: 

788 

789 m.Call(args=[m.AtLeastN(n=4), m.Arg(m.Integer())]) 

790 """ 

791 

792 def __init__( 

793 self, 

794 matcher: Union[_MatcherT, DoNotCareSentinel] = DoNotCareSentinel.DEFAULT, 

795 *, 

796 n: int, 

797 ) -> None: 

798 if n < 0: 

799 raise Exception(f"{self.__class__.__name__} n attribute must be positive") 

800 self._n: int = n 

801 self._matcher: Union[_MatcherT, DoNotCareSentinel] = matcher 

802 

803 @property 

804 def n(self) -> int: 

805 """ 

806 The number of nodes in a row that must match :attr:`AtLeastN.matcher` for 

807 this matcher to be considered a match. If there are less than ``n`` matches, 

808 this matcher will not be considered a match. If there are equal to or more 

809 than ``n`` matches, this matcher will be considered a match. 

810 """ 

811 return self._n 

812 

813 @property 

814 def matcher(self) -> Union[_MatcherT, DoNotCareSentinel]: 

815 """ 

816 The matcher which each node in a sequence needs to match. 

817 """ 

818 return self._matcher 

819 

820 # pyre-fixme[14]: `__or__` overrides method defined in `type` inconsistently. 

821 # pyre-fixme[15]: `__or__` overrides method defined in `type` inconsistently. 

822 def __or__(self, other: object) -> NoReturn: 

823 raise Exception("AtLeastN cannot be used in a OneOf matcher") 

824 

825 def __and__(self, other: object) -> NoReturn: 

826 raise Exception("AtLeastN cannot be used in an AllOf matcher") 

827 

828 def __invert__(self) -> NoReturn: 

829 raise Exception("Cannot invert an AtLeastN matcher!") 

830 

831 def __repr__(self) -> str: 

832 if self._n == 0: 

833 return f"ZeroOrMore({repr(self._matcher)})" 

834 else: 

835 return f"AtLeastN({repr(self._matcher)}, n={self._n})" 

836 

837 

838def ZeroOrMore( 

839 matcher: Union[_MatcherT, DoNotCareSentinel] = DoNotCareSentinel.DEFAULT 

840) -> AtLeastN[Union[_MatcherT, DoNotCareSentinel]]: 

841 """ 

842 Used as a convenience wrapper to :class:`AtLeastN` when ``n`` is equal to ``0``. 

843 Use this when you want to match against any number of nodes in a sequence. 

844 

845 For example, this will match any function call with zero or more arguments, as 

846 long as all of the arguments are integers:: 

847 

848 m.Call(args=[m.ZeroOrMore(m.Arg(m.Integer()))]) 

849 

850 This will match any function call where the first argument is an integer and 

851 it doesn't matter what the rest of the arguments are:: 

852 

853 m.Call(args=[m.Arg(m.Integer()), m.ZeroOrMore()]) 

854 

855 You will often want to use :class:`ZeroOrMore` on both sides of a concrete 

856 matcher in order to match against sequences that contain a particular node 

857 in an arbitrary location. For example, the following will match any function 

858 call that takes in at least one string argument anywhere:: 

859 

860 m.Call(args=[m.ZeroOrMore(), m.Arg(m.SimpleString()), m.ZeroOrMore()]) 

861 """ 

862 return cast(AtLeastN[Union[_MatcherT, DoNotCareSentinel]], AtLeastN(matcher, n=0)) 

863 

864 

865class AtMostN(Generic[_MatcherT], _BaseWildcardNode): 

866 """ 

867 Matcher that matches ``n`` or fewer LibCST nodes in a row in a sequence. 

868 :class:`AtMostN` defaults to matching against the :func:`DoNotCare` matcher, 

869 so if you do not specify a matcher as a child, :class:`AtMostN` will 

870 match only by count. If you do specify a matcher as a child, 

871 :class:`AtMostN` will instead make sure that each LibCST node matches the 

872 matcher supplied. 

873 

874 For example, this will match all function calls with 3 or fewer arguments:: 

875 

876 m.Call(args=[m.AtMostN(n=3)]) 

877 

878 This will match all function calls with 0, 1 or 2 string arguments:: 

879 

880 m.Call(args=[m.AtMostN(n=2, matcher=m.Arg(m.SimpleString()))]) 

881 

882 You can combine sequence matchers with concrete matchers and special matchers 

883 and it will behave as you expect. For example, this will match all function 

884 calls that have 0, 1 or 2 string arguments in a row, followed by an arbitrary 

885 argument:: 

886 

887 m.Call(args=[m.AtMostN(n=2, matcher=m.Arg(m.SimpleString())), m.DoNotCare()]) 

888 

889 And finally, this will match all function calls that have at least 2 

890 arguments, the final one being a string:: 

891 

892 m.Call(args=[m.AtMostN(n=2), m.Arg(m.SimpleString())]) 

893 """ 

894 

895 def __init__( 

896 self, 

897 matcher: Union[_MatcherT, DoNotCareSentinel] = DoNotCareSentinel.DEFAULT, 

898 *, 

899 n: int, 

900 ) -> None: 

901 if n < 0: 

902 raise Exception(f"{self.__class__.__name__} n attribute must be positive") 

903 self._n: int = n 

904 self._matcher: Union[_MatcherT, DoNotCareSentinel] = matcher 

905 

906 @property 

907 def n(self) -> int: 

908 """ 

909 The number of nodes in a row that must match :attr:`AtLeastN.matcher` for 

910 this matcher to be considered a match. If there are less than or equal to 

911 ``n`` matches, then this matcher will be considered a match. Any more than 

912 ``n`` matches in a row and this matcher will stop matching and be considered 

913 not a match. 

914 """ 

915 return self._n 

916 

917 @property 

918 def matcher(self) -> Union[_MatcherT, DoNotCareSentinel]: 

919 """ 

920 The matcher which each node in a sequence needs to match. 

921 """ 

922 return self._matcher 

923 

924 # pyre-fixme[14]: `__or__` overrides method defined in `type` inconsistently. 

925 # pyre-fixme[15]: `__or__` overrides method defined in `type` inconsistently. 

926 def __or__(self, other: object) -> NoReturn: 

927 raise Exception("AtMostN cannot be used in a OneOf matcher") 

928 

929 def __and__(self, other: object) -> NoReturn: 

930 raise Exception("AtMostN cannot be used in an AllOf matcher") 

931 

932 def __invert__(self) -> NoReturn: 

933 raise Exception("Cannot invert an AtMostN matcher!") 

934 

935 def __repr__(self) -> str: 

936 if self._n == 1: 

937 return f"ZeroOrOne({repr(self._matcher)})" 

938 else: 

939 return f"AtMostN({repr(self._matcher)}, n={self._n})" 

940 

941 

942def ZeroOrOne( 

943 matcher: Union[_MatcherT, DoNotCareSentinel] = DoNotCareSentinel.DEFAULT 

944) -> AtMostN[Union[_MatcherT, DoNotCareSentinel]]: 

945 """ 

946 Used as a convenience wrapper to :class:`AtMostN` when ``n`` is equal to ``1``. 

947 This is effectively a maybe clause. 

948 

949 For example, this will match any function call with zero or one integer 

950 argument:: 

951 

952 m.Call(args=[m.ZeroOrOne(m.Arg(m.Integer()))]) 

953 

954 This will match any function call that has two or three arguments, and 

955 the first and last arguments are strings:: 

956 

957 m.Call(args=[m.Arg(m.SimpleString()), m.ZeroOrOne(), m.Arg(m.SimpleString())]) 

958 

959 """ 

960 return cast(AtMostN[Union[_MatcherT, DoNotCareSentinel]], AtMostN(matcher, n=1)) 

961 

962 

963def DoesNotMatch(obj: _OtherNodeT) -> _OtherNodeT: 

964 """ 

965 Matcher helper that inverts the match result of its child. You can also invert a 

966 matcher by using Python's bitwise invert operator on concrete matchers or any 

967 special matcher. 

968 

969 For example, the following matches against any identifier that isn't 

970 ``True``/``False``:: 

971 

972 m.DoesNotMatch(m.OneOf(m.Name("True"), m.Name("False"))) 

973 

974 Or you could use the shorthand, like:: 

975 

976 ~(m.Name("True") | m.Name("False")) 

977 

978 This can be used in place of any concrete matcher as long as it is not the 

979 root matcher. Calling :func:`matches` directly on a :func:`DoesNotMatch` is 

980 redundant since you can invert the return of :func:`matches` using a bitwise not. 

981 """ 

982 

983 # This type is a complete, dirty lie, but there's no way to recursively apply 

984 # a parameter to each type inside a Union that may be in a _OtherNodeT. 

985 # However, given the way _InverseOf works (it will unwrap itself if 

986 # inverted again), and the way we apply De Morgan's law for OneOf and AllOf, 

987 # this lie ends up getting us correct typing. Anywhere a node is valid, using 

988 # DoesNotMatch(node) is also valid. 

989 # 

990 # ~MatchIfTrue is still MatchIfTrue 

991 # ~MatchMetadataIfTrue is still MatchMetadataIfTrue 

992 # ~OneOf[x] is AllOf[~x] 

993 # ~AllOf[x] is OneOf[~x] 

994 # ~~x is x 

995 # 

996 # So, under all circumstances, since OneOf/AllOf are both allowed in every 

997 # instance, and given that inverting MatchIfTrue is still MatchIfTrue, 

998 # and inverting an inverted value returns us the original, its clear that 

999 # there are no operations we can possibly do that bring us outside of the 

1000 # types specified in the concrete matchers as long as we lie that DoesNotMatch 

1001 # returns the value passed in. 

1002 if isinstance( 

1003 obj, 

1004 ( 

1005 BaseMatcherNode, 

1006 MatchIfTrue, 

1007 _BaseMetadataMatcher, 

1008 _InverseOf, 

1009 _ExtractMatchingNode, 

1010 ), 

1011 ): 

1012 # We can use the overridden __invert__ in this case. Pyre doesn't think 

1013 # we can though, and casting doesn't fix the issue. 

1014 inverse = ~obj 

1015 else: 

1016 # We must wrap in a _InverseOf. 

1017 inverse = _InverseOf(obj) 

1018 return cast(_OtherNodeT, inverse) 

1019 

1020 

1021def SaveMatchedNode(matcher: _OtherNodeT, name: str) -> _OtherNodeT: 

1022 """ 

1023 Matcher helper that captures the matched node that matched against a matcher 

1024 class, making it available in the dictionary returned by :func:`extract` or 

1025 :func:`extractall`. 

1026 

1027 For example, the following will match against any binary operation whose left 

1028 and right operands are not integers, saving those expressions for later inspection. 

1029 If used inside :func:`extract` or :func:`extractall`, the resulting dictionary 

1030 will contain the keys ``left_operand`` and ``right_operand``:: 

1031 

1032 m.BinaryOperation( 

1033 left=m.SaveMatchedNode( 

1034 m.DoesNotMatch(m.Integer()), 

1035 "left_operand", 

1036 ), 

1037 right=m.SaveMatchedNode( 

1038 m.DoesNotMatch(m.Integer()), 

1039 "right_operand", 

1040 ), 

1041 ) 

1042 

1043 This can be used in place of any concrete matcher as long as it is not the 

1044 root matcher. Calling :func:`extract` directly on a :func:`SaveMatchedNode` is 

1045 redundant since you already have the reference to the node itself. 

1046 """ 

1047 return cast(_OtherNodeT, _ExtractMatchingNode(matcher, name)) 

1048 

1049 

1050def _matches_zero_nodes( 

1051 matcher: Union[ 

1052 BaseMatcherNode, 

1053 _BaseWildcardNode, 

1054 MatchIfTrue[libcst.CSTNode], 

1055 _BaseMetadataMatcher, 

1056 DoNotCareSentinel, 

1057 ] 

1058) -> bool: 

1059 if isinstance(matcher, AtLeastN) and matcher.n == 0: 

1060 return True 

1061 if isinstance(matcher, AtMostN): 

1062 return True 

1063 if isinstance(matcher, _ExtractMatchingNode): 

1064 return _matches_zero_nodes(matcher.matcher) 

1065 return False 

1066 

1067 

1068@dataclass(frozen=True) 

1069class _SequenceMatchesResult: 

1070 sequence_capture: Optional[ 

1071 Dict[str, Union[libcst.CSTNode, Sequence[libcst.CSTNode]]] 

1072 ] 

1073 matched_nodes: Optional[ 

1074 Union[libcst.CSTNode, MaybeSentinel, Sequence[libcst.CSTNode]] 

1075 ] 

1076 

1077 

1078def _sequence_matches( # noqa: C901 

1079 nodes: Sequence[Union[MaybeSentinel, libcst.CSTNode]], 

1080 matchers: Sequence[ 

1081 Union[ 

1082 BaseMatcherNode, 

1083 _BaseWildcardNode, 

1084 MatchIfTrue[libcst.CSTNode], 

1085 _BaseMetadataMatcher, 

1086 DoNotCareSentinel, 

1087 ] 

1088 ], 

1089 metadata_lookup: Callable[[meta.ProviderT, libcst.CSTNode], object], 

1090) -> _SequenceMatchesResult: 

1091 if not nodes and not matchers: 

1092 # Base case, empty lists are always matches 

1093 return _SequenceMatchesResult({}, None) 

1094 if not nodes and matchers: 

1095 # Base case, we have one or more matcher that wasn't matched 

1096 if all(_matches_zero_nodes(m) for m in matchers): 

1097 return _SequenceMatchesResult( 

1098 # pyre-ignore[16]: `MatchIfTrue` has no attribute `name`. 

1099 {m.name: () for m in matchers if isinstance(m, _ExtractMatchingNode)}, 

1100 (), 

1101 ) 

1102 else: 

1103 return _SequenceMatchesResult(None, None) 

1104 if nodes and not matchers: 

1105 # Base case, we have nodes left that don't match any matcher 

1106 return _SequenceMatchesResult(None, None) 

1107 

1108 # Recursive case, nodes and matchers LHS matches 

1109 node = nodes[0] 

1110 matcher = matchers[0] 

1111 if isinstance(matcher, DoNotCareSentinel): 

1112 # We don't care about the value for this node. 

1113 return _SequenceMatchesResult( 

1114 _sequence_matches( 

1115 nodes[1:], matchers[1:], metadata_lookup 

1116 ).sequence_capture, 

1117 node, 

1118 ) 

1119 elif isinstance(matcher, _BaseWildcardNode): 

1120 if isinstance(matcher, AtMostN): 

1121 if matcher.n > 0: 

1122 # First, assume that this does match a node (greedy). 

1123 # Consume one node since it matched this matcher. 

1124 attribute_capture = _attribute_matches( 

1125 nodes[0], matcher.matcher, metadata_lookup 

1126 ) 

1127 if attribute_capture is not None: 

1128 result = _sequence_matches( 

1129 nodes[1:], 

1130 [AtMostN(matcher.matcher, n=matcher.n - 1), *matchers[1:]], 

1131 metadata_lookup, 

1132 ) 

1133 if result.sequence_capture is not None: 

1134 matched = result.matched_nodes 

1135 assert isinstance(matched, Sequence) 

1136 return _SequenceMatchesResult( 

1137 {**attribute_capture, **result.sequence_capture}, 

1138 # pyre-fixme[6]: Expected `Union[None, Sequence[libcst._n... 

1139 (node, *matched), 

1140 ) 

1141 # Finally, assume that this does not match the current node. 

1142 # Consume the matcher but not the node. 

1143 return _SequenceMatchesResult( 

1144 _sequence_matches( 

1145 nodes, matchers[1:], metadata_lookup 

1146 ).sequence_capture, 

1147 (), 

1148 ) 

1149 elif isinstance(matcher, AtLeastN): 

1150 if matcher.n > 0: 

1151 # Only match if we can consume one of the matches, since we still 

1152 # need to match N nodes. 

1153 attribute_capture = _attribute_matches( 

1154 nodes[0], matcher.matcher, metadata_lookup 

1155 ) 

1156 if attribute_capture is not None: 

1157 result = _sequence_matches( 

1158 nodes[1:], 

1159 [AtLeastN(matcher.matcher, n=matcher.n - 1), *matchers[1:]], 

1160 metadata_lookup, 

1161 ) 

1162 if result.sequence_capture is not None: 

1163 matched = result.matched_nodes 

1164 assert isinstance(matched, Sequence) 

1165 return _SequenceMatchesResult( 

1166 {**attribute_capture, **result.sequence_capture}, 

1167 # pyre-fixme[6]: Expected `Union[None, Sequence[libcst._n... 

1168 (node, *matched), 

1169 ) 

1170 return _SequenceMatchesResult(None, None) 

1171 else: 

1172 # First, assume that this does match a node (greedy). 

1173 # Consume one node since it matched this matcher. 

1174 attribute_capture = _attribute_matches( 

1175 nodes[0], matcher.matcher, metadata_lookup 

1176 ) 

1177 if attribute_capture is not None: 

1178 result = _sequence_matches(nodes[1:], matchers, metadata_lookup) 

1179 if result.sequence_capture is not None: 

1180 matched = result.matched_nodes 

1181 assert isinstance(matched, Sequence) 

1182 return _SequenceMatchesResult( 

1183 {**attribute_capture, **result.sequence_capture}, 

1184 # pyre-fixme[6]: Expected `Union[None, Sequence[libcst._n... 

1185 (node, *matched), 

1186 ) 

1187 # Now, assume that this does not match the current node. 

1188 # Consume the matcher but not the node. 

1189 return _SequenceMatchesResult( 

1190 _sequence_matches( 

1191 nodes, matchers[1:], metadata_lookup 

1192 ).sequence_capture, 

1193 (), 

1194 ) 

1195 else: 

1196 # There are no other types of wildcard consumers, but we're making 

1197 # pyre happy with that fact. 

1198 raise Exception(f"Logic error unrecognized wildcard {type(matcher)}!") 

1199 elif isinstance(matcher, _ExtractMatchingNode): 

1200 # See if the raw matcher matches. If it does, capture the sequence we matched and store it. 

1201 result = _sequence_matches( 

1202 nodes, [matcher.matcher, *matchers[1:]], metadata_lookup 

1203 ) 

1204 if result.sequence_capture is not None: 

1205 return _SequenceMatchesResult( 

1206 { 

1207 # Our own match capture comes first, since we wnat to allow the same 

1208 # name later in the sequence to override us. 

1209 matcher.name: result.matched_nodes, 

1210 **result.sequence_capture, 

1211 }, 

1212 result.matched_nodes, 

1213 ) 

1214 return _SequenceMatchesResult(None, None) 

1215 

1216 match_capture = _matches(node, matcher, metadata_lookup) 

1217 if match_capture is not None: 

1218 # These values match directly 

1219 result = _sequence_matches(nodes[1:], matchers[1:], metadata_lookup) 

1220 if result.sequence_capture is not None: 

1221 return _SequenceMatchesResult( 

1222 {**match_capture, **result.sequence_capture}, node 

1223 ) 

1224 

1225 # Failed recursive case, no match 

1226 return _SequenceMatchesResult(None, None) 

1227 

1228 

1229_AttributeValueT = Optional[Union[MaybeSentinel, libcst.CSTNode, str, bool]] 

1230_AttributeMatcherT = Optional[Union[BaseMatcherNode, DoNotCareSentinel, str, bool]] 

1231 

1232 

1233def _attribute_matches( # noqa: C901 

1234 node: Union[_AttributeValueT, Sequence[_AttributeValueT]], 

1235 matcher: Union[_AttributeMatcherT, Sequence[_AttributeMatcherT]], 

1236 metadata_lookup: Callable[[meta.ProviderT, libcst.CSTNode], object], 

1237) -> Optional[Dict[str, Union[libcst.CSTNode, Sequence[libcst.CSTNode]]]]: 

1238 if isinstance(matcher, DoNotCareSentinel): 

1239 # We don't care what this is, so don't penalize a non-match. 

1240 return {} 

1241 if isinstance(matcher, _InverseOf): 

1242 # Return the opposite evaluation 

1243 return ( 

1244 {} 

1245 if _attribute_matches(node, matcher.matcher, metadata_lookup) is None 

1246 else None 

1247 ) 

1248 if isinstance(matcher, _ExtractMatchingNode): 

1249 attribute_capture = _attribute_matches(node, matcher.matcher, metadata_lookup) 

1250 if attribute_capture is not None: 

1251 return { 

1252 # Our own match capture comes last, since its higher in the tree 

1253 # so we want to override any child match captures by the same name. 

1254 **attribute_capture, 

1255 matcher.name: node, 

1256 } 

1257 return None 

1258 

1259 if isinstance(matcher, MatchIfTrue): 

1260 # We should only return if the matcher function is true. 

1261 return {} if matcher.func(node) else None 

1262 

1263 if matcher is None: 

1264 # Should exactly be None 

1265 return {} if node is None else None 

1266 

1267 if isinstance(matcher, str): 

1268 # Should exactly match matcher text 

1269 return {} if node == matcher else None 

1270 

1271 if isinstance(matcher, bool): 

1272 # Should exactly match matcher bool 

1273 return {} if node is matcher else None 

1274 

1275 if isinstance(node, collections.abc.Sequence): 

1276 # Given we've generated the types for matchers based on LibCST, we know that 

1277 # this is true unless the node is badly constructed and types were ignored. 

1278 node = cast(Sequence[Union[MaybeSentinel, libcst.CSTNode]], node) 

1279 

1280 if isinstance(matcher, OneOf): 

1281 # We should compare against each of the sequences in the OneOf 

1282 for m in matcher.options: 

1283 if isinstance(m, collections.abc.Sequence): 

1284 # Should match the sequence of requested nodes 

1285 result = _sequence_matches(node, m, metadata_lookup) 

1286 if result.sequence_capture is not None: 

1287 return result.sequence_capture 

1288 elif isinstance(m, MatchIfTrue): 

1289 # TODO: return captures 

1290 return {} if m.func(node) else None 

1291 elif isinstance(matcher, AllOf): 

1292 # We should compare against each of the sequences in the AllOf 

1293 all_captures = {} 

1294 for m in matcher.options: 

1295 if isinstance(m, collections.abc.Sequence): 

1296 # Should match the sequence of requested nodes 

1297 result = _sequence_matches(node, m, metadata_lookup) 

1298 if result.sequence_capture is None: 

1299 return None 

1300 all_captures = {**all_captures, **result.sequence_capture} 

1301 else: 

1302 # The value in the AllOf wasn't a sequence, it can't match. 

1303 return None 

1304 # We passed the checks above for each node, so we passed. 

1305 return all_captures 

1306 elif isinstance(matcher, collections.abc.Sequence): 

1307 # We should assume that this matcher is a sequence to compare. Given 

1308 # the way we generate match classes, this should be true unless the 

1309 # match is badly constructed and types were ignored. 

1310 return _sequence_matches( 

1311 node, 

1312 cast( 

1313 Sequence[ 

1314 Union[ 

1315 BaseMatcherNode, 

1316 _BaseWildcardNode, 

1317 MatchIfTrue[libcst.CSTNode], 

1318 DoNotCareSentinel, 

1319 ] 

1320 ], 

1321 matcher, 

1322 ), 

1323 metadata_lookup, 

1324 ).sequence_capture 

1325 

1326 # We exhausted our possibilities, there's no match 

1327 return None 

1328 

1329 # Base case, should match node via matcher. We know the type of node is 

1330 # correct here because we generate matchers directly off of LibCST nodes, 

1331 # so the only way it is wrong is if the node was badly constructed and 

1332 # types were ignored. 

1333 return _matches( 

1334 cast(Union[MaybeSentinel, libcst.CSTNode], node), 

1335 # pyre-fixme[24]: Generic type `MatchIfTrue` expects 1 type parameter. 

1336 cast(Union[BaseMatcherNode, MatchIfTrue, _BaseMetadataMatcher], matcher), 

1337 metadata_lookup, 

1338 ) 

1339 

1340 

1341def _metadata_matches( # noqa: C901 

1342 node: libcst.CSTNode, 

1343 metadata: Union[ 

1344 _BaseMetadataMatcher, 

1345 AllOf[_BaseMetadataMatcher], 

1346 OneOf[_BaseMetadataMatcher], 

1347 _InverseOf[_BaseMetadataMatcher], 

1348 _ExtractMatchingNode[_BaseMetadataMatcher], 

1349 ], 

1350 metadata_lookup: Callable[[meta.ProviderT, libcst.CSTNode], object], 

1351) -> Optional[Dict[str, Union[libcst.CSTNode, Sequence[libcst.CSTNode]]]]: 

1352 if isinstance(metadata, OneOf): 

1353 for metadata in metadata.options: 

1354 metadata_capture = _metadata_matches(node, metadata, metadata_lookup) 

1355 if metadata_capture is not None: 

1356 return metadata_capture 

1357 return None 

1358 elif isinstance(metadata, AllOf): 

1359 all_captures = {} 

1360 for metadata in metadata.options: 

1361 metadata_capture = _metadata_matches(node, metadata, metadata_lookup) 

1362 if metadata_capture is None: 

1363 return None 

1364 all_captures = {**all_captures, **metadata_capture} 

1365 # We passed the above checks, so we pass the matcher. 

1366 return all_captures 

1367 elif isinstance(metadata, _InverseOf): 

1368 return ( 

1369 {} 

1370 if _metadata_matches(node, metadata.matcher, metadata_lookup) is None 

1371 else None 

1372 ) 

1373 elif isinstance(metadata, _ExtractMatchingNode): 

1374 metadata_capture = _metadata_matches(node, metadata.matcher, metadata_lookup) 

1375 if metadata_capture is not None: 

1376 return { 

1377 # Our own match capture comes last, since its higher in the tree 

1378 # so we want to override any child match captures by the same name. 

1379 **metadata_capture, 

1380 metadata.name: node, 

1381 } 

1382 return None 

1383 elif isinstance(metadata, MatchMetadataIfTrue): 

1384 actual_value = metadata_lookup(metadata.key, node) 

1385 if actual_value is _METADATA_MISSING_SENTINEL: 

1386 return None 

1387 return {} if metadata.func(actual_value) else None 

1388 elif isinstance(metadata, MatchMetadata): 

1389 actual_value = metadata_lookup(metadata.key, node) 

1390 if actual_value is _METADATA_MISSING_SENTINEL: 

1391 return None 

1392 return {} if actual_value == metadata.value else None 

1393 else: 

1394 raise Exception("Logic error!") 

1395 

1396 

1397def _node_matches( # noqa: C901 

1398 node: libcst.CSTNode, 

1399 matcher: Union[ 

1400 BaseMatcherNode, 

1401 MatchIfTrue[libcst.CSTNode], 

1402 _BaseMetadataMatcher, 

1403 _InverseOf[ 

1404 Union[ 

1405 BaseMatcherNode, 

1406 MatchIfTrue[libcst.CSTNode], 

1407 _BaseMetadataMatcher, 

1408 ] 

1409 ], 

1410 _ExtractMatchingNode[ 

1411 Union[ 

1412 BaseMatcherNode, 

1413 MatchIfTrue[libcst.CSTNode], 

1414 _BaseMetadataMatcher, 

1415 ] 

1416 ], 

1417 ], 

1418 metadata_lookup: Callable[[meta.ProviderT, libcst.CSTNode], object], 

1419) -> Optional[Dict[str, Union[libcst.CSTNode, Sequence[libcst.CSTNode]]]]: 

1420 # If this is a _InverseOf, then invert the result. 

1421 if isinstance(matcher, _InverseOf): 

1422 return ( 

1423 {} 

1424 if _node_matches(node, matcher.matcher, metadata_lookup) is None 

1425 else None 

1426 ) 

1427 

1428 # If this is an _ExtractMatchingNode, grab the resulting call and pass the check 

1429 # forward. 

1430 if isinstance(matcher, _ExtractMatchingNode): 

1431 node_capture = _node_matches(node, matcher.matcher, metadata_lookup) 

1432 if node_capture is not None: 

1433 return { 

1434 # We come last here since we're further up the tree, so we want to 

1435 # override any identically named child match nodes. 

1436 **node_capture, 

1437 matcher.name: node, 

1438 } 

1439 return None 

1440 

1441 # Now, check if this is a lambda matcher. 

1442 if isinstance(matcher, MatchIfTrue): 

1443 return {} if matcher.func(node) else None 

1444 

1445 if isinstance(matcher, (MatchMetadata, MatchMetadataIfTrue)): 

1446 return _metadata_matches(node, matcher, metadata_lookup) 

1447 

1448 # Now, check that the node and matcher classes are the same. 

1449 if node.__class__.__name__ != matcher.__class__.__name__: 

1450 return None 

1451 

1452 # Now, check that the children match for each attribute. 

1453 all_captures = {} 

1454 for field in fields(matcher): 

1455 if field.name == "_metadata": 

1456 # We don't care about this field, its a dataclasses implementation detail. 

1457 continue 

1458 elif field.name == "metadata": 

1459 # Special field we respect for matching metadata on a particular node. 

1460 desired = getattr(matcher, field.name) 

1461 if isinstance(desired, DoNotCareSentinel): 

1462 # We don't care about this 

1463 continue 

1464 metadata_capture = _metadata_matches(node, desired, metadata_lookup) 

1465 if metadata_capture is None: 

1466 return None 

1467 all_captures = {**all_captures, **metadata_capture} 

1468 else: 

1469 desired = getattr(matcher, field.name) 

1470 actual = getattr(node, field.name) 

1471 attribute_capture = _attribute_matches(actual, desired, metadata_lookup) 

1472 if attribute_capture is None: 

1473 return None 

1474 all_captures = {**all_captures, **attribute_capture} 

1475 

1476 # We didn't find a non-match in the above loop, so it matches! 

1477 return all_captures 

1478 

1479 

1480def _matches( 

1481 node: Union[MaybeSentinel, libcst.CSTNode], 

1482 matcher: Union[ 

1483 BaseMatcherNode, 

1484 MatchIfTrue[libcst.CSTNode], 

1485 _BaseMetadataMatcher, 

1486 _InverseOf[ 

1487 Union[ 

1488 BaseMatcherNode, 

1489 MatchIfTrue[libcst.CSTNode], 

1490 _BaseMetadataMatcher, 

1491 ] 

1492 ], 

1493 _ExtractMatchingNode[ 

1494 Union[ 

1495 BaseMatcherNode, 

1496 MatchIfTrue[libcst.CSTNode], 

1497 _BaseMetadataMatcher, 

1498 ] 

1499 ], 

1500 ], 

1501 metadata_lookup: Callable[[meta.ProviderT, libcst.CSTNode], object], 

1502) -> Optional[Dict[str, Union[libcst.CSTNode, Sequence[libcst.CSTNode]]]]: 

1503 if isinstance(node, MaybeSentinel): 

1504 # We can't possibly match on a maybe sentinel, so it only matches if 

1505 # the matcher we have is a _InverseOf. 

1506 return {} if isinstance(matcher, _InverseOf) else None 

1507 

1508 # Now, evaluate the matcher node itself. 

1509 if isinstance(matcher, (OneOf, TypeOf)): 

1510 for matcher in matcher.options: 

1511 node_capture = _node_matches(node, matcher, metadata_lookup) 

1512 if node_capture is not None: 

1513 return node_capture 

1514 return None 

1515 elif isinstance(matcher, AllOf): 

1516 all_captures = {} 

1517 for matcher in matcher.options: 

1518 node_capture = _node_matches(node, matcher, metadata_lookup) 

1519 if node_capture is None: 

1520 return None 

1521 all_captures = {**all_captures, **node_capture} 

1522 return all_captures 

1523 else: 

1524 return _node_matches(node, matcher, metadata_lookup) 

1525 

1526 

1527def _construct_metadata_fetcher_null() -> ( 

1528 Callable[[meta.ProviderT, libcst.CSTNode], object] 

1529): 

1530 def _fetch(provider: meta.ProviderT, node: libcst.CSTNode) -> NoReturn: 

1531 raise LookupError( 

1532 f"{provider.__name__} is not resolved; did you forget a MetadataWrapper?" 

1533 ) 

1534 

1535 return _fetch 

1536 

1537 

1538def _construct_metadata_fetcher_dependent( 

1539 dependent_class: libcst.MetadataDependent, 

1540) -> Callable[[meta.ProviderT, libcst.CSTNode], object]: 

1541 def _fetch(provider: meta.ProviderT, node: libcst.CSTNode) -> object: 

1542 return dependent_class.get_metadata(provider, node, _METADATA_MISSING_SENTINEL) 

1543 

1544 return _fetch 

1545 

1546 

1547def _construct_metadata_fetcher_wrapper( 

1548 wrapper: libcst.MetadataWrapper, 

1549) -> Callable[[meta.ProviderT, libcst.CSTNode], object]: 

1550 metadata: Dict[meta.ProviderT, Mapping[libcst.CSTNode, object]] = {} 

1551 

1552 def _fetch(provider: meta.ProviderT, node: libcst.CSTNode) -> object: 

1553 if provider not in metadata: 

1554 metadata[provider] = wrapper.resolve(provider) 

1555 

1556 node_metadata = metadata[provider].get(node, _METADATA_MISSING_SENTINEL) 

1557 if isinstance(node_metadata, LazyValue): 

1558 node_metadata = node_metadata() 

1559 

1560 return node_metadata 

1561 

1562 return _fetch 

1563 

1564 

1565def extract( 

1566 node: Union[MaybeSentinel, RemovalSentinel, libcst.CSTNode], 

1567 matcher: BaseMatcherNode, 

1568 *, 

1569 metadata_resolver: Optional[ 

1570 Union[libcst.MetadataDependent, libcst.MetadataWrapper] 

1571 ] = None, 

1572) -> Optional[Dict[str, Union[libcst.CSTNode, Sequence[libcst.CSTNode]]]]: 

1573 """ 

1574 Given an arbitrary node from a LibCST tree, and an arbitrary matcher, returns 

1575 a dictionary of extracted children of the tree if the node matches the shape defined 

1576 by the matcher. Note that the node can also be a :class:`~libcst.RemovalSentinel` or 

1577 a :class:`~libcst.MaybeSentinel` in order to use extract directly on transform results 

1578 and node attributes. In these cases, :func:`extract` will always return ``None``. 

1579 

1580 If the node matches the shape defined by the matcher, the return will be a dictionary 

1581 whose keys are defined by the :func:`SaveMatchedNode` name parameter, and the values 

1582 will be the node or sequence that was present at that location in the shape defined 

1583 by the matcher. In the case of multiple :func:`SaveMatchedNode` matches with the 

1584 same name, parent nodes will take prioirity over child nodes, and nodes later in 

1585 sequences will take priority over nodes earlier in sequences. 

1586 

1587 The matcher can be any concrete matcher that subclasses from :class:`BaseMatcherNode`, 

1588 or a :class:`OneOf`/:class:`AllOf` special matcher. It cannot be a 

1589 :class:`MatchIfTrue` or a :func:`DoesNotMatch` matcher since these are redundant. 

1590 It cannot be a :class:`AtLeastN` or :class:`AtMostN` matcher because these types are 

1591 wildcards which can only be used inside sequences. 

1592 """ 

1593 if isinstance(node, RemovalSentinel): 

1594 # We can't possibly match on a removal sentinel, so it doesn't match. 

1595 return None 

1596 if isinstance(matcher, (AtLeastN, AtMostN, MatchIfTrue, _BaseMetadataMatcher)): 

1597 # We can't match this, since these matchers are forbidden at top level. 

1598 # These are not subclasses of BaseMatcherNode, but in the case that the 

1599 # user is not using type checking, this should still behave correctly. 

1600 return None 

1601 

1602 if metadata_resolver is None: 

1603 fetcher = _construct_metadata_fetcher_null() 

1604 elif isinstance(metadata_resolver, libcst.MetadataWrapper): 

1605 fetcher = _construct_metadata_fetcher_wrapper(metadata_resolver) 

1606 else: 

1607 fetcher = _construct_metadata_fetcher_dependent(metadata_resolver) 

1608 

1609 return _matches(node, matcher, fetcher) 

1610 

1611 

1612def matches( 

1613 node: Union[MaybeSentinel, RemovalSentinel, libcst.CSTNode], 

1614 matcher: BaseMatcherNode, 

1615 *, 

1616 metadata_resolver: Optional[ 

1617 Union[libcst.MetadataDependent, libcst.MetadataWrapper] 

1618 ] = None, 

1619) -> bool: 

1620 """ 

1621 Given an arbitrary node from a LibCST tree, and an arbitrary matcher, returns 

1622 ``True`` if the node matches the shape defined by the matcher. Note that the node 

1623 can also be a :class:`~libcst.RemovalSentinel` or a :class:`~libcst.MaybeSentinel` 

1624 in order to use matches directly on transform results and node attributes. In these 

1625 cases, :func:`matches` will always return ``False``. 

1626 

1627 The matcher can be any concrete matcher that subclasses from :class:`BaseMatcherNode`, 

1628 or a :class:`OneOf`/:class:`AllOf` special matcher. It cannot be a 

1629 :class:`MatchIfTrue` or a :func:`DoesNotMatch` matcher since these are redundant. 

1630 It cannot be a :class:`AtLeastN` or :class:`AtMostN` matcher because these types 

1631 are wildcards which can only be used inside sequences. 

1632 """ 

1633 return extract(node, matcher, metadata_resolver=metadata_resolver) is not None 

1634 

1635 

1636class _FindAllVisitor(libcst.CSTVisitor): 

1637 def __init__( 

1638 self, 

1639 matcher: Union[ 

1640 BaseMatcherNode, 

1641 MatchIfTrue[libcst.CSTNode], 

1642 _BaseMetadataMatcher, 

1643 _InverseOf[ 

1644 Union[ 

1645 BaseMatcherNode, 

1646 MatchIfTrue[libcst.CSTNode], 

1647 _BaseMetadataMatcher, 

1648 ] 

1649 ], 

1650 ], 

1651 metadata_lookup: Callable[[meta.ProviderT, libcst.CSTNode], object], 

1652 ) -> None: 

1653 self.matcher = matcher 

1654 self.metadata_lookup = metadata_lookup 

1655 self.found_nodes: List[libcst.CSTNode] = [] 

1656 self.extracted_nodes: List[ 

1657 Dict[str, Union[libcst.CSTNode, Sequence[libcst.CSTNode]]] 

1658 ] = [] 

1659 

1660 def on_visit(self, node: libcst.CSTNode) -> bool: 

1661 match = _matches(node, self.matcher, self.metadata_lookup) 

1662 if match is not None: 

1663 self.found_nodes.append(node) 

1664 self.extracted_nodes.append(match) 

1665 return True 

1666 

1667 

1668def _find_or_extract_all( 

1669 tree: Union[MaybeSentinel, RemovalSentinel, libcst.CSTNode, meta.MetadataWrapper], 

1670 matcher: Union[ 

1671 BaseMatcherNode, 

1672 MatchIfTrue[libcst.CSTNode], 

1673 _BaseMetadataMatcher, 

1674 # The inverse clause is left off of the public functions `findall` and 

1675 # `extractall` because we play a dirty trick. We lie to the typechecker 

1676 # that `DoesNotMatch` returns identity, so the public functions don't 

1677 # need to be aware of inverses. If we could represent predicate logic 

1678 # in python types we could get away with this, but that's not the state 

1679 # of things right now. 

1680 _InverseOf[ 

1681 Union[ 

1682 BaseMatcherNode, 

1683 MatchIfTrue[libcst.CSTNode], 

1684 _BaseMetadataMatcher, 

1685 ] 

1686 ], 

1687 ], 

1688 *, 

1689 metadata_resolver: Optional[ 

1690 Union[libcst.MetadataDependent, libcst.MetadataWrapper] 

1691 ] = None, 

1692) -> Tuple[ 

1693 Sequence[libcst.CSTNode], 

1694 Sequence[Dict[str, Union[libcst.CSTNode, Sequence[libcst.CSTNode]]]], 

1695]: 

1696 if isinstance(tree, (RemovalSentinel, MaybeSentinel)): 

1697 # We can't possibly match on a removal sentinel, so it doesn't match. 

1698 return [], [] 

1699 if isinstance(matcher, (AtLeastN, AtMostN)): 

1700 # We can't match this, since these matchers are forbidden at top level. 

1701 # These are not subclasses of BaseMatcherNode, but in the case that the 

1702 # user is not using type checking, this should still behave correctly. 

1703 return [], [] 

1704 

1705 if isinstance(tree, meta.MetadataWrapper) and metadata_resolver is None: 

1706 # Provide a convenience for calling findall directly on a MetadataWrapper. 

1707 metadata_resolver = tree 

1708 

1709 if metadata_resolver is None: 

1710 fetcher = _construct_metadata_fetcher_null() 

1711 elif isinstance(metadata_resolver, libcst.MetadataWrapper): 

1712 fetcher = _construct_metadata_fetcher_wrapper(metadata_resolver) 

1713 else: 

1714 fetcher = _construct_metadata_fetcher_dependent(metadata_resolver) 

1715 

1716 finder = _FindAllVisitor(matcher, fetcher) 

1717 tree.visit(finder) 

1718 return finder.found_nodes, finder.extracted_nodes 

1719 

1720 

1721def findall( 

1722 tree: Union[MaybeSentinel, RemovalSentinel, libcst.CSTNode, meta.MetadataWrapper], 

1723 matcher: Union[BaseMatcherNode, MatchIfTrue[libcst.CSTNode], _BaseMetadataMatcher], 

1724 *, 

1725 metadata_resolver: Optional[ 

1726 Union[libcst.MetadataDependent, libcst.MetadataWrapper] 

1727 ] = None, 

1728) -> Sequence[libcst.CSTNode]: 

1729 """ 

1730 Given an arbitrary node from a LibCST tree and an arbitrary matcher, iterates 

1731 over that node and all children returning a sequence of all child nodes that 

1732 match the given matcher. Note that the tree can also be a 

1733 :class:`~libcst.RemovalSentinel` or a :class:`~libcst.MaybeSentinel` 

1734 in order to use findall directly on transform results and node attributes. In these 

1735 cases, :func:`findall` will always return an empty sequence. Note also that 

1736 instead of a LibCST tree, you can instead pass in a 

1737 :class:`~libcst.metadata.MetadataWrapper`. This mirrors the fact that you can 

1738 call ``visit`` on a :class:`~libcst.metadata.MetadataWrapper` in order to iterate 

1739 over it with a transform. If you provide a wrapper for the tree and do not set 

1740 the ``metadata_resolver`` parameter specifically, it will automatically be set 

1741 to the wrapper for you. 

1742 

1743 The matcher can be any concrete matcher that subclasses from :class:`BaseMatcherNode`, 

1744 or a :class:`OneOf`/:class:`AllOf` special matcher. Unlike :func:`matches`, it can 

1745 also be a :class:`MatchIfTrue` or :func:`DoesNotMatch` matcher, since we are 

1746 traversing the tree looking for matches. It cannot be a :class:`AtLeastN` or 

1747 :class:`AtMostN` matcher because these types are wildcards which can only be used 

1748 inside sequences. 

1749 """ 

1750 nodes, _ = _find_or_extract_all(tree, matcher, metadata_resolver=metadata_resolver) 

1751 return nodes 

1752 

1753 

1754def extractall( 

1755 tree: Union[MaybeSentinel, RemovalSentinel, libcst.CSTNode, meta.MetadataWrapper], 

1756 matcher: Union[BaseMatcherNode, MatchIfTrue[libcst.CSTNode], _BaseMetadataMatcher], 

1757 *, 

1758 metadata_resolver: Optional[ 

1759 Union[libcst.MetadataDependent, libcst.MetadataWrapper] 

1760 ] = None, 

1761) -> Sequence[Dict[str, Union[libcst.CSTNode, Sequence[libcst.CSTNode]]]]: 

1762 """ 

1763 Given an arbitrary node from a LibCST tree and an arbitrary matcher, iterates 

1764 over that node and all children returning a sequence of dictionaries representing 

1765 the saved and extracted children specified by :func:`SaveMatchedNode` for each 

1766 match found in the tree. This is analogous to running a :func:`findall` over a 

1767 tree, then running :func:`extract` with the same matcher over each of the returned 

1768 nodes. Note that the tree can also be a :class:`~libcst.RemovalSentinel` or a 

1769 :class:`~libcst.MaybeSentinel` in order to use extractall directly on transform 

1770 results and node attributes. In these cases, :func:`extractall` will always 

1771 return an empty sequence. Note also that instead of a LibCST tree, you can 

1772 instead pass in a :class:`~libcst.metadata.MetadataWrapper`. This mirrors the 

1773 fact that you can call ``visit`` on a :class:`~libcst.metadata.MetadataWrapper` 

1774 in order to iterate over it with a transform. If you provide a wrapper for the 

1775 tree and do not set the ``metadata_resolver`` parameter specifically, it will 

1776 automatically be set to the wrapper for you. 

1777 

1778 The matcher can be any concrete matcher that subclasses from :class:`BaseMatcherNode`, 

1779 or a :class:`OneOf`/:class:`AllOf` special matcher. Unlike :func:`matches`, it can 

1780 also be a :class:`MatchIfTrue` or :func:`DoesNotMatch` matcher, since we are 

1781 traversing the tree looking for matches. It cannot be a :class:`AtLeastN` or 

1782 :class:`AtMostN` matcher because these types are wildcards which can only be usedi 

1783 inside sequences. 

1784 """ 

1785 _, extractions = _find_or_extract_all( 

1786 tree, matcher, metadata_resolver=metadata_resolver 

1787 ) 

1788 return extractions 

1789 

1790 

1791class _ReplaceTransformer(libcst.CSTTransformer): 

1792 def __init__( 

1793 self, 

1794 matcher: Union[ 

1795 BaseMatcherNode, 

1796 MatchIfTrue[libcst.CSTNode], 

1797 _BaseMetadataMatcher, 

1798 _InverseOf[ 

1799 Union[ 

1800 BaseMatcherNode, 

1801 MatchIfTrue[libcst.CSTNode], 

1802 _BaseMetadataMatcher, 

1803 ] 

1804 ], 

1805 ], 

1806 metadata_lookup: Callable[[meta.ProviderT, libcst.CSTNode], object], 

1807 replacement: Union[ 

1808 MaybeSentinel, 

1809 RemovalSentinel, 

1810 libcst.CSTNode, 

1811 Callable[ 

1812 [ 

1813 libcst.CSTNode, 

1814 Dict[str, Union[libcst.CSTNode, Sequence[libcst.CSTNode]]], 

1815 ], 

1816 Union[MaybeSentinel, RemovalSentinel, libcst.CSTNode], 

1817 ], 

1818 ], 

1819 ) -> None: 

1820 self.matcher = matcher 

1821 self.metadata_lookup = metadata_lookup 

1822 self.replacement: Callable[ 

1823 [ 

1824 libcst.CSTNode, 

1825 Dict[str, Union[libcst.CSTNode, Sequence[libcst.CSTNode]]], 

1826 ], 

1827 Union[MaybeSentinel, RemovalSentinel, libcst.CSTNode], 

1828 ] 

1829 

1830 if inspect.isfunction(replacement): 

1831 self.replacement = replacement 

1832 elif isinstance(replacement, (MaybeSentinel, RemovalSentinel)): 

1833 self.replacement = lambda node, matches: replacement 

1834 else: 

1835 # pyre-ignore We know this is a CSTNode. 

1836 self.replacement = lambda node, matches: replacement.deep_clone() 

1837 # We run into a really weird problem here, where we need to run the match 

1838 # and extract step on the original node in order for metadata to work. 

1839 # However, if we do that, then using things like `deep_replace` will fail 

1840 # since any extracted nodes are the originals, not the updates and LibCST 

1841 # does replacement by identity for safety reasons. If we try to run the 

1842 # match and extract step on the updated node (or twice, once for the match 

1843 # and once for the extract), it will fail to extract if any metadata-based 

1844 # matchers are used. So, we try to compromise with the best of both worlds. 

1845 # We track all node updates, and when we send the extracted nodes to the 

1846 # replacement callable, we look up the original nodes and replace them with 

1847 # updated nodes. In the case that an update made the node no-longer exist, 

1848 # we act as if there was not a match (because in reality, there would not 

1849 # have been if we had run the matcher on the update). 

1850 self.node_lut: Dict[libcst.CSTNode, libcst.CSTNode] = {} 

1851 

1852 def _node_translate( 

1853 self, node_or_sequence: Union[libcst.CSTNode, Sequence[libcst.CSTNode]] 

1854 ) -> Union[libcst.CSTNode, Sequence[libcst.CSTNode]]: 

1855 if isinstance(node_or_sequence, Sequence): 

1856 return tuple(self.node_lut[node] for node in node_or_sequence) 

1857 else: 

1858 return self.node_lut[node_or_sequence] 

1859 

1860 def _extraction_translate( 

1861 self, extracted: Dict[str, Union[libcst.CSTNode, Sequence[libcst.CSTNode]]] 

1862 ) -> Dict[str, Union[libcst.CSTNode, Sequence[libcst.CSTNode]]]: 

1863 return {key: self._node_translate(val) for key, val in extracted.items()} 

1864 

1865 def on_leave( 

1866 self, original_node: libcst.CSTNode, updated_node: libcst.CSTNode 

1867 ) -> Union[libcst.CSTNode, MaybeSentinel, RemovalSentinel]: 

1868 # Track original to updated node mapping for this node. 

1869 self.node_lut[original_node] = updated_node 

1870 

1871 # This gets complicated. We need to do the match on the original node, 

1872 # but we want to do the extraction on the updated node. This is so 

1873 # metadata works properly in matchers. So, if we get a match, we fix 

1874 # up the nodes in the match and return that to the replacement lambda. 

1875 extracted = _matches(original_node, self.matcher, self.metadata_lookup) 

1876 if extracted is not None: 

1877 try: 

1878 # Attempt to do a translation from original to updated node. 

1879 extracted = self._extraction_translate(extracted) 

1880 except KeyError: 

1881 # One of the nodes we looked up doesn't exist anymore, this 

1882 # is no longer a match. This can happen if a child node was 

1883 # modified, making this original match not applicable anymore. 

1884 extracted = None 

1885 if extracted is not None: 

1886 # We're replacing this node entirely, so don't save the original 

1887 # updated node. We don't want this to be part of a parent match 

1888 # since we can't guarantee that the update matches anymore. 

1889 del self.node_lut[original_node] 

1890 return self.replacement(updated_node, extracted) 

1891 return updated_node 

1892 

1893 

1894def replace( 

1895 tree: Union[MaybeSentinel, RemovalSentinel, libcst.CSTNode, meta.MetadataWrapper], 

1896 matcher: Union[BaseMatcherNode, MatchIfTrue[libcst.CSTNode], _BaseMetadataMatcher], 

1897 replacement: Union[ 

1898 MaybeSentinel, 

1899 RemovalSentinel, 

1900 libcst.CSTNode, 

1901 Callable[ 

1902 [ 

1903 libcst.CSTNode, 

1904 Dict[str, Union[libcst.CSTNode, Sequence[libcst.CSTNode]]], 

1905 ], 

1906 Union[MaybeSentinel, RemovalSentinel, libcst.CSTNode], 

1907 ], 

1908 ], 

1909 *, 

1910 metadata_resolver: Optional[ 

1911 Union[libcst.MetadataDependent, libcst.MetadataWrapper] 

1912 ] = None, 

1913) -> Union[MaybeSentinel, RemovalSentinel, libcst.CSTNode]: 

1914 """ 

1915 Given an arbitrary node from a LibCST tree and an arbitrary matcher, iterates 

1916 over that node and all children and replaces each node that matches the supplied 

1917 matcher with a supplied replacement. Note that the replacement can either be a 

1918 valid node type, or a callable which takes the matched node and a dictionary of 

1919 any extracted child values and returns a valid node type. If you provide a 

1920 valid LibCST node type, :func:`replace` will replace every node that matches 

1921 the supplied matcher with the replacement node. If you provide a callable, 

1922 :func:`replace` will run :func:`extract` over all matched nodes and call the 

1923 callable with both the node that should be replaced and the dictionary returned 

1924 by :func:`extract`. Under all circumstances a new tree is returned. 

1925 :func:`extract` should be viewed as a short-cut to writing a transform which 

1926 also returns a new tree even when no changes are applied. 

1927 

1928 Note that the tree can also be a :class:`~libcst.RemovalSentinel` or a 

1929 :class:`~libcst.MaybeSentinel` in order to use replace directly on transform 

1930 results and node attributes. In these cases, :func:`replace` will return the 

1931 same :class:`~libcst.RemovalSentinel` or :class:`~libcst.MaybeSentinel`. 

1932 Note also that instead of a LibCST tree, you can instead pass in a 

1933 :class:`~libcst.metadata.MetadataWrapper`. This mirrors the fact that you can 

1934 call ``visit`` on a :class:`~libcst.metadata.MetadataWrapper` in order to 

1935 iterate over it with a transform. If you provide a wrapper for the tree and 

1936 do not set the ``metadata_resolver`` parameter specifically, it will 

1937 automatically be set to the wrapper for you. 

1938 

1939 The matcher can be any concrete matcher that subclasses from :class:`BaseMatcherNode`, 

1940 or a :class:`OneOf`/:class:`AllOf` special matcher. Unlike :func:`matches`, it can 

1941 also be a :class:`MatchIfTrue` or :func:`DoesNotMatch` matcher, since we are 

1942 traversing the tree looking for matches. It cannot be a :class:`AtLeastN` or 

1943 :class:`AtMostN` matcher because these types are wildcards which can only be usedi 

1944 inside sequences. 

1945 """ 

1946 if isinstance(tree, (RemovalSentinel, MaybeSentinel)): 

1947 # We can't do any replacements on this, so return the tree exactly. 

1948 return tree 

1949 if isinstance(matcher, (AtLeastN, AtMostN)): 

1950 # We can't match this, since these matchers are forbidden at top level. 

1951 # These are not subclasses of BaseMatcherNode, but in the case that the 

1952 # user is not using type checking, this should still behave correctly. 

1953 if isinstance(tree, libcst.CSTNode): 

1954 return tree.deep_clone() 

1955 elif isinstance(tree, meta.MetadataWrapper): 

1956 return tree.module.deep_clone() 

1957 else: 

1958 raise Exception("Logic error!") 

1959 

1960 if isinstance(tree, meta.MetadataWrapper) and metadata_resolver is None: 

1961 # Provide a convenience for calling replace directly on a MetadataWrapper. 

1962 metadata_resolver = tree 

1963 

1964 if metadata_resolver is None: 

1965 fetcher = _construct_metadata_fetcher_null() 

1966 elif isinstance(metadata_resolver, libcst.MetadataWrapper): 

1967 fetcher = _construct_metadata_fetcher_wrapper(metadata_resolver) 

1968 else: 

1969 fetcher = _construct_metadata_fetcher_dependent(metadata_resolver) 

1970 

1971 replacer = _ReplaceTransformer(matcher, fetcher, replacement) 

1972 new_tree = tree.visit(replacer) 

1973 if isinstance(new_tree, FlattenSentinel): 

1974 # The above transform never returns FlattenSentinel, so this isn't possible 

1975 raise Exception("Logic error, cannot get a FlattenSentinel here!") 

1976 return new_tree