1 //===--- AvoidConstParamsInDecls.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 "AvoidConstParamsInDecls.h"
10 #include "../utils/LexerUtils.h"
11 #include "clang/ASTMatchers/ASTMatchFinder.h"
12 #include "clang/ASTMatchers/ASTMatchers.h"
13 #include "clang/Lex/Lexer.h"
15 using namespace clang::ast_matchers
;
17 namespace clang::tidy::readability
{
20 SourceRange
getTypeRange(const ParmVarDecl
&Param
) {
21 return {Param
.getBeginLoc(), Param
.getLocation().getLocWithOffset(-1)};
24 // Finds the location of the qualifying `const` token in the `ParmValDecl`'s
25 // return type. Returns `std::nullopt` when the parm type is not
26 // `const`-qualified like when the type is an alias or a macro.
27 static std::optional
<Token
>
28 findConstToRemove(const ParmVarDecl
&Param
,
29 const MatchFinder::MatchResult
&Result
) {
31 CharSourceRange FileRange
= Lexer::makeFileCharRange(
32 CharSourceRange::getTokenRange(getTypeRange(Param
)),
33 *Result
.SourceManager
, Result
.Context
->getLangOpts());
35 if (FileRange
.isInvalid())
38 return tidy::utils::lexer::getQualifyingToken(
39 tok::kw_const
, FileRange
, *Result
.Context
, *Result
.SourceManager
);
44 void AvoidConstParamsInDecls::storeOptions(ClangTidyOptions::OptionMap
&Opts
) {
45 Options
.store(Opts
, "IgnoreMacros", IgnoreMacros
);
48 void AvoidConstParamsInDecls::registerMatchers(MatchFinder
*Finder
) {
49 const auto ConstParamDecl
=
50 parmVarDecl(hasType(qualType(isConstQualified()))).bind("param");
51 Finder
->addMatcher(functionDecl(unless(isDefinition()),
52 has(typeLoc(forEach(ConstParamDecl
))))
57 void AvoidConstParamsInDecls::check(const MatchFinder::MatchResult
&Result
) {
58 const auto *Func
= Result
.Nodes
.getNodeAs
<FunctionDecl
>("func");
59 const auto *Param
= Result
.Nodes
.getNodeAs
<ParmVarDecl
>("param");
61 if (!Param
->getType().isLocalConstQualified())
65 (Param
->getBeginLoc().isMacroID() || Param
->getEndLoc().isMacroID())) {
66 // Suppress the check if macros are involved.
70 const auto Tok
= findConstToRemove(*Param
, Result
);
71 const auto ConstLocation
= Tok
? Tok
->getLocation() : Param
->getBeginLoc();
73 auto Diag
= diag(ConstLocation
,
74 "parameter %0 is const-qualified in the function "
75 "declaration; const-qualification of parameters only has an "
76 "effect in function definitions");
77 if (Param
->getName().empty()) {
78 for (unsigned int I
= 0; I
< Func
->getNumParams(); ++I
) {
79 if (Param
== Func
->getParamDecl(I
)) {
88 if (Param
->getBeginLoc().isMacroID() != Param
->getEndLoc().isMacroID()) {
89 // Do not offer a suggestion if the part of the variable declaration comes
96 Diag
<< FixItHint::CreateRemoval(
97 CharSourceRange::getTokenRange(Tok
->getLocation(), Tok
->getLocation()));
100 } // namespace clang::tidy::readability