Skip to content

Commit f0ff55b

Browse files
Merged main:784e0cf2d980cdf0f63d3dba722389c5a556cda4 into amd-gfx:0033134a6ded
Local branch amd-gfx 0033134 Merged main:3eaaf7c4d062976901c79b523e9f3cc606943119 into amd-gfx:5f9104d4971e Remote branch main 784e0cf [Driver][test] Replace legacy -target with --target= Change-Id: I71eee4775d27cceab8fdc7ebc871a3ef1c054e2b
2 parents 0033134 + 784e0cf commit f0ff55b

File tree

139 files changed

+1710
-654
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

139 files changed

+1710
-654
lines changed

clang-tools-extra/clang-tidy/bugprone/UnsafeFunctionsCheck.cpp

Lines changed: 143 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
//===----------------------------------------------------------------------===//
88

99
#include "UnsafeFunctionsCheck.h"
10+
#include "../utils/OptionsUtils.h"
1011
#include "clang/AST/ASTContext.h"
1112
#include "clang/ASTMatchers/ASTMatchFinder.h"
1213
#include "clang/Lex/PPCallbacks.h"
@@ -18,6 +19,10 @@ using namespace llvm;
1819

1920
namespace clang::tidy::bugprone {
2021

22+
static constexpr llvm::StringLiteral OptionNameCustomFunctions =
23+
"CustomFunctions";
24+
static constexpr llvm::StringLiteral OptionNameReportDefaultFunctions =
25+
"ReportDefaultFunctions";
2126
static constexpr llvm::StringLiteral OptionNameReportMoreUnsafeFunctions =
2227
"ReportMoreUnsafeFunctions";
2328

@@ -26,6 +31,8 @@ static constexpr llvm::StringLiteral FunctionNamesWithAnnexKReplacementId =
2631
static constexpr llvm::StringLiteral FunctionNamesId = "FunctionsNames";
2732
static constexpr llvm::StringLiteral AdditionalFunctionNamesId =
2833
"AdditionalFunctionsNames";
34+
static constexpr llvm::StringLiteral CustomFunctionNamesId =
35+
"CustomFunctionNames";
2936
static constexpr llvm::StringLiteral DeclRefId = "DRE";
3037

3138
static std::optional<std::string>
@@ -127,57 +134,128 @@ static bool isAnnexKAvailable(std::optional<bool> &CacheVar, Preprocessor *PP,
127134
return CacheVar.value();
128135
}
129136

137+
static std::vector<UnsafeFunctionsCheck::CheckedFunction>
138+
parseCheckedFunctions(StringRef Option, ClangTidyContext *Context) {
139+
const std::vector<StringRef> Functions =
140+
utils::options::parseStringList(Option);
141+
std::vector<UnsafeFunctionsCheck::CheckedFunction> Result;
142+
Result.reserve(Functions.size());
143+
144+
for (StringRef Function : Functions) {
145+
if (Function.empty())
146+
continue;
147+
148+
const auto [Name, Rest] = Function.split(',');
149+
const auto [Replacement, Reason] = Rest.split(',');
150+
151+
if (Name.trim().empty()) {
152+
Context->configurationDiag("invalid configuration value for option '%0'; "
153+
"expected the name of an unsafe function")
154+
<< OptionNameCustomFunctions;
155+
continue;
156+
}
157+
158+
Result.push_back(
159+
{Name.trim().str(),
160+
matchers::MatchesAnyListedNameMatcher::NameMatcher(Name.trim()),
161+
Replacement.trim().str(), Reason.trim().str()});
162+
}
163+
164+
return Result;
165+
}
166+
167+
static std::string serializeCheckedFunctions(
168+
const std::vector<UnsafeFunctionsCheck::CheckedFunction> &Functions) {
169+
std::vector<std::string> Result;
170+
Result.reserve(Functions.size());
171+
172+
for (const auto &Entry : Functions) {
173+
if (Entry.Reason.empty())
174+
Result.push_back(Entry.Name + "," + Entry.Replacement);
175+
else
176+
Result.push_back(Entry.Name + "," + Entry.Replacement + "," +
177+
Entry.Reason);
178+
}
179+
180+
return llvm::join(Result, ";");
181+
}
182+
130183
UnsafeFunctionsCheck::UnsafeFunctionsCheck(StringRef Name,
131184
ClangTidyContext *Context)
132185
: ClangTidyCheck(Name, Context),
186+
CustomFunctions(parseCheckedFunctions(
187+
Options.get(OptionNameCustomFunctions, ""), Context)),
188+
ReportDefaultFunctions(
189+
Options.get(OptionNameReportDefaultFunctions, true)),
133190
ReportMoreUnsafeFunctions(
134191
Options.get(OptionNameReportMoreUnsafeFunctions, true)) {}
135192

136193
void UnsafeFunctionsCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {
194+
Options.store(Opts, OptionNameCustomFunctions,
195+
serializeCheckedFunctions(CustomFunctions));
196+
Options.store(Opts, OptionNameReportDefaultFunctions, ReportDefaultFunctions);
137197
Options.store(Opts, OptionNameReportMoreUnsafeFunctions,
138198
ReportMoreUnsafeFunctions);
139199
}
140200

141201
void UnsafeFunctionsCheck::registerMatchers(MatchFinder *Finder) {
142-
if (getLangOpts().C11) {
143-
// Matching functions with safe replacements only in Annex K.
144-
auto FunctionNamesWithAnnexKReplacementMatcher = hasAnyName(
145-
"::bsearch", "::ctime", "::fopen", "::fprintf", "::freopen", "::fscanf",
146-
"::fwprintf", "::fwscanf", "::getenv", "::gmtime", "::localtime",
147-
"::mbsrtowcs", "::mbstowcs", "::memcpy", "::memmove", "::memset",
148-
"::printf", "::qsort", "::scanf", "::snprintf", "::sprintf", "::sscanf",
149-
"::strcat", "::strcpy", "::strerror", "::strlen", "::strncat",
150-
"::strncpy", "::strtok", "::swprintf", "::swscanf", "::vfprintf",
151-
"::vfscanf", "::vfwprintf", "::vfwscanf", "::vprintf", "::vscanf",
152-
"::vsnprintf", "::vsprintf", "::vsscanf", "::vswprintf", "::vswscanf",
153-
"::vwprintf", "::vwscanf", "::wcrtomb", "::wcscat", "::wcscpy",
154-
"::wcslen", "::wcsncat", "::wcsncpy", "::wcsrtombs", "::wcstok",
155-
"::wcstombs", "::wctomb", "::wmemcpy", "::wmemmove", "::wprintf",
156-
"::wscanf");
202+
if (ReportDefaultFunctions) {
203+
if (getLangOpts().C11) {
204+
// Matching functions with safe replacements only in Annex K.
205+
auto FunctionNamesWithAnnexKReplacementMatcher = hasAnyName(
206+
"::bsearch", "::ctime", "::fopen", "::fprintf", "::freopen",
207+
"::fscanf", "::fwprintf", "::fwscanf", "::getenv", "::gmtime",
208+
"::localtime", "::mbsrtowcs", "::mbstowcs", "::memcpy", "::memmove",
209+
"::memset", "::printf", "::qsort", "::scanf", "::snprintf",
210+
"::sprintf", "::sscanf", "::strcat", "::strcpy", "::strerror",
211+
"::strlen", "::strncat", "::strncpy", "::strtok", "::swprintf",
212+
"::swscanf", "::vfprintf", "::vfscanf", "::vfwprintf", "::vfwscanf",
213+
"::vprintf", "::vscanf", "::vsnprintf", "::vsprintf", "::vsscanf",
214+
"::vswprintf", "::vswscanf", "::vwprintf", "::vwscanf", "::wcrtomb",
215+
"::wcscat", "::wcscpy", "::wcslen", "::wcsncat", "::wcsncpy",
216+
"::wcsrtombs", "::wcstok", "::wcstombs", "::wctomb", "::wmemcpy",
217+
"::wmemmove", "::wprintf", "::wscanf");
218+
Finder->addMatcher(
219+
declRefExpr(to(functionDecl(FunctionNamesWithAnnexKReplacementMatcher)
220+
.bind(FunctionNamesWithAnnexKReplacementId)))
221+
.bind(DeclRefId),
222+
this);
223+
}
224+
225+
// Matching functions with replacements without Annex K.
226+
auto FunctionNamesMatcher =
227+
hasAnyName("::asctime", "asctime_r", "::gets", "::rewind", "::setbuf");
157228
Finder->addMatcher(
158-
declRefExpr(to(functionDecl(FunctionNamesWithAnnexKReplacementMatcher)
159-
.bind(FunctionNamesWithAnnexKReplacementId)))
229+
declRefExpr(
230+
to(functionDecl(FunctionNamesMatcher).bind(FunctionNamesId)))
160231
.bind(DeclRefId),
161232
this);
233+
234+
if (ReportMoreUnsafeFunctions) {
235+
// Matching functions with replacements without Annex K, at user request.
236+
auto AdditionalFunctionNamesMatcher =
237+
hasAnyName("::bcmp", "::bcopy", "::bzero", "::getpw", "::vfork");
238+
Finder->addMatcher(
239+
declRefExpr(to(functionDecl(AdditionalFunctionNamesMatcher)
240+
.bind(AdditionalFunctionNamesId)))
241+
.bind(DeclRefId),
242+
this);
243+
}
162244
}
163245

164-
// Matching functions with replacements without Annex K.
165-
auto FunctionNamesMatcher =
166-
hasAnyName("::asctime", "asctime_r", "::gets", "::rewind", "::setbuf");
167-
Finder->addMatcher(
168-
declRefExpr(to(functionDecl(FunctionNamesMatcher).bind(FunctionNamesId)))
169-
.bind(DeclRefId),
170-
this);
171-
172-
if (ReportMoreUnsafeFunctions) {
173-
// Matching functions with replacements without Annex K, at user request.
174-
auto AdditionalFunctionNamesMatcher =
175-
hasAnyName("::bcmp", "::bcopy", "::bzero", "::getpw", "::vfork");
176-
Finder->addMatcher(
177-
declRefExpr(to(functionDecl(AdditionalFunctionNamesMatcher)
178-
.bind(AdditionalFunctionNamesId)))
179-
.bind(DeclRefId),
180-
this);
246+
if (!CustomFunctions.empty()) {
247+
std::vector<llvm::StringRef> FunctionNames;
248+
FunctionNames.reserve(CustomFunctions.size());
249+
250+
for (const auto &Entry : CustomFunctions)
251+
FunctionNames.push_back(Entry.Name);
252+
253+
auto CustomFunctionsMatcher = matchers::matchesAnyListedName(FunctionNames);
254+
255+
Finder->addMatcher(declRefExpr(to(functionDecl(CustomFunctionsMatcher)
256+
.bind(CustomFunctionNamesId)))
257+
.bind(DeclRefId),
258+
this);
181259
}
182260
}
183261

@@ -186,16 +264,46 @@ void UnsafeFunctionsCheck::check(const MatchFinder::MatchResult &Result) {
186264
const auto *FuncDecl = cast<FunctionDecl>(DeclRef->getDecl());
187265
assert(DeclRef && FuncDecl && "No valid matched node in check()");
188266

267+
// Only one of these are matched at a time.
189268
const auto *AnnexK = Result.Nodes.getNodeAs<FunctionDecl>(
190269
FunctionNamesWithAnnexKReplacementId);
191270
const auto *Normal = Result.Nodes.getNodeAs<FunctionDecl>(FunctionNamesId);
192271
const auto *Additional =
193272
Result.Nodes.getNodeAs<FunctionDecl>(AdditionalFunctionNamesId);
194-
assert((AnnexK || Normal || Additional) && "No valid match category.");
273+
const auto *Custom =
274+
Result.Nodes.getNodeAs<FunctionDecl>(CustomFunctionNamesId);
275+
assert((AnnexK || Normal || Additional || Custom) &&
276+
"No valid match category.");
195277

196278
bool AnnexKIsAvailable =
197279
isAnnexKAvailable(IsAnnexKAvailable, PP, getLangOpts());
198280
StringRef FunctionName = FuncDecl->getName();
281+
282+
if (Custom) {
283+
for (const auto &Entry : CustomFunctions) {
284+
if (Entry.Pattern.match(*FuncDecl)) {
285+
StringRef Reason =
286+
Entry.Reason.empty() ? "is marked as unsafe" : Entry.Reason.c_str();
287+
288+
if (Entry.Replacement.empty()) {
289+
diag(DeclRef->getExprLoc(), "function %0 %1; it should not be used")
290+
<< FuncDecl << Reason << Entry.Replacement
291+
<< DeclRef->getSourceRange();
292+
} else {
293+
diag(DeclRef->getExprLoc(),
294+
"function %0 %1; '%2' should be used instead")
295+
<< FuncDecl << Reason << Entry.Replacement
296+
<< DeclRef->getSourceRange();
297+
}
298+
299+
return;
300+
}
301+
}
302+
303+
llvm_unreachable("No custom function was matched.");
304+
return;
305+
}
306+
199307
const std::optional<std::string> ReplacementFunctionName =
200308
[&]() -> std::optional<std::string> {
201309
if (AnnexK) {

clang-tools-extra/clang-tidy/bugprone/UnsafeFunctionsCheck.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_UNSAFEFUNCTIONSCHECK_H
1111

1212
#include "../ClangTidyCheck.h"
13+
#include "../utils/Matchers.h"
1314
#include <optional>
1415

1516
namespace clang::tidy::bugprone {
@@ -32,7 +33,18 @@ class UnsafeFunctionsCheck : public ClangTidyCheck {
3233
Preprocessor *ModuleExpanderPP) override;
3334
void onEndOfTranslationUnit() override;
3435

36+
struct CheckedFunction {
37+
std::string Name;
38+
matchers::MatchesAnyListedNameMatcher::NameMatcher Pattern;
39+
std::string Replacement;
40+
std::string Reason;
41+
};
42+
3543
private:
44+
const std::vector<CheckedFunction> CustomFunctions;
45+
46+
// If true, the default set of functions are reported.
47+
const bool ReportDefaultFunctions;
3648
/// If true, additional functions from widely used API-s (such as POSIX) are
3749
/// added to the list of reported functions.
3850
const bool ReportMoreUnsafeFunctions;

clang-tools-extra/clang-tidy/utils/Matchers.h

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -85,15 +85,7 @@ class MatchesAnyListedNameMatcher
8585
NameList.begin(), NameList.end(), std::back_inserter(NameMatchers),
8686
[](const llvm::StringRef Name) { return NameMatcher(Name); });
8787
}
88-
bool matches(
89-
const NamedDecl &Node, ast_matchers::internal::ASTMatchFinder *Finder,
90-
ast_matchers::internal::BoundNodesTreeBuilder *Builder) const override {
91-
return llvm::any_of(NameMatchers, [&Node](const NameMatcher &NM) {
92-
return NM.match(Node);
93-
});
94-
}
9588

96-
private:
9789
class NameMatcher {
9890
llvm::Regex Regex;
9991
enum class MatchMode {
@@ -136,6 +128,15 @@ class MatchesAnyListedNameMatcher
136128
}
137129
};
138130

131+
bool matches(
132+
const NamedDecl &Node, ast_matchers::internal::ASTMatchFinder *Finder,
133+
ast_matchers::internal::BoundNodesTreeBuilder *Builder) const override {
134+
return llvm::any_of(NameMatchers, [&Node](const NameMatcher &NM) {
135+
return NM.match(Node);
136+
});
137+
}
138+
139+
private:
139140
std::vector<NameMatcher> NameMatchers;
140141
};
141142

clang-tools-extra/clangd/unittests/DiagnosticsTests.cpp

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1984,6 +1984,30 @@ TEST(Diagnostics, Tags) {
19841984
withTag(DiagnosticTag::Deprecated)))));
19851985
}
19861986

1987+
TEST(Diagnostics, TidyDiagsArentAffectedFromWerror) {
1988+
TestTU TU;
1989+
TU.ExtraArgs = {"-Werror"};
1990+
Annotations Test(R"cpp($typedef[[typedef int INT]]; // error-ok)cpp");
1991+
TU.Code = Test.code().str();
1992+
TU.ClangTidyProvider = addTidyChecks("modernize-use-using");
1993+
EXPECT_THAT(
1994+
TU.build().getDiagnostics(),
1995+
ifTidyChecks(UnorderedElementsAre(
1996+
AllOf(Diag(Test.range("typedef"), "use 'using' instead of 'typedef'"),
1997+
// Make sure severity for clang-tidy finding isn't bumped to
1998+
// error due to Werror in compile flags.
1999+
diagSeverity(DiagnosticsEngine::Warning)))));
2000+
2001+
TU.ClangTidyProvider =
2002+
addTidyChecks("modernize-use-using", /*WarningsAsErrors=*/"modernize-*");
2003+
EXPECT_THAT(
2004+
TU.build().getDiagnostics(),
2005+
ifTidyChecks(UnorderedElementsAre(
2006+
AllOf(Diag(Test.range("typedef"), "use 'using' instead of 'typedef'"),
2007+
// Unless bumped explicitly with WarnAsError.
2008+
diagSeverity(DiagnosticsEngine::Error)))));
2009+
}
2010+
19872011
TEST(Diagnostics, DeprecatedDiagsAreHints) {
19882012
ClangdDiagnosticOptions Opts;
19892013
std::optional<clangd::Diagnostic> Diag;

clang-tools-extra/docs/ReleaseNotes.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,10 @@ Changes in existing checks
135135
`bsl::optional` and `bdlb::NullableValue` from
136136
<https://github.com/bloomberg/bde>_.
137137

138+
- Improved :doc:`bugprone-unsafe-functions
139+
<clang-tidy/checks/bugprone/unsafe-functions>` check to allow specifying
140+
additional functions to match.
141+
138142
- Improved :doc:`cert-flp30-c <clang-tidy/checks/cert/flp30-c>` check to
139143
fix false positive that floating point variable is only used in increment
140144
expression.

0 commit comments

Comments
 (0)