The code assumed that taking the lexical parent decl context of a node
and traversing it will eventually visit the node itself. While this is
certeanly true for most AST constructs, template specializations (aka.
instantiations) might inject their AST to surprising lexical parents,
depending on when they get instantiated.
This means that just taking the lexical parent of a template
specialization might land us on some AST node that won't contain (thus
visit) the definition, and consequently, miss the Suppress attribute...
To fix this, we must take special care for template specializations. For
a regular instantiation select the primary template (that has the definition).
For an instantiation coming from a partial specialization, pretend if it
was the partial specialization instead.
Once we canonicalize to the primary template/partial specialization
definition, the usual "walk the lexical parents" logic covers the rest
as usual.
Assisted-by: claude
rdar://168941095
BugSuppression works by traversing the lexical decl context of the
decl-with-issue to record what source ranges should be suppressed by
some attribute.
Note that the decl-with-issue will be changed to the lexical decl
context of the original decl-with-issue, to make suppression attributes
work that were attached to the CXXRecordDecl containing the
CXXMethodDecl (bug report's DeclWithIssue).
It happens so that it uses a DynamicRecursiveASTVisitor, which has a
couple of traversal options. Namely:
- ShouldVisitTemplateInstantiations
- ShouldWalkTypesOfTypeLocs
- ShouldVisitImplicitCode
- ShouldVisitLambdaBody
By default, these have the correct values, except for
ShouldVisitTemplateInstantiations. We should traverse template
instantiations because that might be where the bug is reported - thus,
where we might have a [[clang::suppress]] that we should honor.
In this patch I'll explicitly set these traversal options to avoid
further confusion.
rdar://164646398
Specifically, add a scope for
- each work-list step,
- each entry point,
- each checker run within a step, and
- bug-suppression phase at the end of the analysis of an entry-point.
These scopes add no perceptible run-time overhead when time-tracing is
disabled. You can enable it and generate a time trace using the
`-ftime-trace=file.json` option.
See also the RFC:
https://discourse.llvm.org/t/analyzer-rfc-ftime-trace-time-scopes-for-steps-and-entry-points/84343
--
CPP-6065
The attribute is now allowed on an assortment of declarations, to
suppress warnings related to declarations themselves, or all warnings in
the lexical scope of the declaration.
I don't necessarily see a reason to have a list at all, but it does look
as if some of those more niche items aren't properly supported by the
compiler itself so let's maintain a short safe list for now.
The initial implementation raised a question whether the attribute
should apply to lexical declaration context vs. "actual" declaration
context. I'm using "lexical" here because it results in less warnings
suppressed, which is the conservative behavior: we can always expand it
later if we think this is wrong, without breaking any existing code. I
also think that this is the correct behavior that we will probably never
want to change, given that the user typically desires to keep the
suppressions as localized as possible.
There are currently a few checkers that don't fill in the bug report's
"decl-with-issue" field (typically a function in which the bug is
found).
The new attribute `[[clang::suppress]]` uses decl-with-issue to reduce
the size of the suppression source range map so that it didn't need to
do that for the entire translation unit.
I'm already seeing a few problems with this approach so I'll probably
redesign it in some point as it looks like a premature optimization. Not
only checkers shouldn't be required to pass decl-with-issue (consider
clang-tidy checkers that never had such notion), but also it's not
necessarily uniquely determined (consider leak suppressions at
allocation site).
For now I'm adding a simple stop-gap solution that falls back to
building the suppression map for the entire TU whenever decl-with-issue
isn't specified. Which won't happen in the default setup because luckily
all default checkers do provide decl-with-issue.
---------
Co-authored-by: Balazs Benics <benicsbalazs@gmail.com>
The new attribute can be placed on statements in order to suppress
arbitrary warnings produced by static analysis tools at those statements.
Previously such suppressions were implemented as either informal comments
(eg. clang-tidy `// NOLINT:`) or with preprocessor macros (eg.
clang static analyzer's `#ifdef __clang_analyzer__`). The attribute
provides a universal, formal, flexible and neat-looking suppression mechanism.
Implement support for the new attribute in the clang static analyzer;
clang-tidy coming soon.
The attribute allows specifying which specific warnings to suppress,
in the form of free-form strings that are intended to be specific to
the tools, but currently none are actually supported; so this is also
going to be a future improvement.
Differential Revision: https://reviews.llvm.org/D93110