clang-tools  14.0.0git
ComparisonInTempFailureRetryCheck.cpp
Go to the documentation of this file.
1 //===--- ComparisonInTempFailureRetryCheck.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 
9 #include "../utils/Matchers.h"
11 #include "clang/AST/ASTContext.h"
12 #include "clang/ASTMatchers/ASTMatchFinder.h"
13 #include "clang/Lex/Lexer.h"
14 
15 using namespace clang::ast_matchers;
16 
17 namespace clang {
18 namespace tidy {
19 namespace android {
20 
21 ComparisonInTempFailureRetryCheck::ComparisonInTempFailureRetryCheck(
22  StringRef Name, ClangTidyContext *Context)
23  : ClangTidyCheck(Name, Context),
24  RawRetryList(Options.get("RetryMacros", "TEMP_FAILURE_RETRY")) {
25  StringRef(RawRetryList).split(RetryMacros, ",", -1, false);
26 }
27 
30  Options.store(Opts, "RetryMacros", RawRetryList);
31 }
32 
34  // Both glibc's and Bionic's TEMP_FAILURE_RETRY macros structurally look like:
35  //
36  // #define TEMP_FAILURE_RETRY(x) ({ \
37  // typeof(x) y; \
38  // do y = (x); \
39  // while (y == -1 && errno == EINTR); \
40  // y; \
41  // })
42  //
43  // (glibc uses `long int` instead of `typeof(x)` for the type of y).
44  //
45  // It's unclear how to walk up the AST from inside the expansion of `x`, and
46  // we need to not complain about things like TEMP_FAILURE_RETRY(foo(x == 1)),
47  // so we just match the assignment of `y = (x)` and inspect `x` from there.
48  Finder->addMatcher(
49  binaryOperator(hasOperatorName("="),
50  hasRHS(ignoringParenCasts(
51  binaryOperator(isComparisonOperator()).bind("inner"))))
52  .bind("outer"),
53  this);
54 }
55 
57  const MatchFinder::MatchResult &Result) {
58  StringRef RetryMacroName;
59  const auto &Node = *Result.Nodes.getNodeAs<BinaryOperator>("outer");
60  if (!Node.getBeginLoc().isMacroID())
61  return;
62 
63  const SourceManager &SM = *Result.SourceManager;
64  if (!SM.isMacroArgExpansion(Node.getRHS()->IgnoreParenCasts()->getBeginLoc()))
65  return;
66 
67  const LangOptions &Opts = Result.Context->getLangOpts();
68  SourceLocation LocStart = Node.getBeginLoc();
69  while (LocStart.isMacroID()) {
70  SourceLocation Invocation = SM.getImmediateMacroCallerLoc(LocStart);
71  Token Tok;
72  if (!Lexer::getRawToken(SM.getSpellingLoc(Invocation), Tok, SM, Opts,
73  /*IgnoreWhiteSpace=*/true)) {
74  if (Tok.getKind() == tok::raw_identifier &&
75  llvm::is_contained(RetryMacros, Tok.getRawIdentifier())) {
76  RetryMacroName = Tok.getRawIdentifier();
77  break;
78  }
79  }
80 
81  LocStart = Invocation;
82  }
83  if (RetryMacroName.empty())
84  return;
85 
86  const auto &Inner = *Result.Nodes.getNodeAs<BinaryOperator>("inner");
87  diag(Inner.getOperatorLoc(), "top-level comparison in %0") << RetryMacroName;
88 
89  // FIXME: FixIts would be nice, but potentially nontrivial when nested macros
90  // happen, e.g. `TEMP_FAILURE_RETRY(IS_ZERO(foo()))`
91 }
92 
93 } // namespace android
94 } // namespace tidy
95 } // namespace clang
clang::tidy::ClangTidyOptions::OptionMap
llvm::StringMap< ClangTidyValue > OptionMap
Definition: ClangTidyOptions.h:115
ComparisonInTempFailureRetryCheck.h
clang::tidy::ClangTidyCheck
Base class for all clang-tidy checks.
Definition: ClangTidyCheck.h:54
clang::ast_matchers
Definition: AbseilMatcher.h:14
clang::tidy::ClangTidyCheck::Options
OptionsView Options
Definition: ClangTidyCheck.h:416
Inner
std::pair< Context, Canceler > Inner
Definition: CancellationTests.cpp:49
clang::tidy::ClangTidyContext
Every ClangTidyCheck reports errors through a DiagnosticsEngine provided by this context.
Definition: ClangTidyDiagnosticConsumer.h:72
Name
static constexpr llvm::StringLiteral Name
Definition: UppercaseLiteralSuffixCheck.cpp:28
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::android::ComparisonInTempFailureRetryCheck::storeOptions
void storeOptions(ClangTidyOptions::OptionMap &Opts) override
Should store all options supported by this check with their current values or default values for opti...
Definition: ComparisonInTempFailureRetryCheck.cpp:28
clang::tidy::android::ComparisonInTempFailureRetryCheck::registerMatchers
void registerMatchers(ast_matchers::MatchFinder *Finder) override
Override this to register AST matchers with Finder.
Definition: ComparisonInTempFailureRetryCheck.cpp:33
clang
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
Definition: ApplyReplacements.h:27
clang::tidy::android::ComparisonInTempFailureRetryCheck::check
void check(const ast_matchers::MatchFinder::MatchResult &Result) override
ClangTidyChecks that register ASTMatchers should do the actual work in here.
Definition: ComparisonInTempFailureRetryCheck.cpp:56
clang::tidy::ClangTidyCheck::OptionsView::store
void store(ClangTidyOptions::OptionMap &Options, StringRef LocalName, StringRef Value) const
Stores an option with the check-local name LocalName with string value Value to Options.
Definition: ClangTidyCheck.cpp:120