Skip to content
Open
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -40,10 +40,27 @@ void UncheckedOptionalAccessCheck::registerMatchers(MatchFinder *Finder) {
this);
}

void UncheckedOptionalAccessCheck::onStartOfTranslationUnit() {
// Reset the flag for each TU.
is_test_tu_ = false;
}

void UncheckedOptionalAccessCheck::check(
const MatchFinder::MatchResult &Result) {
if (Result.SourceManager->getDiagnostics().hasUncompilableErrorOccurred())
// The googletest assertion macros are not currently recognized, so we have
// many false positives in tests. So, do not check functions in a test TU.
if (is_test_tu_ ||
Result.SourceManager->getDiagnostics().hasUncompilableErrorOccurred())
return;

// Look for two (public) googletest macros; if found, we'll mark this TU as a
// test TU. We look for ASSERT_TRUE because it is a problematic macro that
// we don't (yet) support, and GTEST_TEST to disambiguate ASSERT_TRUE.
if (Result.Context->Idents.get("ASSERT_TRUE").hasMacroDefinition() &&
Result.Context->Idents.get("GTEST_TEST").hasMacroDefinition()) {
is_test_tu_ = true;
return;
}

const auto *FuncDecl = Result.Nodes.getNodeAs<FunctionDecl>(FuncID);
if (FuncDecl->isTemplated())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@
#include "../ClangTidyCheck.h"
#include "clang/ASTMatchers/ASTMatchFinder.h"
#include "clang/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.h"
#include <optional>

namespace clang::tidy::bugprone {

Expand All @@ -30,6 +29,7 @@ class UncheckedOptionalAccessCheck : public ClangTidyCheck {
Options.getLocalOrGlobal("IgnoreSmartPointerDereference", false)} {}
void registerMatchers(ast_matchers::MatchFinder *Finder) override;
void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
void onStartOfTranslationUnit() override;
bool isLanguageVersionSupported(const LangOptions &LangOpts) const override {
return LangOpts.CPlusPlus;
}
Expand All @@ -40,6 +40,12 @@ class UncheckedOptionalAccessCheck : public ClangTidyCheck {

private:
dataflow::UncheckedOptionalAccessModelOptions ModelOptions;

// Records whether the current TU includes the googletest headers, in which
// case we assume it is a test TU of some sort. The googletest assertion
// macros are not currently recognized, so we have many false positives in
// tests. So, we disable checking for all test TUs.
bool is_test_tu_ = false;
};

} // namespace clang::tidy::bugprone
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
#ifndef LLVM_CLANG_TOOLS_EXTRA_TEST_CLANG_TIDY_CHECKERS_INPUTS_GTEST_GTEST_H_
#define LLVM_CLANG_TOOLS_EXTRA_TEST_CLANG_TIDY_CHECKERS_INPUTS_GTEST_GTEST_H_

// Mock version of googletest macros.

// Normally this declares a class, but it isn't relevant for testing.
#define GTEST_TEST(test_suite_name, test_name)

// Normally, this has a relatively complex implementation
// (wrapping the condition evaluation), more complex failure behavior, etc.,
// but we keep it simple for testing.
#define ASSERT_TRUE(condition) \
if (condition) \
; \
else \
return; // normally "fails" rather than just return

#endif // LLVM_CLANG_TOOLS_EXTRA_TEST_CLANG_TIDY_CHECKERS_INPUTS_GTEST_GTEST_H_
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please also add an ASSERT_FALSE (or just ASSERT_TRUE(!opt.has_value())) with a dereference after, to show that there are false-negatives

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done (there was a false-negative example in unchecked_value_access but also added the ASSERT_FALSE)

Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// RUN: %check_clang_tidy %s bugprone-unchecked-optional-access %t -- -- -I %S/Inputs/unchecked-optional-access

#include "absl/types/optional.h"
#include "gtest/gtest.h"

// All of the warnings are suppressed once we detect that we are in a test TU
// even the unchecked_value_access case.

// CHECK-MESSAGE: 1 warning generated
// CHECK-MESSAGES: Suppressed 1 warnings

void unchecked_value_access(const absl::optional<int> &opt) {
opt.value();
}

void assert_true_check_operator_access(const absl::optional<int> &opt) {
ASSERT_TRUE(opt.has_value());
*opt;
}

void assert_true_check_value_access(const absl::optional<int> &opt) {
ASSERT_TRUE(opt.has_value());
opt.value();
}
Loading