Skip to content

Commit a80ab59

Browse files
author
Carlos Gálvez
committed
[clang][AST][clang-tidy] Do not set a reduced traversal scope in ASTMatchFinder
This was introduced here with the purpose of speed up clang-tidy, making it not process system headers: e4a8969 However it was later realized that this change is too aggressive: the reduced traversal scope also impacts the ParentMapContext, which in turn means that matchers like "hasParent" or "hasAncestor" are not able to find parents in system headers, even if the declaration at hand is in a user header. This causes regressions for downstream users writing custom clang-tidy checks: #128150 (comment) This patch fixes this problem, as follows: - Revert the changes to the clang-tidy unit tests. - Revert setting the TraversalScope in MatchASTConsumer. - Move the logic to MatchASTVisitor::TraverseDecl instead. Pros: - Leaves the ASTContext and ParentMapContext untouched, so hasParent and similar matchers should work again. - Keeps avoiding matching and checking decls outside of system headers. - The broken unit test in readability now works, because we are no longer processing only TopLevelDecls. - The changes to the CERT test can be reverted. - Most likely we don't lose any functionality or introduce false negatives. Cons: - We still have to traverse decls in system headers. I did try to return false; instead of return true; in the proposed code but that made around 60 clang-tidy tests to fail. - We still process many nodes (not Decls) that are in system headers. As a benchmark, I tried running all clang-tidy checks on a .cpp file that includes all the standard C++ headers. This leads to: * Baseline (without any optimizations). Suppressed 196093 warnings (196093 in non-user code) 10 seconds to run. * Trunk (aggressive optimizations). Suppressed 8050 warnings (8050 in non-user code). 1 second to run. * This patch (conservative optimizations). Suppressed 141779 warnings (141779 in non-user code). 3 seconds to run. This patch thus gives some performance improvement while keeping backwards compatibility. There's still room for improvement which shall be tackled in a follow-up patch after unbreaking clang-tidy. Fixes #130618
1 parent 8a8e4cf commit a80ab59

File tree

5 files changed

+28
-73
lines changed

5 files changed

+28
-73
lines changed

clang-tools-extra/clang-tidy/cert/DontModifyStdNamespaceCheck.cpp

Lines changed: 5 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -35,41 +35,19 @@ AST_POLYMORPHIC_MATCHER_P(
3535
Builder) != Args.end();
3636
}
3737

38-
bool isStdOrPosixImpl(const DeclContext *Ctx) {
39-
if (!Ctx->isNamespace())
40-
return false;
41-
42-
const auto *ND = cast<NamespaceDecl>(Ctx);
43-
if (ND->isInline()) {
44-
return isStdOrPosixImpl(ND->getParent());
45-
}
46-
47-
if (!ND->getParent()->getRedeclContext()->isTranslationUnit())
48-
return false;
49-
50-
const IdentifierInfo *II = ND->getIdentifier();
51-
return II && (II->isStr("std") || II->isStr("posix"));
52-
}
53-
54-
AST_MATCHER(Decl, isInStdOrPosixNS) {
55-
for (const auto *Ctx = Node.getDeclContext(); Ctx; Ctx = Ctx->getParent()) {
56-
if (isStdOrPosixImpl(Ctx))
57-
return true;
58-
}
59-
return false;
60-
}
61-
6238
} // namespace
6339

6440
namespace clang::tidy::cert {
6541

6642
void DontModifyStdNamespaceCheck::registerMatchers(MatchFinder *Finder) {
6743
auto HasStdParent =
6844
hasDeclContext(namespaceDecl(hasAnyName("std", "posix"),
69-
unless(hasDeclContext(namespaceDecl())))
45+
unless(hasParent(namespaceDecl())))
7046
.bind("nmspc"));
71-
auto UserDefinedType = qualType(hasUnqualifiedDesugaredType(
72-
tagType(unless(hasDeclaration(tagDecl(isInStdOrPosixNS()))))));
47+
auto UserDefinedType = qualType(
48+
hasUnqualifiedDesugaredType(tagType(unless(hasDeclaration(tagDecl(
49+
hasAncestor(namespaceDecl(hasAnyName("std", "posix"),
50+
unless(hasParent(namespaceDecl()))))))))));
7351
auto HasNoProgramDefinedTemplateArgument = unless(
7452
hasAnyTemplateArgumentIncludingPack(refersToType(UserDefinedType)));
7553
auto InsideStdClassOrClassTemplateSpecialization = hasDeclContext(

clang-tools-extra/docs/ReleaseNotes.rst

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -94,8 +94,6 @@ Improvements to clang-tidy
9494
- :program:`clang-tidy` no longer processes declarations from system headers
9595
by default, greatly improving performance. This behavior is disabled if the
9696
`SystemHeaders` option is enabled.
97-
Note: this may lead to false negatives; downstream users may need to adjust
98-
their checks to preserve existing behavior.
9997

10098
- Improved :program:`clang-tidy-diff.py` script. Add the `-warnings-as-errors`
10199
argument to treat warnings as errors.

clang-tools-extra/test/clang-tidy/checkers/readability/identifier-naming-anon-record-fields.cpp

Lines changed: 8 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -33,29 +33,23 @@
3333
// RUN: readability-identifier-naming.LocalConstantPointerPrefix: 'lc_', \
3434
// RUN: }}'
3535

36-
// FIXME: make this test case pass.
37-
// Currently not working because the CXXRecordDecl for the global anonymous
38-
// union is *not* collected as a top-level declaration.
39-
// https://github.com/llvm/llvm-project/issues/130618
40-
#if 0
4136
static union {
4237
int global;
43-
// FIXME-CHECK-MESSAGES: :[[@LINE-1]]:7: warning: invalid case style for global variable 'global'
44-
// FIXME-CHECK-FIXES: {{^}} int g_global;{{$}}
38+
// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: invalid case style for global variable 'global'
39+
// CHECK-FIXES: {{^}} int g_global;{{$}}
4540

4641
const int global_const;
47-
// FIXME-CHECK-MESSAGES: :[[@LINE-1]]:13: warning: invalid case style for global constant 'global_const'
48-
// FIXME-CHECK-FIXES: {{^}} const int GLOBAL_CONST;{{$}}
42+
// CHECK-MESSAGES: :[[@LINE-1]]:13: warning: invalid case style for global constant 'global_const'
43+
// CHECK-FIXES: {{^}} const int GLOBAL_CONST;{{$}}
4944

5045
int *global_ptr;
51-
// FIXME-CHECK-MESSAGES: :[[@LINE-1]]:8: warning: invalid case style for global pointer 'global_ptr'
52-
// FIXME-CHECK-FIXES: {{^}} int *GlobalPtr_Ptr;{{$}}
46+
// CHECK-MESSAGES: :[[@LINE-1]]:8: warning: invalid case style for global pointer 'global_ptr'
47+
// CHECK-FIXES: {{^}} int *GlobalPtr_Ptr;{{$}}
5348

5449
int *const global_const_ptr;
55-
// FIXME-CHECK-MESSAGES: :[[@LINE-1]]:14: warning: invalid case style for global constant pointer 'global_const_ptr'
56-
// FIXME-CHECK-FIXES: {{^}} int *const GLOBAL_CONST_PTR_Ptr;{{$}}
50+
// CHECK-MESSAGES: :[[@LINE-1]]:14: warning: invalid case style for global constant pointer 'global_const_ptr'
51+
// CHECK-FIXES: {{^}} int *const GLOBAL_CONST_PTR_Ptr;{{$}}
5752
};
58-
#endif
5953

6054
namespace ns {
6155

clang/docs/ReleaseNotes.rst

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -460,9 +460,8 @@ AST Matchers
460460
specialization.
461461
- Move ``ast_matchers::MatchFinder::MatchFinderOptions`` to
462462
``ast_matchers::MatchFinderOptions``.
463-
- Add a boolean member ``SkipSystemHeaders`` to ``MatchFinderOptions``, and make
464-
``MatchASTConsumer`` receive a reference to ``MatchFinderOptions`` in the
465-
constructor. This allows it to skip system headers when traversing the AST.
463+
- Add a boolean member ``SkipSystemHeaders`` to ``MatchFinderOptions``. This
464+
allows it to avoid matching declarations in system headers .
466465

467466
clang-format
468467
------------

clang/lib/ASTMatchers/ASTMatchFinder.cpp

Lines changed: 13 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,6 @@
2828
#include <deque>
2929
#include <memory>
3030
#include <set>
31-
#include <vector>
3231

3332
namespace clang {
3433
namespace ast_matchers {
@@ -1464,11 +1463,21 @@ bool MatchASTVisitor::objcClassIsDerivedFrom(
14641463
return false;
14651464
}
14661465

1466+
static bool isInSystemHeader(Decl *D) {
1467+
const SourceManager &SM = D->getASTContext().getSourceManager();
1468+
const SourceLocation Loc = SM.getExpansionLoc(D->getBeginLoc());
1469+
return SM.isInSystemHeader(Loc);
1470+
}
1471+
14671472
bool MatchASTVisitor::TraverseDecl(Decl *DeclNode) {
14681473
if (!DeclNode) {
14691474
return true;
14701475
}
14711476

1477+
// Skip declarations in system headers if requested
1478+
if (Options.SkipSystemHeaders && isInSystemHeader(DeclNode))
1479+
return true;
1480+
14721481
bool ScopedTraversal =
14731482
TraversingASTNodeNotSpelledInSource || DeclNode->isImplicit();
14741483
bool ScopedChildren = TraversingASTChildrenNotSpelledInSource;
@@ -1574,41 +1583,19 @@ bool MatchASTVisitor::TraverseAttr(Attr *AttrNode) {
15741583
class MatchASTConsumer : public ASTConsumer {
15751584
public:
15761585
MatchASTConsumer(MatchFinder *Finder,
1577-
MatchFinder::ParsingDoneTestCallback *ParsingDone,
1578-
const MatchFinderOptions &Options)
1579-
: Finder(Finder), ParsingDone(ParsingDone), Options(Options) {}
1586+
MatchFinder::ParsingDoneTestCallback *ParsingDone)
1587+
: Finder(Finder), ParsingDone(ParsingDone) {}
15801588

15811589
private:
1582-
bool HandleTopLevelDecl(DeclGroupRef DG) override {
1583-
if (Options.SkipSystemHeaders) {
1584-
for (Decl *D : DG) {
1585-
if (!isInSystemHeader(D))
1586-
TraversalScope.push_back(D);
1587-
}
1588-
}
1589-
return true;
1590-
}
1591-
15921590
void HandleTranslationUnit(ASTContext &Context) override {
1593-
if (!TraversalScope.empty())
1594-
Context.setTraversalScope(TraversalScope);
1595-
15961591
if (ParsingDone != nullptr) {
15971592
ParsingDone->run();
15981593
}
15991594
Finder->matchAST(Context);
16001595
}
16011596

1602-
bool isInSystemHeader(Decl *D) {
1603-
const SourceManager &SM = D->getASTContext().getSourceManager();
1604-
const SourceLocation Loc = SM.getExpansionLoc(D->getBeginLoc());
1605-
return SM.isInSystemHeader(Loc);
1606-
}
1607-
16081597
MatchFinder *Finder;
16091598
MatchFinder::ParsingDoneTestCallback *ParsingDone;
1610-
const MatchFinderOptions &Options;
1611-
std::vector<Decl *> TraversalScope;
16121599
};
16131600

16141601
} // end namespace
@@ -1727,8 +1714,7 @@ bool MatchFinder::addDynamicMatcher(const internal::DynTypedMatcher &NodeMatch,
17271714
}
17281715

17291716
std::unique_ptr<ASTConsumer> MatchFinder::newASTConsumer() {
1730-
return std::make_unique<internal::MatchASTConsumer>(this, ParsingDone,
1731-
Options);
1717+
return std::make_unique<internal::MatchASTConsumer>(this, ParsingDone);
17321718
}
17331719

17341720
void MatchFinder::match(const clang::DynTypedNode &Node, ASTContext &Context) {

0 commit comments

Comments
 (0)