Skip to content

Commit fd3346d

Browse files
authored
[clang-tidy] fix modernize-use-auto incorrect fix hints for pointer (#77943)
1 parent 63d7ca9 commit fd3346d

File tree

3 files changed

+74
-15
lines changed

3 files changed

+74
-15
lines changed

clang-tools-extra/clang-tidy/modernize/UseAutoCheck.cpp

Lines changed: 41 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,12 @@
88

99
#include "UseAutoCheck.h"
1010
#include "clang/AST/ASTContext.h"
11+
#include "clang/AST/TypeLoc.h"
1112
#include "clang/ASTMatchers/ASTMatchFinder.h"
1213
#include "clang/ASTMatchers/ASTMatchers.h"
1314
#include "clang/Basic/CharInfo.h"
1415
#include "clang/Tooling/FixIt.h"
16+
#include "llvm/ADT/STLExtras.h"
1517

1618
using namespace clang;
1719
using namespace clang::ast_matchers;
@@ -333,6 +335,25 @@ void UseAutoCheck::replaceIterators(const DeclStmt *D, ASTContext *Context) {
333335
<< FixItHint::CreateReplacement(Range, "auto");
334336
}
335337

338+
static void ignoreTypeLocClasses(
339+
TypeLoc &Loc,
340+
std::initializer_list<TypeLoc::TypeLocClass> const &LocClasses) {
341+
while (llvm::is_contained(LocClasses, Loc.getTypeLocClass()))
342+
Loc = Loc.getNextTypeLoc();
343+
}
344+
345+
static bool isMutliLevelPointerToTypeLocClasses(
346+
TypeLoc Loc,
347+
std::initializer_list<TypeLoc::TypeLocClass> const &LocClasses) {
348+
ignoreTypeLocClasses(Loc, {TypeLoc::Paren, TypeLoc::Qualified});
349+
TypeLoc::TypeLocClass TLC = Loc.getTypeLocClass();
350+
if (TLC != TypeLoc::Pointer && TLC != TypeLoc::MemberPointer)
351+
return false;
352+
ignoreTypeLocClasses(Loc, {TypeLoc::Paren, TypeLoc::Qualified,
353+
TypeLoc::Pointer, TypeLoc::MemberPointer});
354+
return llvm::is_contained(LocClasses, Loc.getTypeLocClass());
355+
}
356+
336357
void UseAutoCheck::replaceExpr(
337358
const DeclStmt *D, ASTContext *Context,
338359
llvm::function_ref<QualType(const Expr *)> GetType, StringRef Message) {
@@ -342,6 +363,10 @@ void UseAutoCheck::replaceExpr(
342363
return;
343364

344365
const QualType FirstDeclType = FirstDecl->getType().getCanonicalType();
366+
TypeSourceInfo *TSI = FirstDecl->getTypeSourceInfo();
367+
368+
if (TSI == nullptr)
369+
return;
345370

346371
std::vector<FixItHint> StarRemovals;
347372
for (const auto *Dec : D->decls()) {
@@ -383,17 +408,11 @@ void UseAutoCheck::replaceExpr(
383408
// is the same as the initializer, just more CV-qualified. However, TypeLoc
384409
// information is not reliable where CV qualifiers are concerned so we can't
385410
// do anything about this case for now.
386-
TypeLoc Loc = FirstDecl->getTypeSourceInfo()->getTypeLoc();
387-
if (!RemoveStars) {
388-
while (Loc.getTypeLocClass() == TypeLoc::Pointer ||
389-
Loc.getTypeLocClass() == TypeLoc::Qualified)
390-
Loc = Loc.getNextTypeLoc();
391-
}
392-
while (Loc.getTypeLocClass() == TypeLoc::LValueReference ||
393-
Loc.getTypeLocClass() == TypeLoc::RValueReference ||
394-
Loc.getTypeLocClass() == TypeLoc::Qualified) {
395-
Loc = Loc.getNextTypeLoc();
396-
}
411+
TypeLoc Loc = TSI->getTypeLoc();
412+
if (!RemoveStars)
413+
ignoreTypeLocClasses(Loc, {TypeLoc::Pointer, TypeLoc::Qualified});
414+
ignoreTypeLocClasses(Loc, {TypeLoc::LValueReference, TypeLoc::RValueReference,
415+
TypeLoc::Qualified});
397416
SourceRange Range(Loc.getSourceRange());
398417

399418
if (MinTypeNameLength != 0 &&
@@ -405,12 +424,19 @@ void UseAutoCheck::replaceExpr(
405424

406425
auto Diag = diag(Range.getBegin(), Message);
407426

427+
bool ShouldReplenishVariableName = isMutliLevelPointerToTypeLocClasses(
428+
TSI->getTypeLoc(), {TypeLoc::FunctionProto, TypeLoc::ConstantArray});
429+
408430
// Space after 'auto' to handle cases where the '*' in the pointer type is
409431
// next to the identifier. This avoids changing 'int *p' into 'autop'.
410-
// FIXME: This doesn't work for function pointers because the variable name
411-
// is inside the type.
412-
Diag << FixItHint::CreateReplacement(Range, RemoveStars ? "auto " : "auto")
413-
<< StarRemovals;
432+
llvm::StringRef Auto = ShouldReplenishVariableName
433+
? (RemoveStars ? "auto " : "auto *")
434+
: (RemoveStars ? "auto " : "auto");
435+
std::string ReplenishedVariableName =
436+
ShouldReplenishVariableName ? FirstDecl->getQualifiedNameAsString() : "";
437+
std::string Replacement =
438+
(Auto + llvm::StringRef{ReplenishedVariableName}).str();
439+
Diag << FixItHint::CreateReplacement(Range, Replacement) << StarRemovals;
414440
}
415441

416442
void UseAutoCheck::check(const MatchFinder::MatchResult &Result) {

clang-tools-extra/docs/ReleaseNotes.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -434,6 +434,10 @@ Changes in existing checks
434434
false-positives when constructing the container with ``count`` copies of
435435
elements with value ``value``.
436436

437+
- Improved :doc:`modernize-use-auto
438+
<clang-tidy/checks/modernize/use-auto>` to avoid create incorrect fix hints
439+
for pointer to array type and pointer to function type.
440+
437441
- Improved :doc:`modernize-use-emplace
438442
<clang-tidy/checks/modernize/use-emplace>` to not replace aggregates that
439443
``emplace`` cannot construct with aggregate initialization.
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
// RUN: %check_clang_tidy -check-suffix=REMOVE %s modernize-use-auto %t -- \
2+
// RUN: -config="{CheckOptions: {modernize-use-auto.RemoveStars: 'true', modernize-use-auto.MinTypeNameLength: '0'}}"
3+
// RUN: %check_clang_tidy %s modernize-use-auto %t -- \
4+
// RUN: -config="{CheckOptions: {modernize-use-auto.RemoveStars: 'false', modernize-use-auto.MinTypeNameLength: '0'}}"
5+
6+
void pointerToFunction() {
7+
void (*(*(f1)))() = static_cast<void (**)()>(nullptr);
8+
// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when initializing
9+
// CHECK-FIXES-REMOVE: auto f1 =
10+
// CHECK-FIXES: auto *f1 =
11+
}
12+
13+
void pointerToArray() {
14+
int(*a1)[2] = new int[10][2];
15+
// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when initializing
16+
// CHECK-FIXES-REMOVE: auto a1 =
17+
// CHECK-FIXES: auto *a1 =
18+
}
19+
20+
void memberFunctionPointer() {
21+
class A {
22+
void f();
23+
};
24+
void(A::* a1)() = static_cast<void(A::*)()>(nullptr);
25+
// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when initializing
26+
// CHECK-FIXES-REMOVE: auto a1 =
27+
// CHECK-FIXES: auto *a1 =
28+
}
29+

0 commit comments

Comments
 (0)