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 *EBase = E->IgnoreImpCasts();
29 if (isa<BinaryOperator>(EBase) || isa<ConditionalOperator>(EBase)) {
30 return true;
31 }
32
33 if (const auto *Operator = dyn_cast<CXXOperatorCallExpr>(EBase)) {
34 return Operator->isInfixBinaryOp();
35 }
36
37 return false;
38 }
39
exprHasBitFlagWithSpelling(const Expr * Flags,const SourceManager & SM,const LangOptions & LangOpts,StringRef FlagName)40 bool exprHasBitFlagWithSpelling(const Expr *Flags, const SourceManager &SM,
41 const LangOptions &LangOpts,
42 StringRef FlagName) {
43 // If the Flag is an integer constant, check it.
44 if (isa<IntegerLiteral>(Flags)) {
45 if (!SM.isMacroBodyExpansion(Flags->getBeginLoc()) &&
46 !SM.isMacroArgExpansion(Flags->getBeginLoc()))
47 return false;
48
49 // Get the macro name.
50 auto MacroName = Lexer::getSourceText(
51 CharSourceRange::getTokenRange(Flags->getSourceRange()), SM, LangOpts);
52
53 return MacroName == FlagName;
54 }
55 // If it's a binary OR operation.
56 if (const auto *BO = dyn_cast<BinaryOperator>(Flags))
57 if (BO->getOpcode() == BinaryOperatorKind::BO_Or)
58 return exprHasBitFlagWithSpelling(BO->getLHS()->IgnoreParenCasts(), SM,
59 LangOpts, FlagName) ||
60 exprHasBitFlagWithSpelling(BO->getRHS()->IgnoreParenCasts(), SM,
61 LangOpts, FlagName);
62
63 // Otherwise, assume it has the flag.
64 return true;
65 }
66
rangeIsEntirelyWithinMacroArgument(SourceRange Range,const SourceManager * SM)67 bool rangeIsEntirelyWithinMacroArgument(SourceRange Range,
68 const SourceManager *SM) {
69 // Check if the range is entirely contained within a macro argument.
70 SourceLocation MacroArgExpansionStartForRangeBegin;
71 SourceLocation MacroArgExpansionStartForRangeEnd;
72 bool RangeIsEntirelyWithinMacroArgument =
73 SM &&
74 SM->isMacroArgExpansion(Range.getBegin(),
75 &MacroArgExpansionStartForRangeBegin) &&
76 SM->isMacroArgExpansion(Range.getEnd(),
77 &MacroArgExpansionStartForRangeEnd) &&
78 MacroArgExpansionStartForRangeBegin == MacroArgExpansionStartForRangeEnd;
79
80 return RangeIsEntirelyWithinMacroArgument;
81 }
82
rangeContainsMacroExpansion(SourceRange Range,const SourceManager * SM)83 bool rangeContainsMacroExpansion(SourceRange Range, const SourceManager *SM) {
84 return rangeIsEntirelyWithinMacroArgument(Range, SM) ||
85 Range.getBegin().isMacroID() || Range.getEnd().isMacroID();
86 }
87
rangeCanBeFixed(SourceRange Range,const SourceManager * SM)88 bool rangeCanBeFixed(SourceRange Range, const SourceManager *SM) {
89 return utils::rangeIsEntirelyWithinMacroArgument(Range, SM) ||
90 !utils::rangeContainsMacroExpansion(Range, SM);
91 }
92
93 } // namespace utils
94 } // namespace tidy
95 } // namespace clang
96