[clang-tools-extra] [clang-tidy] Filter out googletest TUs in bugprone-unchecked-optional-access (PR #115051)

Jan Voung via cfe-commits cfe-commits at lists.llvm.org
Fri Jan 24 08:14:30 PST 2025


jvoung wrote:

> It would be better to use `GtestCmp` if you really want clang-tidy support gtest in this check. Here is an unfinished example which can match
> 
> ```
> TEST(a, b) {
>   std::optional<int> a;
>   if (v) {
>     a = 1;
>   }
>   ASSERT_NE(a, std::nullopt);
>   a.value();
> }
> ```
> 
> ```c++
>   using namespace ast_matchers;
>   auto HasOptionalCallDescendant = hasDescendant(callExpr(callee(cxxMethodDecl(
>       ofClass(UncheckedOptionalAccessModel::optionalClassDecl())))));
>   Finder->addMatcher(
>       decl(anyOf(functionDecl(
>                      unless(isExpansionInSystemHeader()),
>                      // FIXME: Remove the filter below when lambdas are
>                      // well supported by the check.
>                      unless(hasDeclContext(cxxRecordDecl(isLambda()))),
>                      hasBody(allOf(
>                          HasOptionalCallDescendant,
>                          unless(hasDescendant(gtestAssert(
>                              GtestCmp::Ne,
>                              expr(hasType(qualType(hasUnqualifiedDesugaredType(
>                                  recordType(hasDeclaration(
>                                      UncheckedOptionalAccessModel::
>                                          optionalClassDecl())))))),
>                              anything())))))),
>                  cxxConstructorDecl(hasAnyConstructorInitializer(
>                      withInitializer(HasOptionalCallDescendant)))))
>           .bind(FuncID),
>       this);
> ```

Sorry I missed this comment earlier!

I think doing "unless( ... gtestAssert... GtestCmp...)" for filtering this way would be more complex for not much gain, over the current filtering. Is the concern accuracy?

regarding complexity: there are many forms to check if the optional has a value, so doing filters this way (with "unless") we would need to enumerate all of them (gtestExpect, gtestExpectThat, gtestAssertThat, a to-be-added gtestExpectTrue, gtestAssertTrue, might need GtestCmp::Eq as well as Ne, like ASSERT_EQ(a.has_value(), true)). Similarly if we want to  filter out catch2.

At that point we may as well handle the matcher + transfer functions to "see through" the macros in the checker itself rather than filtering here in a simple way (but then see prioritization concern).

regarding accuracy: I've run a large scale experiment across our monorepo, and the current method seems accurate w.r.t. filtering test files, test utilities, test base classes, fakes, mock classes, etc. Only 0.4% of the diffs didn't have "test/Test/TEST/..." etc in the path for file name (as a rough check). Among that 0.4% some really were test-only libraries that were less obviously test-only from the file name (golden_generator, sampler, fake, mock, benchmark, etc.), and some were timeout diffs.


https://github.com/llvm/llvm-project/pull/115051


More information about the cfe-commits mailing list