clang-tools  15.0.0git
UncheckedOptionalAccessCheck.cpp
Go to the documentation of this file.
1 //===--- UncheckedOptionalAccessCheck.cpp - clang-tidy --------------------===//
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 
10 #include "clang/AST/ASTContext.h"
11 #include "clang/AST/DeclCXX.h"
12 #include "clang/AST/DeclTemplate.h"
13 #include "clang/ASTMatchers/ASTMatchFinder.h"
14 #include "clang/ASTMatchers/ASTMatchers.h"
15 #include "clang/Analysis/CFG.h"
16 #include "clang/Analysis/FlowSensitive/ControlFlowContext.h"
17 #include "clang/Analysis/FlowSensitive/DataflowAnalysisContext.h"
18 #include "clang/Analysis/FlowSensitive/DataflowEnvironment.h"
19 #include "clang/Analysis/FlowSensitive/DataflowLattice.h"
20 #include "clang/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.h"
21 #include "clang/Analysis/FlowSensitive/WatchedLiteralsSolver.h"
22 #include "clang/Basic/SourceLocation.h"
23 #include "llvm/ADT/Any.h"
24 #include "llvm/ADT/Optional.h"
25 #include "llvm/ADT/STLExtras.h"
26 #include "llvm/Support/Error.h"
27 #include <memory>
28 #include <vector>
29 
30 namespace clang {
31 namespace tidy {
32 namespace bugprone {
33 using ast_matchers::MatchFinder;
34 using dataflow::UncheckedOptionalAccessDiagnoser;
35 using dataflow::UncheckedOptionalAccessModel;
36 using llvm::Optional;
37 
38 static constexpr llvm::StringLiteral FuncID("fun");
39 
40 static Optional<std::vector<SourceLocation>>
41 analyzeFunction(const FunctionDecl &FuncDecl, ASTContext &ASTCtx) {
42  using dataflow::ControlFlowContext;
43  using dataflow::DataflowAnalysisState;
44  using llvm::Expected;
45 
46  Expected<ControlFlowContext> Context =
47  ControlFlowContext::build(&FuncDecl, FuncDecl.getBody(), &ASTCtx);
48  if (!Context)
49  return llvm::None;
50 
51  dataflow::DataflowAnalysisContext AnalysisContext(
52  std::make_unique<dataflow::WatchedLiteralsSolver>());
53  dataflow::Environment Env(AnalysisContext, FuncDecl);
54  UncheckedOptionalAccessModel Analysis(ASTCtx);
55  UncheckedOptionalAccessDiagnoser Diagnoser;
56  std::vector<SourceLocation> Diagnostics;
57  Expected<std::vector<
58  Optional<DataflowAnalysisState<UncheckedOptionalAccessModel::Lattice>>>>
59  BlockToOutputState = dataflow::runDataflowAnalysis(
60  *Context, Analysis, Env,
61  [&ASTCtx, &Diagnoser, &Diagnostics](
62  const Stmt *Stmt,
63  const DataflowAnalysisState<UncheckedOptionalAccessModel::Lattice>
64  &State) mutable {
65  auto StmtDiagnostics = Diagnoser.diagnose(ASTCtx, Stmt, State.Env);
66  llvm::move(StmtDiagnostics, std::back_inserter(Diagnostics));
67  });
68  if (!BlockToOutputState)
69  return llvm::None;
70 
71  return Diagnostics;
72 }
73 
75  using namespace ast_matchers;
76 
77  auto HasOptionalCallDescendant = hasDescendant(callExpr(callee(cxxMethodDecl(
78  ofClass(UncheckedOptionalAccessModel::optionalClassDecl())))));
79  Finder->addMatcher(
80  decl(anyOf(functionDecl(unless(isExpansionInSystemHeader()),
81  // FIXME: Remove the filter below when lambdas are
82  // well supported by the check.
83  unless(hasDeclContext(cxxRecordDecl(isLambda()))),
84  hasBody(HasOptionalCallDescendant)),
85  cxxConstructorDecl(hasAnyConstructorInitializer(
86  withInitializer(HasOptionalCallDescendant)))))
87  .bind(FuncID),
88  this);
89 }
90 
92  const MatchFinder::MatchResult &Result) {
93  if (Result.SourceManager->getDiagnostics().hasUncompilableErrorOccurred())
94  return;
95 
96  const auto *FuncDecl = Result.Nodes.getNodeAs<FunctionDecl>(FuncID);
97  if (FuncDecl->isTemplated())
98  return;
99 
100  if (Optional<std::vector<SourceLocation>> Errors =
101  analyzeFunction(*FuncDecl, *Result.Context))
102  for (const SourceLocation &Loc : *Errors)
103  diag(Loc, "unchecked access to optional value");
104 }
105 
106 } // namespace bugprone
107 } // namespace tidy
108 } // namespace clang
Loc
SourceLocation Loc
Definition: KernelNameRestrictionCheck.cpp:45
Expected
std::vector< const char * > Expected
Definition: PrintASTTests.cpp:26
Diagnostics
WantDiagnostics Diagnostics
Definition: TUScheduler.cpp:655
clang::tidy::bugprone::FuncID
static constexpr llvm::StringLiteral FuncID("fun")
clang::tidy::ClangTidyCheck::diag
DiagnosticBuilder diag(SourceLocation Loc, StringRef Description, DiagnosticIDs::Level Level=DiagnosticIDs::Warning)
Add a diagnostic with the check's name.
Definition: ClangTidyCheck.cpp:25
clang::tidy::bugprone::UncheckedOptionalAccessCheck::registerMatchers
void registerMatchers(ast_matchers::MatchFinder *Finder) override
Override this to register AST matchers with Finder.
Definition: UncheckedOptionalAccessCheck.cpp:74
clang
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
Definition: ApplyReplacements.h:27
clang::tidy::bugprone::UncheckedOptionalAccessCheck::check
void check(const ast_matchers::MatchFinder::MatchResult &Result) override
ClangTidyChecks that register ASTMatchers should do the actual work in here.
Definition: UncheckedOptionalAccessCheck.cpp:91
UncheckedOptionalAccessCheck.h
clang::tidy::bugprone::analyzeFunction
static Optional< std::vector< SourceLocation > > analyzeFunction(const FunctionDecl &FuncDecl, ASTContext &ASTCtx)
Definition: UncheckedOptionalAccessCheck.cpp:41