1f27c8ac8SGergely Fűtő //===--- UnsafeFunctionsCheck.cpp - clang-tidy ----------------------------===// 2f27c8ac8SGergely Fűtő // 3f27c8ac8SGergely Fűtő // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4f27c8ac8SGergely Fűtő // See https://llvm.org/LICENSE.txt for license information. 5f27c8ac8SGergely Fűtő // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6f27c8ac8SGergely Fűtő // 7f27c8ac8SGergely Fűtő //===----------------------------------------------------------------------===// 8f27c8ac8SGergely Fűtő 9f27c8ac8SGergely Fűtő #include "UnsafeFunctionsCheck.h" 10*0b8866d1SDiscookie #include "../utils/OptionsUtils.h" 11f27c8ac8SGergely Fűtő #include "clang/AST/ASTContext.h" 12f27c8ac8SGergely Fűtő #include "clang/ASTMatchers/ASTMatchFinder.h" 13f27c8ac8SGergely Fűtő #include "clang/Lex/PPCallbacks.h" 14f27c8ac8SGergely Fűtő #include "clang/Lex/Preprocessor.h" 15f27c8ac8SGergely Fűtő #include <cassert> 16f27c8ac8SGergely Fűtő 17f27c8ac8SGergely Fűtő using namespace clang::ast_matchers; 18f27c8ac8SGergely Fűtő using namespace llvm; 19f27c8ac8SGergely Fűtő 20d57cf05fSPiotr Zegar namespace clang::tidy::bugprone { 21f27c8ac8SGergely Fűtő 22*0b8866d1SDiscookie static constexpr llvm::StringLiteral OptionNameCustomFunctions = 23*0b8866d1SDiscookie "CustomFunctions"; 24*0b8866d1SDiscookie static constexpr llvm::StringLiteral OptionNameReportDefaultFunctions = 25*0b8866d1SDiscookie "ReportDefaultFunctions"; 26f27c8ac8SGergely Fűtő static constexpr llvm::StringLiteral OptionNameReportMoreUnsafeFunctions = 27f27c8ac8SGergely Fűtő "ReportMoreUnsafeFunctions"; 28f27c8ac8SGergely Fűtő 29f27c8ac8SGergely Fűtő static constexpr llvm::StringLiteral FunctionNamesWithAnnexKReplacementId = 30f27c8ac8SGergely Fűtő "FunctionNamesWithAnnexKReplacement"; 31f27c8ac8SGergely Fűtő static constexpr llvm::StringLiteral FunctionNamesId = "FunctionsNames"; 32f27c8ac8SGergely Fűtő static constexpr llvm::StringLiteral AdditionalFunctionNamesId = 33f27c8ac8SGergely Fűtő "AdditionalFunctionsNames"; 34*0b8866d1SDiscookie static constexpr llvm::StringLiteral CustomFunctionNamesId = 35*0b8866d1SDiscookie "CustomFunctionNames"; 36f27c8ac8SGergely Fűtő static constexpr llvm::StringLiteral DeclRefId = "DRE"; 37f27c8ac8SGergely Fűtő 38f27c8ac8SGergely Fűtő static std::optional<std::string> 39f27c8ac8SGergely Fűtő getAnnexKReplacementFor(StringRef FunctionName) { 40f27c8ac8SGergely Fűtő return StringSwitch<std::string>(FunctionName) 41f27c8ac8SGergely Fűtő .Case("strlen", "strnlen_s") 42f27c8ac8SGergely Fűtő .Case("wcslen", "wcsnlen_s") 43f27c8ac8SGergely Fűtő .Default((Twine{FunctionName} + "_s").str()); 44f27c8ac8SGergely Fűtő } 45f27c8ac8SGergely Fűtő 46f27c8ac8SGergely Fűtő static StringRef getReplacementFor(StringRef FunctionName, 47f27c8ac8SGergely Fűtő bool IsAnnexKAvailable) { 48f27c8ac8SGergely Fűtő if (IsAnnexKAvailable) { 49f27c8ac8SGergely Fűtő // Try to find a better replacement from Annex K first. 50f27c8ac8SGergely Fűtő StringRef AnnexKReplacementFunction = 51f27c8ac8SGergely Fűtő StringSwitch<StringRef>(FunctionName) 52f27c8ac8SGergely Fűtő .Cases("asctime", "asctime_r", "asctime_s") 53f27c8ac8SGergely Fűtő .Case("gets", "gets_s") 54f27c8ac8SGergely Fűtő .Default({}); 55f27c8ac8SGergely Fűtő if (!AnnexKReplacementFunction.empty()) 56f27c8ac8SGergely Fűtő return AnnexKReplacementFunction; 57f27c8ac8SGergely Fűtő } 58f27c8ac8SGergely Fűtő 59f27c8ac8SGergely Fűtő // FIXME: Some of these functions are available in C++ under "std::", and 60f27c8ac8SGergely Fűtő // should be matched and suggested. 61f27c8ac8SGergely Fűtő return StringSwitch<StringRef>(FunctionName) 62f27c8ac8SGergely Fűtő .Cases("asctime", "asctime_r", "strftime") 63f27c8ac8SGergely Fűtő .Case("gets", "fgets") 64f27c8ac8SGergely Fűtő .Case("rewind", "fseek") 65f27c8ac8SGergely Fűtő .Case("setbuf", "setvbuf"); 66f27c8ac8SGergely Fűtő } 67f27c8ac8SGergely Fűtő 68f27c8ac8SGergely Fűtő static StringRef getReplacementForAdditional(StringRef FunctionName, 69f27c8ac8SGergely Fűtő bool IsAnnexKAvailable) { 70f27c8ac8SGergely Fűtő if (IsAnnexKAvailable) { 71f27c8ac8SGergely Fűtő // Try to find a better replacement from Annex K first. 72f27c8ac8SGergely Fűtő StringRef AnnexKReplacementFunction = StringSwitch<StringRef>(FunctionName) 73f27c8ac8SGergely Fűtő .Case("bcopy", "memcpy_s") 74f27c8ac8SGergely Fűtő .Case("bzero", "memset_s") 75f27c8ac8SGergely Fűtő .Default({}); 76f27c8ac8SGergely Fűtő 77f27c8ac8SGergely Fűtő if (!AnnexKReplacementFunction.empty()) 78f27c8ac8SGergely Fűtő return AnnexKReplacementFunction; 79f27c8ac8SGergely Fűtő } 80f27c8ac8SGergely Fűtő 81f27c8ac8SGergely Fűtő return StringSwitch<StringRef>(FunctionName) 82f27c8ac8SGergely Fűtő .Case("bcmp", "memcmp") 83f27c8ac8SGergely Fűtő .Case("bcopy", "memcpy") 84f27c8ac8SGergely Fűtő .Case("bzero", "memset") 85f27c8ac8SGergely Fűtő .Case("getpw", "getpwuid") 86f27c8ac8SGergely Fűtő .Case("vfork", "posix_spawn"); 87f27c8ac8SGergely Fűtő } 88f27c8ac8SGergely Fűtő 89f27c8ac8SGergely Fűtő /// \returns The rationale for replacing the function \p FunctionName with the 90f27c8ac8SGergely Fűtő /// safer alternative. 91f27c8ac8SGergely Fűtő static StringRef getRationaleFor(StringRef FunctionName) { 92f27c8ac8SGergely Fűtő return StringSwitch<StringRef>(FunctionName) 93f27c8ac8SGergely Fűtő .Cases("asctime", "asctime_r", "ctime", 94f27c8ac8SGergely Fűtő "is not bounds-checking and non-reentrant") 95f27c8ac8SGergely Fűtő .Cases("bcmp", "bcopy", "bzero", "is deprecated") 96f27c8ac8SGergely Fűtő .Cases("fopen", "freopen", "has no exclusive access to the opened file") 97f27c8ac8SGergely Fűtő .Case("gets", "is insecure, was deprecated and removed in C11 and C++14") 98f27c8ac8SGergely Fűtő .Case("getpw", "is dangerous as it may overflow the provided buffer") 99f27c8ac8SGergely Fűtő .Cases("rewind", "setbuf", "has no error detection") 100f27c8ac8SGergely Fűtő .Case("vfork", "is insecure as it can lead to denial of service " 101f27c8ac8SGergely Fűtő "situations in the parent process") 102f27c8ac8SGergely Fűtő .Default("is not bounds-checking"); 103f27c8ac8SGergely Fűtő } 104f27c8ac8SGergely Fűtő 105f27c8ac8SGergely Fűtő /// Calculates whether Annex K is available for the current translation unit 106f27c8ac8SGergely Fűtő /// based on the macro definitions and the language options. 107f27c8ac8SGergely Fűtő /// 108f27c8ac8SGergely Fűtő /// The result is cached and saved in \p CacheVar. 109f27c8ac8SGergely Fűtő static bool isAnnexKAvailable(std::optional<bool> &CacheVar, Preprocessor *PP, 110f27c8ac8SGergely Fűtő const LangOptions &LO) { 111f27c8ac8SGergely Fűtő if (CacheVar.has_value()) 112f27c8ac8SGergely Fűtő return *CacheVar; 113f27c8ac8SGergely Fűtő 114f27c8ac8SGergely Fűtő if (!LO.C11) 115f27c8ac8SGergely Fűtő // TODO: How is "Annex K" available in C++ mode? 116f27c8ac8SGergely Fűtő return (CacheVar = false).value(); 117f27c8ac8SGergely Fűtő 118f27c8ac8SGergely Fűtő assert(PP && "No Preprocessor registered."); 119f27c8ac8SGergely Fűtő 120f27c8ac8SGergely Fűtő if (!PP->isMacroDefined("__STDC_LIB_EXT1__") || 121f27c8ac8SGergely Fűtő !PP->isMacroDefined("__STDC_WANT_LIB_EXT1__")) 122f27c8ac8SGergely Fűtő return (CacheVar = false).value(); 123f27c8ac8SGergely Fűtő 124f27c8ac8SGergely Fűtő const auto *MI = 125f27c8ac8SGergely Fűtő PP->getMacroInfo(PP->getIdentifierInfo("__STDC_WANT_LIB_EXT1__")); 126f27c8ac8SGergely Fűtő if (!MI || MI->tokens_empty()) 127f27c8ac8SGergely Fűtő return (CacheVar = false).value(); 128f27c8ac8SGergely Fűtő 129f27c8ac8SGergely Fűtő const Token &T = MI->tokens().back(); 130f27c8ac8SGergely Fűtő if (!T.isLiteral() || !T.getLiteralData()) 131f27c8ac8SGergely Fűtő return (CacheVar = false).value(); 132f27c8ac8SGergely Fűtő 133f27c8ac8SGergely Fűtő CacheVar = StringRef(T.getLiteralData(), T.getLength()) == "1"; 134f27c8ac8SGergely Fűtő return CacheVar.value(); 135f27c8ac8SGergely Fűtő } 136f27c8ac8SGergely Fűtő 137*0b8866d1SDiscookie static std::vector<UnsafeFunctionsCheck::CheckedFunction> 138*0b8866d1SDiscookie parseCheckedFunctions(StringRef Option, ClangTidyContext *Context) { 139*0b8866d1SDiscookie const std::vector<StringRef> Functions = 140*0b8866d1SDiscookie utils::options::parseStringList(Option); 141*0b8866d1SDiscookie std::vector<UnsafeFunctionsCheck::CheckedFunction> Result; 142*0b8866d1SDiscookie Result.reserve(Functions.size()); 143*0b8866d1SDiscookie 144*0b8866d1SDiscookie for (StringRef Function : Functions) { 145*0b8866d1SDiscookie if (Function.empty()) 146*0b8866d1SDiscookie continue; 147*0b8866d1SDiscookie 148*0b8866d1SDiscookie const auto [Name, Rest] = Function.split(','); 149*0b8866d1SDiscookie const auto [Replacement, Reason] = Rest.split(','); 150*0b8866d1SDiscookie 151*0b8866d1SDiscookie if (Name.trim().empty()) { 152*0b8866d1SDiscookie Context->configurationDiag("invalid configuration value for option '%0'; " 153*0b8866d1SDiscookie "expected the name of an unsafe function") 154*0b8866d1SDiscookie << OptionNameCustomFunctions; 155*0b8866d1SDiscookie continue; 156*0b8866d1SDiscookie } 157*0b8866d1SDiscookie 158*0b8866d1SDiscookie Result.push_back( 159*0b8866d1SDiscookie {Name.trim().str(), 160*0b8866d1SDiscookie matchers::MatchesAnyListedNameMatcher::NameMatcher(Name.trim()), 161*0b8866d1SDiscookie Replacement.trim().str(), Reason.trim().str()}); 162*0b8866d1SDiscookie } 163*0b8866d1SDiscookie 164*0b8866d1SDiscookie return Result; 165*0b8866d1SDiscookie } 166*0b8866d1SDiscookie 167*0b8866d1SDiscookie static std::string serializeCheckedFunctions( 168*0b8866d1SDiscookie const std::vector<UnsafeFunctionsCheck::CheckedFunction> &Functions) { 169*0b8866d1SDiscookie std::vector<std::string> Result; 170*0b8866d1SDiscookie Result.reserve(Functions.size()); 171*0b8866d1SDiscookie 172*0b8866d1SDiscookie for (const auto &Entry : Functions) { 173*0b8866d1SDiscookie if (Entry.Reason.empty()) 174*0b8866d1SDiscookie Result.push_back(Entry.Name + "," + Entry.Replacement); 175*0b8866d1SDiscookie else 176*0b8866d1SDiscookie Result.push_back(Entry.Name + "," + Entry.Replacement + "," + 177*0b8866d1SDiscookie Entry.Reason); 178*0b8866d1SDiscookie } 179*0b8866d1SDiscookie 180*0b8866d1SDiscookie return llvm::join(Result, ";"); 181*0b8866d1SDiscookie } 182*0b8866d1SDiscookie 183f27c8ac8SGergely Fűtő UnsafeFunctionsCheck::UnsafeFunctionsCheck(StringRef Name, 184f27c8ac8SGergely Fűtő ClangTidyContext *Context) 185f27c8ac8SGergely Fűtő : ClangTidyCheck(Name, Context), 186*0b8866d1SDiscookie CustomFunctions(parseCheckedFunctions( 187*0b8866d1SDiscookie Options.get(OptionNameCustomFunctions, ""), Context)), 188*0b8866d1SDiscookie ReportDefaultFunctions( 189*0b8866d1SDiscookie Options.get(OptionNameReportDefaultFunctions, true)), 190f27c8ac8SGergely Fűtő ReportMoreUnsafeFunctions( 191f27c8ac8SGergely Fűtő Options.get(OptionNameReportMoreUnsafeFunctions, true)) {} 192f27c8ac8SGergely Fűtő 193f27c8ac8SGergely Fűtő void UnsafeFunctionsCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) { 194*0b8866d1SDiscookie Options.store(Opts, OptionNameCustomFunctions, 195*0b8866d1SDiscookie serializeCheckedFunctions(CustomFunctions)); 196*0b8866d1SDiscookie Options.store(Opts, OptionNameReportDefaultFunctions, ReportDefaultFunctions); 197f27c8ac8SGergely Fűtő Options.store(Opts, OptionNameReportMoreUnsafeFunctions, 198f27c8ac8SGergely Fűtő ReportMoreUnsafeFunctions); 199f27c8ac8SGergely Fűtő } 200f27c8ac8SGergely Fűtő 201f27c8ac8SGergely Fűtő void UnsafeFunctionsCheck::registerMatchers(MatchFinder *Finder) { 202*0b8866d1SDiscookie if (ReportDefaultFunctions) { 203f27c8ac8SGergely Fűtő if (getLangOpts().C11) { 204f27c8ac8SGergely Fűtő // Matching functions with safe replacements only in Annex K. 205f27c8ac8SGergely Fűtő auto FunctionNamesWithAnnexKReplacementMatcher = hasAnyName( 206*0b8866d1SDiscookie "::bsearch", "::ctime", "::fopen", "::fprintf", "::freopen", 207*0b8866d1SDiscookie "::fscanf", "::fwprintf", "::fwscanf", "::getenv", "::gmtime", 208*0b8866d1SDiscookie "::localtime", "::mbsrtowcs", "::mbstowcs", "::memcpy", "::memmove", 209*0b8866d1SDiscookie "::memset", "::printf", "::qsort", "::scanf", "::snprintf", 210*0b8866d1SDiscookie "::sprintf", "::sscanf", "::strcat", "::strcpy", "::strerror", 211*0b8866d1SDiscookie "::strlen", "::strncat", "::strncpy", "::strtok", "::swprintf", 212*0b8866d1SDiscookie "::swscanf", "::vfprintf", "::vfscanf", "::vfwprintf", "::vfwscanf", 213*0b8866d1SDiscookie "::vprintf", "::vscanf", "::vsnprintf", "::vsprintf", "::vsscanf", 214*0b8866d1SDiscookie "::vswprintf", "::vswscanf", "::vwprintf", "::vwscanf", "::wcrtomb", 215*0b8866d1SDiscookie "::wcscat", "::wcscpy", "::wcslen", "::wcsncat", "::wcsncpy", 216*0b8866d1SDiscookie "::wcsrtombs", "::wcstok", "::wcstombs", "::wctomb", "::wmemcpy", 217*0b8866d1SDiscookie "::wmemmove", "::wprintf", "::wscanf"); 218f27c8ac8SGergely Fűtő Finder->addMatcher( 219f27c8ac8SGergely Fűtő declRefExpr(to(functionDecl(FunctionNamesWithAnnexKReplacementMatcher) 220f27c8ac8SGergely Fűtő .bind(FunctionNamesWithAnnexKReplacementId))) 221f27c8ac8SGergely Fűtő .bind(DeclRefId), 222f27c8ac8SGergely Fűtő this); 223f27c8ac8SGergely Fűtő } 224f27c8ac8SGergely Fűtő 225f27c8ac8SGergely Fűtő // Matching functions with replacements without Annex K. 226f27c8ac8SGergely Fűtő auto FunctionNamesMatcher = 227f27c8ac8SGergely Fűtő hasAnyName("::asctime", "asctime_r", "::gets", "::rewind", "::setbuf"); 228f27c8ac8SGergely Fűtő Finder->addMatcher( 229*0b8866d1SDiscookie declRefExpr( 230*0b8866d1SDiscookie to(functionDecl(FunctionNamesMatcher).bind(FunctionNamesId))) 231f27c8ac8SGergely Fűtő .bind(DeclRefId), 232f27c8ac8SGergely Fűtő this); 233f27c8ac8SGergely Fűtő 234f27c8ac8SGergely Fűtő if (ReportMoreUnsafeFunctions) { 235f27c8ac8SGergely Fűtő // Matching functions with replacements without Annex K, at user request. 236f27c8ac8SGergely Fűtő auto AdditionalFunctionNamesMatcher = 237f27c8ac8SGergely Fűtő hasAnyName("::bcmp", "::bcopy", "::bzero", "::getpw", "::vfork"); 238f27c8ac8SGergely Fűtő Finder->addMatcher( 239f27c8ac8SGergely Fűtő declRefExpr(to(functionDecl(AdditionalFunctionNamesMatcher) 240f27c8ac8SGergely Fűtő .bind(AdditionalFunctionNamesId))) 241f27c8ac8SGergely Fűtő .bind(DeclRefId), 242f27c8ac8SGergely Fűtő this); 243f27c8ac8SGergely Fűtő } 244f27c8ac8SGergely Fűtő } 245f27c8ac8SGergely Fűtő 246*0b8866d1SDiscookie if (!CustomFunctions.empty()) { 247*0b8866d1SDiscookie std::vector<llvm::StringRef> FunctionNames; 248*0b8866d1SDiscookie FunctionNames.reserve(CustomFunctions.size()); 249*0b8866d1SDiscookie 250*0b8866d1SDiscookie for (const auto &Entry : CustomFunctions) 251*0b8866d1SDiscookie FunctionNames.push_back(Entry.Name); 252*0b8866d1SDiscookie 253*0b8866d1SDiscookie auto CustomFunctionsMatcher = matchers::matchesAnyListedName(FunctionNames); 254*0b8866d1SDiscookie 255*0b8866d1SDiscookie Finder->addMatcher(declRefExpr(to(functionDecl(CustomFunctionsMatcher) 256*0b8866d1SDiscookie .bind(CustomFunctionNamesId))) 257*0b8866d1SDiscookie .bind(DeclRefId), 258*0b8866d1SDiscookie this); 259*0b8866d1SDiscookie } 260*0b8866d1SDiscookie } 261*0b8866d1SDiscookie 262f27c8ac8SGergely Fűtő void UnsafeFunctionsCheck::check(const MatchFinder::MatchResult &Result) { 263f27c8ac8SGergely Fűtő const auto *DeclRef = Result.Nodes.getNodeAs<DeclRefExpr>(DeclRefId); 264f27c8ac8SGergely Fűtő const auto *FuncDecl = cast<FunctionDecl>(DeclRef->getDecl()); 265f27c8ac8SGergely Fűtő assert(DeclRef && FuncDecl && "No valid matched node in check()"); 266f27c8ac8SGergely Fűtő 267*0b8866d1SDiscookie // Only one of these are matched at a time. 268f27c8ac8SGergely Fűtő const auto *AnnexK = Result.Nodes.getNodeAs<FunctionDecl>( 269f27c8ac8SGergely Fűtő FunctionNamesWithAnnexKReplacementId); 270f27c8ac8SGergely Fűtő const auto *Normal = Result.Nodes.getNodeAs<FunctionDecl>(FunctionNamesId); 271f27c8ac8SGergely Fűtő const auto *Additional = 272f27c8ac8SGergely Fűtő Result.Nodes.getNodeAs<FunctionDecl>(AdditionalFunctionNamesId); 273*0b8866d1SDiscookie const auto *Custom = 274*0b8866d1SDiscookie Result.Nodes.getNodeAs<FunctionDecl>(CustomFunctionNamesId); 275*0b8866d1SDiscookie assert((AnnexK || Normal || Additional || Custom) && 276*0b8866d1SDiscookie "No valid match category."); 277f27c8ac8SGergely Fűtő 278f27c8ac8SGergely Fűtő bool AnnexKIsAvailable = 279f27c8ac8SGergely Fűtő isAnnexKAvailable(IsAnnexKAvailable, PP, getLangOpts()); 280f27c8ac8SGergely Fűtő StringRef FunctionName = FuncDecl->getName(); 281*0b8866d1SDiscookie 282*0b8866d1SDiscookie if (Custom) { 283*0b8866d1SDiscookie for (const auto &Entry : CustomFunctions) { 284*0b8866d1SDiscookie if (Entry.Pattern.match(*FuncDecl)) { 285*0b8866d1SDiscookie StringRef Reason = 286*0b8866d1SDiscookie Entry.Reason.empty() ? "is marked as unsafe" : Entry.Reason.c_str(); 287*0b8866d1SDiscookie 288*0b8866d1SDiscookie if (Entry.Replacement.empty()) { 289*0b8866d1SDiscookie diag(DeclRef->getExprLoc(), "function %0 %1; it should not be used") 290*0b8866d1SDiscookie << FuncDecl << Reason << Entry.Replacement 291*0b8866d1SDiscookie << DeclRef->getSourceRange(); 292*0b8866d1SDiscookie } else { 293*0b8866d1SDiscookie diag(DeclRef->getExprLoc(), 294*0b8866d1SDiscookie "function %0 %1; '%2' should be used instead") 295*0b8866d1SDiscookie << FuncDecl << Reason << Entry.Replacement 296*0b8866d1SDiscookie << DeclRef->getSourceRange(); 297*0b8866d1SDiscookie } 298*0b8866d1SDiscookie 299*0b8866d1SDiscookie return; 300*0b8866d1SDiscookie } 301*0b8866d1SDiscookie } 302*0b8866d1SDiscookie 303*0b8866d1SDiscookie llvm_unreachable("No custom function was matched."); 304*0b8866d1SDiscookie return; 305*0b8866d1SDiscookie } 306*0b8866d1SDiscookie 307f27c8ac8SGergely Fűtő const std::optional<std::string> ReplacementFunctionName = 308f27c8ac8SGergely Fűtő [&]() -> std::optional<std::string> { 309f27c8ac8SGergely Fűtő if (AnnexK) { 310f27c8ac8SGergely Fűtő if (AnnexKIsAvailable) 311f27c8ac8SGergely Fűtő return getAnnexKReplacementFor(FunctionName); 312f27c8ac8SGergely Fűtő return std::nullopt; 313f27c8ac8SGergely Fűtő } 314f27c8ac8SGergely Fűtő 315f27c8ac8SGergely Fűtő if (Normal) 316f27c8ac8SGergely Fűtő return getReplacementFor(FunctionName, AnnexKIsAvailable).str(); 317f27c8ac8SGergely Fűtő 318f27c8ac8SGergely Fűtő if (Additional) 319f27c8ac8SGergely Fűtő return getReplacementForAdditional(FunctionName, AnnexKIsAvailable).str(); 320f27c8ac8SGergely Fűtő 321f27c8ac8SGergely Fűtő llvm_unreachable("Unhandled match category"); 322f27c8ac8SGergely Fűtő }(); 323f27c8ac8SGergely Fűtő if (!ReplacementFunctionName) 324f27c8ac8SGergely Fűtő return; 325f27c8ac8SGergely Fűtő 326f27c8ac8SGergely Fűtő diag(DeclRef->getExprLoc(), "function %0 %1; '%2' should be used instead") 327f27c8ac8SGergely Fűtő << FuncDecl << getRationaleFor(FunctionName) 328f27c8ac8SGergely Fűtő << ReplacementFunctionName.value() << DeclRef->getSourceRange(); 329f27c8ac8SGergely Fűtő } 330f27c8ac8SGergely Fűtő 331f27c8ac8SGergely Fűtő void UnsafeFunctionsCheck::registerPPCallbacks( 332f27c8ac8SGergely Fűtő const SourceManager &SM, Preprocessor *PP, 333f27c8ac8SGergely Fűtő Preprocessor * /*ModuleExpanderPP*/) { 334f27c8ac8SGergely Fűtő this->PP = PP; 3359225d08cSWhisperity } 3369225d08cSWhisperity 3379225d08cSWhisperity void UnsafeFunctionsCheck::onEndOfTranslationUnit() { 3389225d08cSWhisperity this->PP = nullptr; 339f27c8ac8SGergely Fűtő IsAnnexKAvailable.reset(); 340f27c8ac8SGergely Fűtő } 341f27c8ac8SGergely Fűtő 342d57cf05fSPiotr Zegar } // namespace clang::tidy::bugprone 343