• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //===---------- ASTUtils.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 "ASTUtils.h"
10 
11 #include "clang/ASTMatchers/ASTMatchFinder.h"
12 #include "clang/ASTMatchers/ASTMatchers.h"
13 #include "clang/Lex/Lexer.h"
14 
15 namespace clang {
16 namespace tidy {
17 namespace utils {
18 using namespace ast_matchers;
19 
getSurroundingFunction(ASTContext & Context,const Stmt & Statement)20 const FunctionDecl *getSurroundingFunction(ASTContext &Context,
21                                            const Stmt &Statement) {
22   return selectFirst<const FunctionDecl>(
23       "function", match(stmt(hasAncestor(functionDecl().bind("function"))),
24                         Statement, Context));
25 }
26 
IsBinaryOrTernary(const Expr * E)27 bool IsBinaryOrTernary(const Expr *E) {
28   const Expr *E_base = E->IgnoreImpCasts();
29   if (clang::isa<clang::BinaryOperator>(E_base) ||
30       clang::isa<clang::ConditionalOperator>(E_base)) {
31     return true;
32   }
33 
34   if (const auto *Operator =
35           clang::dyn_cast<clang::CXXOperatorCallExpr>(E_base)) {
36     return Operator->isInfixBinaryOp();
37   }
38 
39   return false;
40 }
41 
exprHasBitFlagWithSpelling(const Expr * Flags,const SourceManager & SM,const LangOptions & LangOpts,StringRef FlagName)42 bool exprHasBitFlagWithSpelling(const Expr *Flags, const SourceManager &SM,
43                                 const LangOptions &LangOpts,
44                                 StringRef FlagName) {
45   // If the Flag is an integer constant, check it.
46   if (isa<IntegerLiteral>(Flags)) {
47     if (!SM.isMacroBodyExpansion(Flags->getBeginLoc()) &&
48         !SM.isMacroArgExpansion(Flags->getBeginLoc()))
49       return false;
50 
51     // Get the macro name.
52     auto MacroName = Lexer::getSourceText(
53         CharSourceRange::getTokenRange(Flags->getSourceRange()), SM, LangOpts);
54 
55     return MacroName == FlagName;
56   }
57   // If it's a binary OR operation.
58   if (const auto *BO = dyn_cast<BinaryOperator>(Flags))
59     if (BO->getOpcode() == clang::BinaryOperatorKind::BO_Or)
60       return exprHasBitFlagWithSpelling(BO->getLHS()->IgnoreParenCasts(), SM,
61                                         LangOpts, FlagName) ||
62              exprHasBitFlagWithSpelling(BO->getRHS()->IgnoreParenCasts(), SM,
63                                         LangOpts, FlagName);
64 
65   // Otherwise, assume it has the flag.
66   return true;
67 }
68 
rangeIsEntirelyWithinMacroArgument(SourceRange Range,const SourceManager * SM)69 bool rangeIsEntirelyWithinMacroArgument(SourceRange Range,
70                                         const SourceManager *SM) {
71   // Check if the range is entirely contained within a macro argument.
72   SourceLocation MacroArgExpansionStartForRangeBegin;
73   SourceLocation MacroArgExpansionStartForRangeEnd;
74   bool RangeIsEntirelyWithinMacroArgument =
75       SM &&
76       SM->isMacroArgExpansion(Range.getBegin(),
77                               &MacroArgExpansionStartForRangeBegin) &&
78       SM->isMacroArgExpansion(Range.getEnd(),
79                               &MacroArgExpansionStartForRangeEnd) &&
80       MacroArgExpansionStartForRangeBegin == MacroArgExpansionStartForRangeEnd;
81 
82   return RangeIsEntirelyWithinMacroArgument;
83 }
84 
rangeContainsMacroExpansion(SourceRange Range,const SourceManager * SM)85 bool rangeContainsMacroExpansion(SourceRange Range, const SourceManager *SM) {
86   return rangeIsEntirelyWithinMacroArgument(Range, SM) ||
87          Range.getBegin().isMacroID() || Range.getEnd().isMacroID();
88 }
89 
rangeCanBeFixed(SourceRange Range,const SourceManager * SM)90 bool rangeCanBeFixed(SourceRange Range, const SourceManager *SM) {
91   return utils::rangeIsEntirelyWithinMacroArgument(Range, SM) ||
92          !utils::rangeContainsMacroExpansion(Range, SM);
93 }
94 
95 } // namespace utils
96 } // namespace tidy
97 } // namespace clang
98