14
14
#include " clang/ASTMatchers/ASTMatchers.h"
15
15
#include " clang/ASTMatchers/ASTMatchersInternal.h"
16
16
#include " llvm/ADT/SmallString.h"
17
+ #include " llvm/ADT/SmallVector.h"
17
18
#include " llvm/Support/ManagedStatic.h"
18
19
19
20
namespace clang {
@@ -293,15 +294,26 @@ bool AnyOfVariadicOperator(const ast_type_traits::DynTypedNode &DynNode,
293
294
return false ;
294
295
}
295
296
296
- HasNameMatcher::HasNameMatcher (std::string NameRef)
297
- : UseUnqualifiedMatch(NameRef.find(" ::" ) == NameRef.npos),
298
- Name (std::move(NameRef)) {
299
- assert (!Name.empty ());
297
+ Matcher<NamedDecl> hasAnyNameFunc (ArrayRef<const StringRef *> NameRefs) {
298
+ std::vector<std::string> Names;
299
+ for (auto *Name : NameRefs)
300
+ Names.emplace_back (*Name);
301
+ return internal::Matcher<NamedDecl>(
302
+ new internal::HasNameMatcher (std::move (Names)));
303
+ }
304
+
305
+ HasNameMatcher::HasNameMatcher (std::vector<std::string> N)
306
+ : UseUnqualifiedMatch(std::all_of(
307
+ N.begin(), N.end(),
308
+ [](StringRef Name) { return Name.find (" ::" ) == Name.npos ; })),
309
+ Names (std::move(N)) {
310
+ for (StringRef Name : Names)
311
+ assert (!Name.empty ());
300
312
}
301
313
302
314
namespace {
303
315
304
- bool ConsumeNameSuffix (StringRef &FullName, StringRef Suffix) {
316
+ bool consumeNameSuffix (StringRef &FullName, StringRef Suffix) {
305
317
StringRef Name = FullName;
306
318
if (!Name.endswith (Suffix))
307
319
return false ;
@@ -315,79 +327,127 @@ bool ConsumeNameSuffix(StringRef &FullName, StringRef Suffix) {
315
327
return true ;
316
328
}
317
329
318
- bool ConsumeNodeName ( StringRef &Name, const NamedDecl &Node) {
330
+ StringRef getNodeName ( const NamedDecl &Node, llvm::SmallString< 128 > &Scratch ) {
319
331
// Simple name.
320
332
if (Node.getIdentifier ())
321
- return ConsumeNameSuffix (Name, Node.getName () );
333
+ return Node.getName ();
322
334
323
335
if (Node.getDeclName ()) {
324
336
// Name needs to be constructed.
325
- llvm::SmallString< 128 > NodeName ;
326
- llvm::raw_svector_ostream OS (NodeName );
337
+ Scratch. clear () ;
338
+ llvm::raw_svector_ostream OS (Scratch );
327
339
Node.printName (OS);
328
- return ConsumeNameSuffix (Name, OS.str () );
340
+ return OS.str ();
329
341
}
330
342
331
- return ConsumeNameSuffix (Name, " (anonymous)" ) ;
343
+ return " (anonymous)" ;
332
344
}
333
345
346
+ StringRef getNodeName (const RecordDecl &Node, llvm::SmallString<128 > &Scratch) {
347
+ if (Node.getIdentifier ()) {
348
+ return Node.getName ();
349
+ }
350
+ Scratch.clear ();
351
+ return (" (anonymous " + Node.getKindName () + " )" ).toStringRef (Scratch);
352
+ }
353
+
354
+ StringRef getNodeName (const NamespaceDecl &Node,
355
+ llvm::SmallString<128 > &Scratch) {
356
+ return Node.isAnonymousNamespace () ? " (anonymous namespace)" : Node.getName ();
357
+ }
358
+
359
+
360
+ class PatternSet {
361
+ public:
362
+ PatternSet (ArrayRef<std::string> Names) {
363
+ for (StringRef Name : Names)
364
+ Patterns.push_back ({Name, Name.startswith (" ::" )});
365
+ }
366
+
367
+ // / Consumes the name suffix from each pattern in the set and removes the ones
368
+ // / that didn't match.
369
+ // / Return true if there are still any patterns left.
370
+ bool consumeNameSuffix (StringRef NodeName, bool CanSkip) {
371
+ for (size_t I = 0 ; I < Patterns.size ();) {
372
+ if (internal::consumeNameSuffix (Patterns[I].Pattern , NodeName) ||
373
+ CanSkip) {
374
+ ++I;
375
+ } else {
376
+ Patterns.erase (Patterns.begin () + I);
377
+ }
378
+ }
379
+ return !Patterns.empty ();
380
+ }
381
+
382
+ // / Check if any of the patterns are a match.
383
+ // / A match will be a pattern that was fully consumed, that also matches the
384
+ // / 'fully qualified' requirement.
385
+ bool foundMatch (bool AllowFullyQualified) const {
386
+ for (auto & P: Patterns)
387
+ if (P.Pattern .empty () && (AllowFullyQualified || !P.IsFullyQualified ))
388
+ return true ;
389
+ return false ;
390
+ }
391
+
392
+ private:
393
+ struct Pattern {
394
+ StringRef Pattern;
395
+ bool IsFullyQualified;
396
+ };
397
+ llvm::SmallVector<Pattern, 8 > Patterns;
398
+ };
399
+
334
400
} // namespace
335
401
336
402
bool HasNameMatcher::matchesNodeUnqualified (const NamedDecl &Node) const {
337
403
assert (UseUnqualifiedMatch);
338
- StringRef NodeName = Name;
339
- return ConsumeNodeName (NodeName, Node) && NodeName.empty ();
404
+ llvm::SmallString<128 > Scratch;
405
+ StringRef NodeName = getNodeName (Node, Scratch);
406
+ return std::any_of (Names.begin (), Names.end (), [&](StringRef Name) {
407
+ return consumeNameSuffix (Name, NodeName) && Name.empty ();
408
+ });
340
409
}
341
410
342
411
bool HasNameMatcher::matchesNodeFullFast (const NamedDecl &Node) const {
412
+ PatternSet Patterns (Names);
413
+ llvm::SmallString<128 > Scratch;
414
+
343
415
// This function is copied and adapted from NamedDecl::printQualifiedName()
344
416
// By matching each part individually we optimize in a couple of ways:
345
417
// - We can exit early on the first failure.
346
418
// - We can skip inline/anonymous namespaces without another pass.
347
419
// - We print one name at a time, reducing the chance of overflowing the
348
420
// inlined space of the SmallString.
349
- StringRef Pattern = Name;
350
- const bool IsFullyQualified = Pattern.startswith (" ::" );
351
421
352
422
// First, match the name.
353
- if (!ConsumeNodeName (Pattern, Node))
423
+ if (!Patterns.consumeNameSuffix (getNodeName (Node, Scratch),
424
+ /* CanSkip=*/ false ))
354
425
return false ;
355
426
356
427
// Try to match each declaration context.
357
428
// We are allowed to skip anonymous and inline namespaces if they don't match.
358
429
const DeclContext *Ctx = Node.getDeclContext ();
359
430
360
431
if (Ctx->isFunctionOrMethod ())
361
- return Pattern. empty () && !IsFullyQualified ;
432
+ return Patterns. foundMatch ( /* AllowFullyQualified= */ false ) ;
362
433
363
- for (; !Pattern.empty () && Ctx && isa<NamedDecl>(Ctx);
364
- Ctx = Ctx->getParent ()) {
365
- if (const auto *ND = dyn_cast<NamespaceDecl>(Ctx)) {
366
- StringRef NSName =
367
- ND->isAnonymousNamespace () ? " (anonymous namespace)" : ND->getName ();
434
+ for (; Ctx && isa<NamedDecl>(Ctx); Ctx = Ctx->getParent ()) {
435
+ if (Patterns.foundMatch (/* AllowFullyQualified=*/ false ))
436
+ return true ;
368
437
369
- // If it matches, continue.
370
- if ( ConsumeNameSuffix (Pattern, NSName))
371
- continue ;
372
- // If it didn't match but we can skip it, continue.
373
- if (ND-> isAnonymousNamespace () || ND->isInline ())
438
+ if ( const auto *ND = dyn_cast<NamespaceDecl>(Ctx)) {
439
+ // If it matches (or we can skip it), continue.
440
+ if (Patterns. consumeNameSuffix ( getNodeName (*ND, Scratch),
441
+ /* CanSkip= */ ND-> isAnonymousNamespace () ||
442
+ ND->isInline () ))
374
443
continue ;
375
-
376
444
return false ;
377
445
}
378
446
if (const auto *RD = dyn_cast<RecordDecl>(Ctx)) {
379
447
if (!isa<ClassTemplateSpecializationDecl>(Ctx)) {
380
- if (RD->getIdentifier ()) {
381
- if (ConsumeNameSuffix (Pattern, RD->getName ()))
382
- continue ;
383
- } else {
384
- llvm::SmallString<128 > NodeName;
385
- NodeName += StringRef (" (anonymous " );
386
- NodeName += RD->getKindName ();
387
- NodeName += ' )' ;
388
- if (ConsumeNameSuffix (Pattern, NodeName))
389
- continue ;
390
- }
448
+ if (Patterns.consumeNameSuffix (getNodeName (*RD, Scratch),
449
+ /* CanSkip=*/ false ))
450
+ continue ;
391
451
392
452
return false ;
393
453
}
@@ -398,16 +458,10 @@ bool HasNameMatcher::matchesNodeFullFast(const NamedDecl &Node) const {
398
458
return matchesNodeFullSlow (Node);
399
459
}
400
460
401
- // If we are fully qualified, we must not have any leftover context.
402
- if (IsFullyQualified && Ctx && isa<NamedDecl>(Ctx))
403
- return false ;
404
-
405
- return Pattern.empty ();
461
+ return Patterns.foundMatch (/* AllowFullyQualified=*/ true );
406
462
}
407
463
408
464
bool HasNameMatcher::matchesNodeFullSlow (const NamedDecl &Node) const {
409
- const StringRef Pattern = Name;
410
-
411
465
const bool SkipUnwrittenCases[] = {false , true };
412
466
for (bool SkipUnwritten : SkipUnwrittenCases) {
413
467
llvm::SmallString<128 > NodeName = StringRef (" ::" );
@@ -423,12 +477,14 @@ bool HasNameMatcher::matchesNodeFullSlow(const NamedDecl &Node) const {
423
477
424
478
const StringRef FullName = OS.str ();
425
479
426
- if (Pattern.startswith (" ::" )) {
427
- if (FullName == Pattern)
480
+ for (const StringRef Pattern : Names) {
481
+ if (Pattern.startswith (" ::" )) {
482
+ if (FullName == Pattern)
483
+ return true ;
484
+ } else if (FullName.endswith (Pattern) &&
485
+ FullName.drop_back (Pattern.size ()).endswith (" ::" )) {
428
486
return true ;
429
- } else if (FullName.endswith (Pattern) &&
430
- FullName.drop_back (Pattern.size ()).endswith (" ::" )) {
431
- return true ;
487
+ }
432
488
}
433
489
}
434
490
0 commit comments