PostfixOperatorCheck.cpp 2.7 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980
  1. //===--- PostfixOperatorCheck.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 "PostfixOperatorCheck.h"
  9. #include "clang/AST/ASTContext.h"
  10. #include "clang/ASTMatchers/ASTMatchFinder.h"
  11. #include "clang/Lex/Lexer.h"
  12. using namespace clang::ast_matchers;
  13. namespace clang::tidy::cert {
  14. void PostfixOperatorCheck::registerMatchers(MatchFinder *Finder) {
  15. Finder->addMatcher(functionDecl(hasAnyOverloadedOperatorName("++", "--"),
  16. unless(isInstantiated()))
  17. .bind("decl"),
  18. this);
  19. }
  20. void PostfixOperatorCheck::check(const MatchFinder::MatchResult &Result) {
  21. const auto *FuncDecl = Result.Nodes.getNodeAs<FunctionDecl>("decl");
  22. bool HasThis = false;
  23. if (const auto *MethodDecl = dyn_cast<CXXMethodDecl>(FuncDecl))
  24. HasThis = MethodDecl->isInstance();
  25. // Check if the operator is a postfix one.
  26. if (FuncDecl->getNumParams() != (HasThis ? 1 : 2))
  27. return;
  28. SourceRange ReturnRange = FuncDecl->getReturnTypeSourceRange();
  29. SourceLocation Location = ReturnRange.getBegin();
  30. if (!Location.isValid())
  31. return;
  32. QualType ReturnType = FuncDecl->getReturnType();
  33. // Warn when the operators return a reference.
  34. if (const auto *RefType = ReturnType->getAs<ReferenceType>()) {
  35. auto Diag = diag(Location, "overloaded %0 returns a reference instead of a "
  36. "constant object type")
  37. << FuncDecl;
  38. if (Location.isMacroID() || ReturnType->getAs<TypedefType>() ||
  39. RefType->getPointeeTypeAsWritten()->getAs<TypedefType>())
  40. return;
  41. QualType ReplaceType =
  42. ReturnType.getNonReferenceType().getLocalUnqualifiedType();
  43. // The getReturnTypeSourceRange omits the qualifiers. We do not want to
  44. // duplicate the const.
  45. if (!ReturnType->getPointeeType().isConstQualified())
  46. ReplaceType.addConst();
  47. Diag << FixItHint::CreateReplacement(
  48. ReturnRange,
  49. ReplaceType.getAsString(Result.Context->getPrintingPolicy()) + " ");
  50. return;
  51. }
  52. if (ReturnType.isConstQualified() || ReturnType->isBuiltinType() ||
  53. ReturnType->isPointerType())
  54. return;
  55. auto Diag =
  56. diag(Location, "overloaded %0 returns a non-constant object instead of a "
  57. "constant object type")
  58. << FuncDecl;
  59. if (!Location.isMacroID() && !ReturnType->getAs<TypedefType>())
  60. Diag << FixItHint::CreateInsertion(Location, "const ");
  61. }
  62. } // namespace clang::tidy::cert