35 const MatchFinder::MatchResult &Result) {
40 assert((Qual == Qualifier::Const || Qual == Qualifier::Volatile ||
41 Qual == Qualifier::Restrict) &&
44 SourceLocation BeginLoc = Decl->getQualifierLoc().getBeginLoc();
45 if (BeginLoc.isInvalid())
46 BeginLoc = Decl->getBeginLoc();
47 const SourceLocation EndLoc = Decl->getLocation();
49 const CharSourceRange FileRange = Lexer::makeFileCharRange(
50 CharSourceRange::getCharRange(BeginLoc, EndLoc), *Result.SourceManager,
51 Result.Context->getLangOpts());
53 if (FileRange.isInvalid())
56 const tok::TokenKind Tok = Qual == Qualifier::Const ? tok::kw_const
57 : Qual == Qualifier::Volatile ? tok::kw_volatile
61 *Result.SourceManager);
121 auto ExplicitSingleVarDecl =
122 [](
const ast_matchers::internal::Matcher<VarDecl> &InnerMatcher,
123 llvm::StringRef ID) {
125 unless(isInTemplateInstantiation()),
127 varDecl(unless(isImplicit()), InnerMatcher).bind(ID)));
129 auto ExplicitSingleVarDeclInTemplate =
130 [](
const ast_matchers::internal::Matcher<VarDecl> &InnerMatcher,
131 llvm::StringRef ID) {
133 isInTemplateInstantiation(),
135 varDecl(unless(isImplicit()), InnerMatcher).bind(ID)));
138 auto IsBoundToType = refersToType(equalsBoundNode(
"type"));
139 auto UnlessFunctionType = unless(hasUnqualifiedDesugaredType(functionType()));
141 auto IsPointerType = [
this](
const auto &...InnerMatchers) {
142 if (this->IgnoreAliasing) {
144 hasUnqualifiedDesugaredType(pointerType(pointee(InnerMatchers...))));
146 return qualType(anyOf(qualType(pointerType(pointee(InnerMatchers...))),
147 qualType(substTemplateTypeParmType(hasReplacementType(
148 pointerType(pointee(InnerMatchers...)))))));
151 auto IsAutoDeducedToPointer =
152 [IsPointerType](
const std::vector<StringRef> &AllowedTypes,
153 const auto &...InnerMatchers) {
154 return autoType(hasDeducedType(
155 IsPointerType(InnerMatchers...),
156 unless(hasUnqualifiedType(
158 unless(pointerType(pointee(hasUnqualifiedType(
163 ExplicitSingleVarDecl(
164 hasType(IsAutoDeducedToPointer(AllowedTypes, UnlessFunctionType)),
169 ExplicitSingleVarDeclInTemplate(
170 allOf(hasType(IsAutoDeducedToPointer(
171 AllowedTypes, hasUnqualifiedType(qualType().bind(
"type")),
172 UnlessFunctionType)),
174 functionDecl(hasAnyTemplateArgument(IsBoundToType))),
175 hasAncestor(classTemplateSpecializationDecl(
176 hasAnyTemplateArgument(IsBoundToType))))),
179 if (!AddConstToQualified)
181 Finder->addMatcher(ExplicitSingleVarDecl(
182 hasType(pointerType(pointee(autoType()))),
"auto_ptr"),
185 ExplicitSingleVarDecl(hasType(lValueReferenceType(pointee(autoType()))),
191 if (
const auto *Var = Result.Nodes.getNodeAs<VarDecl>(
"auto")) {
192 SourceRange TypeSpecifier;
193 if (std::optional<SourceRange> TypeSpec =
195 TypeSpecifier = *TypeSpec;
200 llvm::SmallVector<SourceRange, 4> RemoveQualifiersRange;
201 auto CheckQualifier = [&](
bool IsPresent, Qualifier Qual) {
203 std::optional<Token> Token =
findQualToken(Var, Qual, Result);
204 if (!Token || Token->getLocation().isMacroID())
206 if (std::optional<SourceRange> Result =
208 RemoveQualifiersRange.push_back(*Result);
213 bool IsLocalConst = Var->getType().isLocalConstQualified();
214 bool IsLocalVolatile = Var->getType().isLocalVolatileQualified();
215 bool IsLocalRestrict = Var->getType().isLocalRestrictQualified();
217 if (CheckQualifier(IsLocalConst, Qualifier::Const) ||
218 CheckQualifier(IsLocalVolatile, Qualifier::Volatile) ||
219 CheckQualifier(IsLocalRestrict, Qualifier::Restrict))
223 if (Var->getLocation() == TypeSpecifier.getEnd().getLocWithOffset(1))
224 TypeSpecifier.setEnd(TypeSpecifier.getEnd().getLocWithOffset(1));
226 const CharSourceRange FixItRange =
227 CharSourceRange::getCharRange(TypeSpecifier);
228 if (FixItRange.isInvalid())
231 SourceLocation FixitLoc = FixItRange.getBegin();
232 for (
const SourceRange &Range : RemoveQualifiersRange)
233 if (Range.getBegin() < FixitLoc)
234 FixitLoc = Range.getBegin();
236 const std::string ReplStr = [&] {
237 const StringRef PtrConst =
isPointerConst(Var->getType()) ?
"const " :
"";
238 const StringRef LocalConst = IsLocalConst ?
"const " :
"";
239 const StringRef LocalVol = IsLocalVolatile ?
"volatile " :
"";
240 const StringRef LocalRestrict = IsLocalRestrict ?
"__restrict " :
"";
241 return (PtrConst +
"auto *" + LocalConst + LocalVol + LocalRestrict)
245 const DiagnosticBuilder Diag =
247 "'%select{|const }0%select{|volatile }1%select{|__restrict }2auto "
248 "%3' can be declared as '%4%3'")
249 << IsLocalConst << IsLocalVolatile << IsLocalRestrict << Var->getName()
252 for (
const SourceRange &Range : RemoveQualifiersRange)
253 Diag << FixItHint::CreateRemoval(CharSourceRange::getCharRange(Range));
255 Diag << FixItHint::CreateReplacement(FixItRange, ReplStr);
258 if (
const auto *Var = Result.Nodes.getNodeAs<VarDecl>(
"auto_ptr")) {
265 if (Var->getType().isLocalConstQualified()) {
266 std::optional<Token> Token =
findQualToken(Var, Qualifier::Const, Result);
267 if (!Token || Token->getLocation().isMacroID())
270 if (Var->getType().isLocalVolatileQualified()) {
271 std::optional<Token> Token =
273 if (!Token || Token->getLocation().isMacroID())
276 if (Var->getType().isLocalRestrictQualified()) {
277 std::optional<Token> Token =
279 if (!Token || Token->getLocation().isMacroID())
283 if (std::optional<SourceRange> TypeSpec =
285 if (TypeSpec->isInvalid() || TypeSpec->getBegin().isMacroID() ||
286 TypeSpec->getEnd().isMacroID())
288 const SourceLocation InsertPos = TypeSpec->getBegin();
290 "'auto *%select{|const }0%select{|volatile }1%2' can be declared as "
291 "'const auto *%select{|const }0%select{|volatile }1%2'")
292 << Var->getType().isLocalConstQualified()
293 << Var->getType().isLocalVolatileQualified() << Var->getName()
294 << FixItHint::CreateInsertion(InsertPos,
"const ");
298 if (
const auto *Var = Result.Nodes.getNodeAs<VarDecl>(
"auto_ref")) {
305 if (std::optional<SourceRange> TypeSpec =
307 if (TypeSpec->isInvalid() || TypeSpec->getBegin().isMacroID() ||
308 TypeSpec->getEnd().isMacroID())
310 const SourceLocation InsertPos = TypeSpec->getBegin();
311 diag(InsertPos,
"'auto &%0' can be declared as 'const auto &%0'")
312 << Var->getName() << FixItHint::CreateInsertion(InsertPos,
"const ");
Every ClangTidyCheck reports errors through a DiagnosticsEngine provided by this context.