AvoidConstParamsInDecls.cpp 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990
  1. //===--- AvoidConstParamsInDecls.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 "AvoidConstParamsInDecls.h"
  9. #include "../utils/LexerUtils.h"
  10. #include "clang/ASTMatchers/ASTMatchFinder.h"
  11. #include "clang/ASTMatchers/ASTMatchers.h"
  12. #include "clang/Lex/Lexer.h"
  13. using namespace clang::ast_matchers;
  14. namespace clang::tidy::readability {
  15. namespace {
  16. SourceRange getTypeRange(const ParmVarDecl &Param) {
  17. return SourceRange(Param.getBeginLoc(),
  18. Param.getLocation().getLocWithOffset(-1));
  19. }
  20. } // namespace
  21. void AvoidConstParamsInDecls::storeOptions(ClangTidyOptions::OptionMap &Opts) {
  22. Options.store(Opts, "IgnoreMacros", IgnoreMacros);
  23. }
  24. void AvoidConstParamsInDecls::registerMatchers(MatchFinder *Finder) {
  25. const auto ConstParamDecl =
  26. parmVarDecl(hasType(qualType(isConstQualified()))).bind("param");
  27. Finder->addMatcher(
  28. functionDecl(unless(isDefinition()),
  29. has(typeLoc(forEach(ConstParamDecl))))
  30. .bind("func"),
  31. this);
  32. }
  33. void AvoidConstParamsInDecls::check(const MatchFinder::MatchResult &Result) {
  34. const auto *Func = Result.Nodes.getNodeAs<FunctionDecl>("func");
  35. const auto *Param = Result.Nodes.getNodeAs<ParmVarDecl>("param");
  36. if (!Param->getType().isLocalConstQualified())
  37. return;
  38. if (IgnoreMacros &&
  39. (Param->getBeginLoc().isMacroID() || Param->getEndLoc().isMacroID())) {
  40. // Suppress the check if macros are involved.
  41. return;
  42. }
  43. auto Diag = diag(Param->getBeginLoc(),
  44. "parameter %0 is const-qualified in the function "
  45. "declaration; const-qualification of parameters only has an "
  46. "effect in function definitions");
  47. if (Param->getName().empty()) {
  48. for (unsigned int I = 0; I < Func->getNumParams(); ++I) {
  49. if (Param == Func->getParamDecl(I)) {
  50. Diag << (I + 1);
  51. break;
  52. }
  53. }
  54. } else {
  55. Diag << Param;
  56. }
  57. if (Param->getBeginLoc().isMacroID() != Param->getEndLoc().isMacroID()) {
  58. // Do not offer a suggestion if the part of the variable declaration comes
  59. // from a macro.
  60. return;
  61. }
  62. CharSourceRange FileRange = Lexer::makeFileCharRange(
  63. CharSourceRange::getTokenRange(getTypeRange(*Param)),
  64. *Result.SourceManager, getLangOpts());
  65. if (!FileRange.isValid())
  66. return;
  67. auto Tok = tidy::utils::lexer::getQualifyingToken(
  68. tok::kw_const, FileRange, *Result.Context, *Result.SourceManager);
  69. if (!Tok)
  70. return;
  71. Diag << FixItHint::CreateRemoval(
  72. CharSourceRange::getTokenRange(Tok->getLocation(), Tok->getLocation()));
  73. }
  74. } // namespace clang::tidy::readability