1 //===--- MisplacedConstCheck.cpp - clang-tidy------------------------------===//
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
7 //===----------------------------------------------------------------------===//
9 #include "MisplacedConstCheck.h"
10 #include "clang/AST/ASTContext.h"
11 #include "clang/ASTMatchers/ASTMatchFinder.h"
13 using namespace clang::ast_matchers
;
15 namespace clang::tidy::misc
{
17 void MisplacedConstCheck::registerMatchers(MatchFinder
*Finder
) {
18 auto NonConstAndNonFunctionPointerType
= hasType(pointerType(unless(
19 pointee(anyOf(isConstQualified(), ignoringParens(functionType()))))));
22 valueDecl(hasType(qualType(
24 elaboratedType(namesType(typedefType(hasDeclaration(
25 anyOf(typedefDecl(NonConstAndNonFunctionPointerType
)
27 typeAliasDecl(NonConstAndNonFunctionPointerType
)
28 .bind("typeAlias")))))))))
33 static 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())
40 Qualifiers Quals
= QT
.getLocalQualifiers();
43 QualType NewQT
= Context
.getPointerType(
44 QualType(QT
->getPointeeType().getTypePtr(), Qualifiers::Const
));
45 return NewQT
.withCVRQualifiers(Quals
.getCVRQualifiers());
48 void 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();
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";
63 llvm_unreachable("registerMatchers has registered an unknown matcher,"
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
;
75 } // namespace clang::tidy::misc