Skip to content

Commit 37b6ba9

Browse files
authored
[clang-tidy] Handle expr with side-effects in readability-static-accessed-through-instance (#90736)
Improved readability-static-accessed-through-instance check to support expressions with side-effects. Originally calls to overloaded operator were ignored by check, in fear of possible side-effects. This change remove that restriction, and enables fix-its for expressions with side-effect via --fix-notes. Closes #75163
1 parent 10bdcf6 commit 37b6ba9

File tree

4 files changed

+62
-21
lines changed

4 files changed

+62
-21
lines changed

clang-tools-extra/clang-tidy/readability/StaticAccessedThroughInstanceCheck.cpp

Lines changed: 23 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -59,10 +59,6 @@ void StaticAccessedThroughInstanceCheck::check(
5959

6060
const Expr *BaseExpr = MemberExpression->getBase();
6161

62-
// Do not warn for overloaded -> operators.
63-
if (isa<CXXOperatorCallExpr>(BaseExpr))
64-
return;
65-
6662
const QualType BaseType =
6763
BaseExpr->getType()->isPointerType()
6864
? BaseExpr->getType()->getPointeeType().getUnqualifiedType()
@@ -89,17 +85,30 @@ void StaticAccessedThroughInstanceCheck::check(
8985
return;
9086

9187
SourceLocation MemberExprStartLoc = MemberExpression->getBeginLoc();
92-
auto Diag =
93-
diag(MemberExprStartLoc, "static member accessed through instance");
94-
95-
if (BaseExpr->HasSideEffects(*AstContext) ||
96-
getNameSpecifierNestingLevel(BaseType) > NameSpecifierNestingThreshold)
97-
return;
88+
auto CreateFix = [&] {
89+
return FixItHint::CreateReplacement(
90+
CharSourceRange::getCharRange(MemberExprStartLoc,
91+
MemberExpression->getMemberLoc()),
92+
BaseTypeName + "::");
93+
};
94+
95+
{
96+
auto Diag =
97+
diag(MemberExprStartLoc, "static member accessed through instance");
98+
99+
if (getNameSpecifierNestingLevel(BaseType) > NameSpecifierNestingThreshold)
100+
return;
101+
102+
if (!BaseExpr->HasSideEffects(*AstContext,
103+
/* IncludePossibleEffects =*/true)) {
104+
Diag << CreateFix();
105+
return;
106+
}
107+
}
98108

99-
Diag << FixItHint::CreateReplacement(
100-
CharSourceRange::getCharRange(MemberExprStartLoc,
101-
MemberExpression->getMemberLoc()),
102-
BaseTypeName + "::");
109+
diag(MemberExprStartLoc, "member base expression may carry some side effects",
110+
DiagnosticIDs::Level::Note)
111+
<< BaseExpr->getSourceRange() << CreateFix();
103112
}
104113

105114
} // namespace clang::tidy::readability

clang-tools-extra/docs/ReleaseNotes.rst

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -352,6 +352,11 @@ Changes in existing checks
352352
<clang-tidy/checks/readability/redundant-inline-specifier>` check to properly
353353
emit warnings for static data member with an in-class initializer.
354354

355+
- Improved :doc:`readability-static-accessed-through-instance
356+
<clang-tidy/checks/readability/static-accessed-through-instance>` check to
357+
support calls to overloaded operators as base expression and provide fixes to
358+
expressions with side-effects.
359+
355360
- Improved :doc:`readability-static-definition-in-anonymous-namespace
356361
<clang-tidy/checks/readability/static-definition-in-anonymous-namespace>`
357362
check by resolving fix-it overlaps in template code by disregarding implicit

clang-tools-extra/docs/clang-tidy/checks/readability/static-accessed-through-instance.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,3 +35,6 @@ is changed to:
3535
C::E1;
3636
C::E2;
3737
38+
The `--fix` commandline option provides default support for safe fixes, whereas
39+
`--fix-notes` enables fixes that may replace expressions with side effects,
40+
potentially altering the program's behavior.

clang-tools-extra/test/clang-tidy/checkers/readability/static-accessed-through-instance.cpp

Lines changed: 31 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// RUN: %check_clang_tidy %s readability-static-accessed-through-instance %t -- -- -isystem %S/Inputs/static-accessed-through-instance
1+
// RUN: %check_clang_tidy %s readability-static-accessed-through-instance %t -- --fix-notes -- -isystem %S/Inputs/static-accessed-through-instance
22
#include <__clang_cuda_builtin_vars.h>
33

44
enum OutEnum {
@@ -47,7 +47,8 @@ C &f(int, int, int, int);
4747
void g() {
4848
f(1, 2, 3, 4).x;
4949
// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: static member accessed through instance [readability-static-accessed-through-instance]
50-
// CHECK-FIXES: {{^}} f(1, 2, 3, 4).x;{{$}}
50+
// CHECK-MESSAGES: :[[@LINE-2]]:3: note: member base expression may carry some side effects
51+
// CHECK-FIXES: {{^}} C::x;{{$}}
5152
}
5253

5354
int i(int &);
@@ -59,20 +60,23 @@ int k(bool);
5960
void f(C c) {
6061
j(i(h().x));
6162
// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: static member
62-
// CHECK-FIXES: {{^}} j(i(h().x));{{$}}
63+
// CHECK-MESSAGES: :[[@LINE-2]]:7: note: member base expression may carry some side effects
64+
// CHECK-FIXES: {{^}} j(i(C::x));{{$}}
6365

6466
// The execution of h() depends on the return value of a().
6567
j(k(a() && h().x));
6668
// CHECK-MESSAGES: :[[@LINE-1]]:14: warning: static member
67-
// CHECK-FIXES: {{^}} j(k(a() && h().x));{{$}}
69+
// CHECK-MESSAGES: :[[@LINE-2]]:14: note: member base expression may carry some side effects
70+
// CHECK-FIXES: {{^}} j(k(a() && C::x));{{$}}
6871

6972
if ([c]() {
7073
c.ns();
7174
return c;
7275
}().x == 15)
7376
;
7477
// CHECK-MESSAGES: :[[@LINE-5]]:7: warning: static member
75-
// CHECK-FIXES: {{^}} if ([c]() {{{$}}
78+
// CHECK-MESSAGES: :[[@LINE-6]]:7: note: member base expression may carry some side effects
79+
// CHECK-FIXES: {{^}} if (C::x == 15){{$}}
7680
}
7781

7882
// Nested specifiers
@@ -261,8 +265,11 @@ struct Qptr {
261265
};
262266

263267
int func(Qptr qp) {
264-
qp->y = 10; // OK, the overloaded operator might have side-effects.
265-
qp->K = 10; //
268+
qp->y = 10;
269+
qp->K = 10;
270+
// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: static member accessed through instance [readability-static-accessed-through-instance]
271+
// CHECK-MESSAGES: :[[@LINE-2]]:3: note: member base expression may carry some side effects
272+
// CHECK-FIXES: {{^}} Q::K = 10;
266273
}
267274

268275
namespace {
@@ -380,3 +387,20 @@ namespace PR51861 {
380387
// CHECK-FIXES: {{^}} PR51861::Foo::getBar();{{$}}
381388
}
382389
}
390+
391+
namespace PR75163 {
392+
struct Static {
393+
static void call();
394+
};
395+
396+
struct Ptr {
397+
Static* operator->();
398+
};
399+
400+
void test(Ptr& ptr) {
401+
ptr->call();
402+
// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: static member accessed through instance [readability-static-accessed-through-instance]
403+
// CHECK-MESSAGES: :[[@LINE-2]]:5: note: member base expression may carry some side effects
404+
// CHECK-FIXES: {{^}} PR75163::Static::call();{{$}}
405+
}
406+
}

0 commit comments

Comments
 (0)