Skip to content

Commit 908a5a8

Browse files
committed
[clang-tidy] add abseil-unchecked-statusor-access
Pull Request: llvm#171188
1 parent 3c31c84 commit 908a5a8

File tree

13 files changed

+1532
-0
lines changed

13 files changed

+1532
-0
lines changed

clang-tools-extra/clang-tidy/abseil/AbseilTidyModule.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
#include "StringFindStrContainsCheck.h"
2828
#include "TimeComparisonCheck.h"
2929
#include "TimeSubtractionCheck.h"
30+
#include "UncheckedStatusOrAccessCheck.h"
3031
#include "UpgradeDurationConversionsCheck.h"
3132

3233
namespace clang::tidy {
@@ -67,6 +68,8 @@ class AbseilModule : public ClangTidyModule {
6768
CheckFactories.registerCheck<TimeComparisonCheck>("abseil-time-comparison");
6869
CheckFactories.registerCheck<TimeSubtractionCheck>(
6970
"abseil-time-subtraction");
71+
CheckFactories.registerCheck<UncheckedStatusOrAccessCheck>(
72+
"abseil-unchecked-statusor-access");
7073
CheckFactories.registerCheck<UpgradeDurationConversionsCheck>(
7174
"abseil-upgrade-duration-conversions");
7275
}

clang-tools-extra/clang-tidy/abseil/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ add_clang_library(clangTidyAbseilModule STATIC
2525
TimeComparisonCheck.cpp
2626
TimeSubtractionCheck.cpp
2727
UpgradeDurationConversionsCheck.cpp
28+
UncheckedStatusOrAccessCheck.cpp
2829

2930
LINK_LIBS
3031
clangTidy
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#include "UncheckedStatusOrAccessCheck.h"
10+
#include "clang/AST/ASTContext.h"
11+
#include "clang/ASTMatchers/ASTMatchFinder.h"
12+
#include "clang/ASTMatchers/ASTMatchers.h"
13+
#include "clang/Analysis/FlowSensitive/DataflowAnalysis.h"
14+
#include "clang/Analysis/FlowSensitive/Models/UncheckedStatusOrAccessModel.h"
15+
#include "clang/Basic/SourceLocation.h"
16+
#include "llvm/ADT/SmallVector.h"
17+
#include "llvm/Support/Error.h"
18+
19+
namespace clang::tidy::abseil {
20+
using ast_matchers::MatchFinder;
21+
using dataflow::statusor_model::UncheckedStatusOrAccessDiagnoser;
22+
using dataflow::statusor_model::UncheckedStatusOrAccessModel;
23+
24+
static constexpr llvm::StringLiteral FuncID("fun");
25+
26+
void UncheckedStatusOrAccessCheck::registerMatchers(MatchFinder *Finder) {
27+
using namespace ast_matchers;
28+
29+
auto HasStatusOrCallDescendant =
30+
hasDescendant(callExpr(callee(cxxMethodDecl(ofClass(hasAnyName(
31+
"absl::StatusOr", "absl::internal_statusor::OperatorBase"))))));
32+
Finder->addMatcher(functionDecl(unless(isExpansionInSystemHeader()),
33+
hasBody(HasStatusOrCallDescendant))
34+
.bind(FuncID),
35+
this);
36+
Finder->addMatcher(
37+
cxxConstructorDecl(hasAnyConstructorInitializer(
38+
withInitializer(HasStatusOrCallDescendant)))
39+
.bind(FuncID),
40+
this);
41+
}
42+
43+
void UncheckedStatusOrAccessCheck::check(
44+
const MatchFinder::MatchResult &Result) {
45+
if (Result.SourceManager->getDiagnostics().hasUncompilableErrorOccurred())
46+
return;
47+
48+
const auto *FuncDecl = Result.Nodes.getNodeAs<FunctionDecl>(FuncID);
49+
if (FuncDecl->isTemplated())
50+
return;
51+
52+
UncheckedStatusOrAccessDiagnoser Diagnoser;
53+
if (llvm::Expected<llvm::SmallVector<SourceLocation>> Locs =
54+
dataflow::diagnoseFunction<UncheckedStatusOrAccessModel,
55+
SourceLocation>(*FuncDecl, *Result.Context,
56+
Diagnoser))
57+
for (const SourceLocation &Loc : *Locs)
58+
diag(Loc, "unchecked access to 'absl::StatusOr' value");
59+
else
60+
llvm::consumeError(Locs.takeError());
61+
}
62+
63+
bool UncheckedStatusOrAccessCheck::isLanguageVersionSupported(
64+
const LangOptions &LangOpts) const {
65+
return LangOpts.CPlusPlus;
66+
}
67+
68+
} // namespace clang::tidy::abseil
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_ABSEIL_UNCHECKEDSTATUSORACCESSCHECK_H
2+
#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_ABSEIL_UNCHECKEDSTATUSORACCESSCHECK_H
3+
4+
#include "../ClangTidyCheck.h"
5+
#include "clang/ASTMatchers/ASTMatchFinder.h"
6+
7+
namespace clang::tidy::abseil {
8+
9+
// Warns when the code is unwrapping an absl::StatusOr<T> object without
10+
// assuring that it contains a value.
11+
//
12+
// For details on the dataflow analysis implemented in this check see:
13+
// clang/lib/Analysis/FlowSensitive/Models/UncheckedStatusOrAccessModel.cpp
14+
class UncheckedStatusOrAccessCheck : public ClangTidyCheck {
15+
public:
16+
using ClangTidyCheck::ClangTidyCheck;
17+
void registerMatchers(ast_matchers::MatchFinder *Finder) override;
18+
void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
19+
bool isLanguageVersionSupported(const LangOptions &LangOpts) const override;
20+
};
21+
22+
} // namespace clang::tidy::abseil
23+
24+
#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_ABSEIL_UNCHECKEDSTATUSORACCESSCHECK_H

clang-tools-extra/docs/ReleaseNotes.rst

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -214,6 +214,11 @@ Improvements to clang-tidy
214214
New checks
215215
^^^^^^^^^^
216216

217+
- New :doc:`abseil-unchecked-statusor-access
218+
<clang-tidy/checks/abseil/unchecked-statusor-access>` check.
219+
220+
Finds uses of ``absl::StatusOr`` without checking if a value is present.
221+
217222
- New :doc:`bugprone-derived-method-shadowing-base-method
218223
<clang-tidy/checks/bugprone/derived-method-shadowing-base-method>` check.
219224

0 commit comments

Comments
 (0)