blob: 7a028df588ffa5d6bb1a73ff161e341d6989e29f [file] [log] [blame]
Aaron Ballmancf6cefd2016-06-07 17:22:47 +00001//===--- MisplacedConstCheck.cpp - clang-tidy------------------------------===//
2//
Chandler Carruth2946cd72019-01-19 08:50:56 +00003// 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
Aaron Ballmancf6cefd2016-06-07 17:22:47 +00006//
7//===----------------------------------------------------------------------===//
8
9#include "MisplacedConstCheck.h"
10#include "clang/AST/ASTContext.h"
11#include "clang/ASTMatchers/ASTMatchFinder.h"
12
13using namespace clang::ast_matchers;
14
15namespace clang {
16namespace tidy {
17namespace misc {
18
19void MisplacedConstCheck::registerMatchers(MatchFinder *Finder) {
Alexander Lanin84c5f192020-01-22 15:26:11 -050020 auto NonConstAndNonFunctionPointerType = hasType(pointerType(unless(
21 pointee(anyOf(isConstQualified(), ignoringParens(functionType()))))));
22
Aaron Ballmancf6cefd2016-06-07 17:22:47 +000023 Finder->addMatcher(
Alexander Lanin84c5f192020-01-22 15:26:11 -050024 valueDecl(
25 hasType(isConstQualified()),
26 hasType(typedefType(hasDeclaration(anyOf(
27 typedefDecl(NonConstAndNonFunctionPointerType).bind("typedef"),
28 typeAliasDecl(NonConstAndNonFunctionPointerType)
29 .bind("typeAlias"))))))
Aaron Ballmancf6cefd2016-06-07 17:22:47 +000030 .bind("decl"),
31 this);
32}
33
34static QualType guessAlternateQualification(ASTContext &Context, QualType QT) {
35 // We're given a QualType from a typedef where the qualifiers apply to the
36 // pointer instead of the pointee. Strip the const qualifier from the pointer
37 // type and add it to the pointee instead.
38 if (!QT->isPointerType())
39 return QT;
40
41 Qualifiers Quals = QT.getLocalQualifiers();
42 Quals.removeConst();
43
44 QualType NewQT = Context.getPointerType(
45 QualType(QT->getPointeeType().getTypePtr(), Qualifiers::Const));
46 return NewQT.withCVRQualifiers(Quals.getCVRQualifiers());
47}
48
49void MisplacedConstCheck::check(const MatchFinder::MatchResult &Result) {
50 const auto *Var = Result.Nodes.getNodeAs<ValueDecl>("decl");
Aaron Ballmancf6cefd2016-06-07 17:22:47 +000051 ASTContext &Ctx = *Result.Context;
52 QualType CanQT = Var->getType().getCanonicalType();
53
Alexander Lanin84c5f192020-01-22 15:26:11 -050054 SourceLocation AliasLoc;
55 const char *AliasType;
56 if (const auto *Typedef = Result.Nodes.getNodeAs<TypedefDecl>("typedef")) {
57 AliasLoc = Typedef->getLocation();
58 AliasType = "typedef";
59 } else if (const auto *TypeAlias =
60 Result.Nodes.getNodeAs<TypeAliasDecl>("typeAlias")) {
61 AliasLoc = TypeAlias->getLocation();
62 AliasType = "type alias";
63 } else {
64 llvm_unreachable("registerMatchers has registered an unknown matcher,"
65 " code out of sync");
66 }
67
68 diag(Var->getLocation(), "%0 declared with a const-qualified %1; "
69 "results in the type being '%2' instead of '%3'")
70 << Var << AliasType << CanQT.getAsString(Ctx.getPrintingPolicy())
Aaron Ballmancf6cefd2016-06-07 17:22:47 +000071 << guessAlternateQualification(Ctx, CanQT)
72 .getAsString(Ctx.getPrintingPolicy());
Alexander Lanin84c5f192020-01-22 15:26:11 -050073 diag(AliasLoc, "%0 declared here", DiagnosticIDs::Note) << AliasType;
Aaron Ballmancf6cefd2016-06-07 17:22:47 +000074}
75
76} // namespace misc
77} // namespace tidy
78} // namespace clang