MisplacedConstCheck.cpp 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475
  1. //===--- MisplacedConstCheck.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 "MisplacedConstCheck.h"
  9. #include "clang/AST/ASTContext.h"
  10. #include "clang/ASTMatchers/ASTMatchFinder.h"
  11. using namespace clang::ast_matchers;
  12. namespace clang::tidy::misc {
  13. void MisplacedConstCheck::registerMatchers(MatchFinder *Finder) {
  14. auto NonConstAndNonFunctionPointerType = hasType(pointerType(unless(
  15. pointee(anyOf(isConstQualified(), ignoringParens(functionType()))))));
  16. Finder->addMatcher(
  17. valueDecl(hasType(qualType(
  18. isConstQualified(),
  19. elaboratedType(namesType(typedefType(hasDeclaration(
  20. anyOf(typedefDecl(NonConstAndNonFunctionPointerType)
  21. .bind("typedef"),
  22. typeAliasDecl(NonConstAndNonFunctionPointerType)
  23. .bind("typeAlias")))))))))
  24. .bind("decl"),
  25. this);
  26. }
  27. static QualType guessAlternateQualification(ASTContext &Context, QualType QT) {
  28. // We're given a QualType from a typedef where the qualifiers apply to the
  29. // pointer instead of the pointee. Strip the const qualifier from the pointer
  30. // type and add it to the pointee instead.
  31. if (!QT->isPointerType())
  32. return QT;
  33. Qualifiers Quals = QT.getLocalQualifiers();
  34. Quals.removeConst();
  35. QualType NewQT = Context.getPointerType(
  36. QualType(QT->getPointeeType().getTypePtr(), Qualifiers::Const));
  37. return NewQT.withCVRQualifiers(Quals.getCVRQualifiers());
  38. }
  39. void MisplacedConstCheck::check(const MatchFinder::MatchResult &Result) {
  40. const auto *Var = Result.Nodes.getNodeAs<ValueDecl>("decl");
  41. ASTContext &Ctx = *Result.Context;
  42. QualType CanQT = Var->getType().getCanonicalType();
  43. SourceLocation AliasLoc;
  44. const char *AliasType;
  45. if (const auto *Typedef = Result.Nodes.getNodeAs<TypedefDecl>("typedef")) {
  46. AliasLoc = Typedef->getLocation();
  47. AliasType = "typedef";
  48. } else if (const auto *TypeAlias =
  49. Result.Nodes.getNodeAs<TypeAliasDecl>("typeAlias")) {
  50. AliasLoc = TypeAlias->getLocation();
  51. AliasType = "type alias";
  52. } else {
  53. llvm_unreachable("registerMatchers has registered an unknown matcher,"
  54. " code out of sync");
  55. }
  56. diag(Var->getLocation(), "%0 declared with a const-qualified %1; "
  57. "results in the type being '%2' instead of '%3'")
  58. << Var << AliasType << CanQT.getAsString(Ctx.getPrintingPolicy())
  59. << guessAlternateQualification(Ctx, CanQT)
  60. .getAsString(Ctx.getPrintingPolicy());
  61. diag(AliasLoc, "%0 declared here", DiagnosticIDs::Note) << AliasType;
  62. }
  63. } // namespace clang::tidy::misc