blob: 3c0427fdcc249d5c32beb8a40c8cd3b9194d00e1 [file] [log] [blame]
Haojian Wuada28622016-10-17 08:33:59 +00001//===---------- ASTUtils.cpp - clang-tidy ---------------------------------===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9
10#include "ASTUtils.h"
11
12#include "clang/ASTMatchers/ASTMatchFinder.h"
13#include "clang/ASTMatchers/ASTMatchers.h"
Yan Wangb38045d2017-07-12 17:43:36 +000014#include "clang/Lex/Lexer.h"
Haojian Wuada28622016-10-17 08:33:59 +000015
16namespace clang {
17namespace tidy {
18namespace utils {
19using namespace ast_matchers;
20
21const FunctionDecl *getSurroundingFunction(ASTContext &Context,
22 const Stmt &Statement) {
23 return selectFirst<const FunctionDecl>(
24 "function", match(stmt(hasAncestor(functionDecl().bind("function"))),
25 Statement, Context));
26}
Aaron Ballman72163a92017-04-24 14:57:09 +000027
28bool IsBinaryOrTernary(const Expr *E) {
29 const Expr *E_base = E->IgnoreImpCasts();
30 if (clang::isa<clang::BinaryOperator>(E_base) ||
31 clang::isa<clang::ConditionalOperator>(E_base)) {
32 return true;
33 }
34
35 if (const auto *Operator =
36 clang::dyn_cast<clang::CXXOperatorCallExpr>(E_base)) {
37 return Operator->isInfixBinaryOp();
38 }
39
40 return false;
41}
42
Yan Wangb38045d2017-07-12 17:43:36 +000043bool exprHasBitFlagWithSpelling(const Expr *Flags, const SourceManager &SM,
44 const LangOptions &LangOpts,
45 StringRef FlagName) {
46 // If the Flag is an integer constant, check it.
47 if (isa<IntegerLiteral>(Flags)) {
Stephen Kelly43465bf2018-08-09 22:42:26 +000048 if (!SM.isMacroBodyExpansion(Flags->getBeginLoc()) &&
49 !SM.isMacroArgExpansion(Flags->getBeginLoc()))
Yan Wangb38045d2017-07-12 17:43:36 +000050 return false;
51
Benjamin Kramer26f2eec2018-02-02 13:39:07 +000052 // Get the macro name.
Yan Wangb38045d2017-07-12 17:43:36 +000053 auto MacroName = Lexer::getSourceText(
54 CharSourceRange::getTokenRange(Flags->getSourceRange()), SM, LangOpts);
55
56 return MacroName == FlagName;
57 }
58 // If it's a binary OR operation.
59 if (const auto *BO = dyn_cast<BinaryOperator>(Flags))
60 if (BO->getOpcode() == clang::BinaryOperatorKind::BO_Or)
61 return exprHasBitFlagWithSpelling(BO->getLHS()->IgnoreParenCasts(), SM,
62 LangOpts, FlagName) ||
63 exprHasBitFlagWithSpelling(BO->getRHS()->IgnoreParenCasts(), SM,
64 LangOpts, FlagName);
65
66 // Otherwise, assume it has the flag.
67 return true;
68}
69
Roman Lebedev08701ec2018-10-26 13:09:27 +000070bool rangeIsEntirelyWithinMacroArgument(SourceRange Range,
71 const SourceManager *SM) {
72 // Check if the range is entirely contained within a macro argument.
73 SourceLocation MacroArgExpansionStartForRangeBegin;
74 SourceLocation MacroArgExpansionStartForRangeEnd;
75 bool RangeIsEntirelyWithinMacroArgument =
76 SM &&
77 SM->isMacroArgExpansion(Range.getBegin(),
78 &MacroArgExpansionStartForRangeBegin) &&
79 SM->isMacroArgExpansion(Range.getEnd(),
80 &MacroArgExpansionStartForRangeEnd) &&
81 MacroArgExpansionStartForRangeBegin == MacroArgExpansionStartForRangeEnd;
82
83 return RangeIsEntirelyWithinMacroArgument;
84}
85
86bool rangeContainsMacroExpansion(SourceRange Range, const SourceManager *SM) {
87 return rangeIsEntirelyWithinMacroArgument(Range, SM) ||
88 Range.getBegin().isMacroID() || Range.getEnd().isMacroID();
89}
90
91bool rangeCanBeFixed(SourceRange Range, const SourceManager *SM) {
92 return utils::rangeIsEntirelyWithinMacroArgument(Range, SM) ||
93 !utils::rangeContainsMacroExpansion(Range, SM);
94}
95
Haojian Wuada28622016-10-17 08:33:59 +000096} // namespace utils
97} // namespace tidy
98} // namespace clang