ASTUtils.cpp 3.3 KB

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