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