Skip to content

Commit 583a258

Browse files
da-viperPiotrZSL
authored andcommitted
[clang-tidy] Don't replace typedefs in extern c scope (#69102)
Added IgnoreExternC option to modernize-use-using check. Fixes #35272
1 parent 34621aa commit 583a258

File tree

6 files changed

+72
-7
lines changed

6 files changed

+72
-7
lines changed

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

Lines changed: 25 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,26 +11,39 @@
1111
#include "clang/Lex/Lexer.h"
1212

1313
using namespace clang::ast_matchers;
14+
namespace {
15+
16+
AST_MATCHER(clang::LinkageSpecDecl, isExternCLinkage) {
17+
return Node.getLanguage() == clang::LinkageSpecDecl::lang_c;
18+
}
19+
} // namespace
1420

1521
namespace clang::tidy::modernize {
1622

23+
static constexpr llvm::StringLiteral ExternCDeclName = "extern-c-decl";
1724
static constexpr llvm::StringLiteral ParentDeclName = "parent-decl";
1825
static constexpr llvm::StringLiteral TagDeclName = "tag-decl";
1926
static constexpr llvm::StringLiteral TypedefName = "typedef";
2027

2128
UseUsingCheck::UseUsingCheck(StringRef Name, ClangTidyContext *Context)
2229
: ClangTidyCheck(Name, Context),
23-
IgnoreMacros(Options.getLocalOrGlobal("IgnoreMacros", true)) {}
30+
IgnoreMacros(Options.getLocalOrGlobal("IgnoreMacros", true)),
31+
IgnoreExternC(Options.get("IgnoreExternC", false)) {}
2432

2533
void UseUsingCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {
2634
Options.store(Opts, "IgnoreMacros", IgnoreMacros);
35+
Options.store(Opts, "IgnoreExternC", IgnoreExternC);
2736
}
2837

2938
void UseUsingCheck::registerMatchers(MatchFinder *Finder) {
30-
Finder->addMatcher(typedefDecl(unless(isInstantiated()),
31-
hasParent(decl().bind(ParentDeclName)))
32-
.bind(TypedefName),
33-
this);
39+
Finder->addMatcher(
40+
typedefDecl(
41+
unless(isInstantiated()),
42+
optionally(hasAncestor(
43+
linkageSpecDecl(isExternCLinkage()).bind(ExternCDeclName))),
44+
hasParent(decl().bind(ParentDeclName)))
45+
.bind(TypedefName),
46+
this);
3447

3548
// This matcher is used to find tag declarations in source code within
3649
// typedefs. They appear in the AST just *prior* to the typedefs.
@@ -70,6 +83,11 @@ void UseUsingCheck::check(const MatchFinder::MatchResult &Result) {
7083
if (MatchedDecl->getLocation().isInvalid())
7184
return;
7285

86+
const auto *ExternCDecl =
87+
Result.Nodes.getNodeAs<LinkageSpecDecl>(ExternCDeclName);
88+
if (ExternCDecl && IgnoreExternC)
89+
return;
90+
7391
SourceLocation StartLoc = MatchedDecl->getBeginLoc();
7492

7593
if (StartLoc.isMacroID() && IgnoreMacros)
@@ -122,7 +140,8 @@ void UseUsingCheck::check(const MatchFinder::MatchResult &Result) {
122140
Type = FirstTypedefName + Type.substr(FirstTypedefType.size() + 1);
123141
}
124142
if (!ReplaceRange.getEnd().isMacroID()) {
125-
const SourceLocation::IntTy Offset = MatchedDecl->getFunctionType() ? 0 : Name.size();
143+
const SourceLocation::IntTy Offset =
144+
MatchedDecl->getFunctionType() ? 0 : Name.size();
126145
LastReplacementEnd = ReplaceRange.getEnd().getLocWithOffset(Offset);
127146
}
128147

clang-tools-extra/clang-tidy/modernize/UseUsingCheck.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ namespace clang::tidy::modernize {
2020
class UseUsingCheck : public ClangTidyCheck {
2121

2222
const bool IgnoreMacros;
23+
const bool IgnoreExternC;
2324
SourceLocation LastReplacementEnd;
2425
llvm::DenseMap<const Decl *, SourceRange> LastTagDeclRanges;
2526

clang-tools-extra/docs/ReleaseNotes.rst

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -408,7 +408,8 @@ Changes in existing checks
408408

409409
- Improved :doc:`modernize-use-using
410410
<clang-tidy/checks/modernize/use-using>` check to fix function pointer and
411-
forward declared ``typedef`` correctly.
411+
forward declared ``typedef`` correctly. Added option `IgnoreExternC` to ignore ``typedef``
412+
declaration in ``extern "C"`` scope.
412413

413414
- Improved :doc:`performance-faster-string-find
414415
<clang-tidy/checks/performance/faster-string-find>` check to properly escape

clang-tools-extra/docs/clang-tidy/checks/modernize/use-using.rst

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,14 @@ After:
2828
using R_t = struct { int a; };
2929
using R_p = R_t*;
3030

31+
The checker ignores `typedef` within `extern "C" { ... }` blocks.
32+
33+
.. code-block:: c++
34+
35+
extern "C" {
36+
typedef int InExternC; // Left intact.
37+
}
38+
3139
This check requires using C++11 or higher to run.
3240

3341
Options
@@ -37,3 +45,8 @@ Options
3745

3846
If set to `true`, the check will not give warnings inside macros. Default
3947
is `true`.
48+
49+
.. option:: IgnoreExternC
50+
51+
If set to `true`, the check will not give warning inside `extern "C"`scope.
52+
Default is `false`
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
// RUN: %check_clang_tidy %s modernize-use-using %t -- -config="{CheckOptions: {modernize-use-using.IgnoreExternC: true}}" -- -I %S/Input/use-using/
2+
3+
// Some Header
4+
extern "C" {
5+
6+
typedef int NewInt;
7+
}
8+
9+
extern "C++" {
10+
11+
typedef int InExternCPP;
12+
// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use 'using' instead of 'typedef' [modernize-use-using]
13+
// CHECK-FIXES: using InExternCPP = int;
14+
}

clang-tools-extra/test/clang-tidy/checkers/modernize/use-using.cpp

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -325,3 +325,20 @@ typedef bool (*ISSUE_65055_2)(int);
325325
typedef class ISSUE_67529_1 *ISSUE_67529;
326326
// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use 'using' instead of 'typedef'
327327
// CHECK-FIXES: using ISSUE_67529 = class ISSUE_67529_1 *;
328+
329+
// Some Header
330+
extern "C" {
331+
332+
typedef int InExternC;
333+
// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use 'using' instead of 'typedef' [modernize-use-using]
334+
// CHECK-FIXES: using InExternC = int;
335+
336+
}
337+
338+
extern "C++" {
339+
340+
typedef int InExternCPP;
341+
// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use 'using' instead of 'typedef' [modernize-use-using]
342+
// CHECK-FIXES: using InExternCPP = int;
343+
344+
}

0 commit comments

Comments
 (0)