diff --git a/clang/include/clang/Analysis/Analyses/UnsafeBufferUsage.h b/clang/include/clang/Analysis/Analyses/UnsafeBufferUsage.h index 92b831187c54d..617bc7c77c565 100644 --- a/clang/include/clang/Analysis/Analyses/UnsafeBufferUsage.h +++ b/clang/include/clang/Analysis/Analyses/UnsafeBufferUsage.h @@ -16,10 +16,8 @@ #include "clang/AST/Decl.h" #include "clang/AST/Stmt.h" -#include "clang/Sema/Sema.h" namespace clang { -class Sema; using DefMapTy = llvm::DenseMap>; @@ -47,12 +45,21 @@ class UnsafeBufferUsageHandler { /// Returns a reference to the `Preprocessor`: virtual bool isSafeBufferOptOut(const SourceLocation &Loc) const = 0; + + /// Returns the text indicating that the user needs to provide input there: + virtual std::string + getUserFillPlaceHolder(StringRef HintTextToUser = "placeholder") const { + std::string s = std::string("<# "); + s += HintTextToUser; + s += " #>"; + return s; + } }; // This function invokes the analysis and allows the caller to react to it // through the handler class. void checkUnsafeBufferUsage(const Decl *D, UnsafeBufferUsageHandler &Handler, - bool EmitSuggestions, Sema &Sema); + bool EmitSuggestions); namespace internal { // Tests if any two `FixItHint`s in `FixIts` conflict. Two `FixItHint`s diff --git a/clang/lib/Analysis/UnsafeBufferUsage.cpp b/clang/lib/Analysis/UnsafeBufferUsage.cpp index e0b22cff9df38..539bf389b7dd9 100644 --- a/clang/lib/Analysis/UnsafeBufferUsage.cpp +++ b/clang/lib/Analysis/UnsafeBufferUsage.cpp @@ -1290,14 +1290,6 @@ static StringRef getEndOfLine() { return EOL; } -// Returns the text indicating that the user needs to provide input there: -std::string getUserFillPlaceHolder(StringRef HintTextToUser = "placeholder") { - std::string s = std::string("<# "); - s += HintTextToUser; - s += " #>"; - return s; -} - // Return the text representation of the given `APInt Val`: static std::string getAPIntText(APInt Val) { SmallVector Txt; @@ -1764,28 +1756,11 @@ static bool hasConflictingOverload(const FunctionDecl *FD) { } // Returns the text representation of clang::unsafe_buffer_usage attribute. -// `WSSuffix` holds customized "white-space"s, e.g., newline or whilespace -// characters. -static std::string -getUnsafeBufferUsageAttributeTextAt(SourceLocation Loc, Sema &S, - StringRef WSSuffix = "") { - Preprocessor &PP = S.getPreprocessor(); - TokenValue ClangUnsafeBufferUsageTokens[] = { - tok::l_square, - tok::l_square, - PP.getIdentifierInfo("clang"), - tok::coloncolon, - PP.getIdentifierInfo("unsafe_buffer_usage"), - tok::r_square, - tok::r_square}; - - StringRef MacroName; - - // The returned macro (it returns) is guaranteed not to be function-like: - MacroName = PP.getLastMacroWithSpelling(Loc, ClangUnsafeBufferUsageTokens); - if (MacroName.empty()) - MacroName = "[[clang::unsafe_buffer_usage]]"; - return MacroName.str() + WSSuffix.str(); +static std::string getUnsafeBufferUsageAttributeText() { + static const char *const RawAttr = "[[clang::unsafe_buffer_usage]]"; + std::stringstream SS; + SS << RawAttr << getEndOfLine().str(); + return SS.str(); } // For a `FunDecl`, one of whose `ParmVarDecl`s is being changed to have a new @@ -1830,11 +1805,11 @@ getUnsafeBufferUsageAttributeTextAt(SourceLocation Loc, Sema &S, static std::optional createOverloadsForFixedParams(unsigned ParmIdx, StringRef NewTyText, const FunctionDecl *FD, const ASTContext &Ctx, - UnsafeBufferUsageHandler &Handler, Sema &Sema) { + UnsafeBufferUsageHandler &Handler) { // FIXME: need to make this conflict checking better: if (hasConflictingOverload(FD)) return std::nullopt; - + const SourceManager &SM = Ctx.getSourceManager(); const LangOptions &LangOpts = Ctx.getLangOpts(); // FIXME Respect indentation of the original code. @@ -1884,7 +1859,7 @@ createOverloadsForFixedParams(unsigned ParmIdx, StringRef NewTyText, // A lambda that creates the text representation of a function definition with // the original signature: const auto OldOverloadDefCreator = - [&SM, &Sema, + [&Handler, &SM, &LangOpts](const FunctionDecl *FD, unsigned ParmIdx, StringRef NewTypeText) -> std::optional { std::stringstream SS; @@ -1894,8 +1869,7 @@ createOverloadsForFixedParams(unsigned ParmIdx, StringRef NewTyText, if (auto FDPrefix = getRangeText( SourceRange(FD->getBeginLoc(), FD->getBody()->getBeginLoc()), SM, LangOpts)) - SS << getUnsafeBufferUsageAttributeTextAt(FD->getBeginLoc(), Sema, " ") - << FDPrefix->str() << "{"; + SS << getUnsafeBufferUsageAttributeText() << FDPrefix->str() << "{"; else return std::nullopt; // Append: "return" func-name "(" @@ -1916,7 +1890,7 @@ createOverloadsForFixedParams(unsigned ParmIdx, StringRef NewTyText, if (i == ParmIdx) // This is our spanified paramter! SS << NewTypeText.str() << "(" << Parm->getIdentifier()->getName().str() << ", " - << getUserFillPlaceHolder("size") << ")"; + << Handler.getUserFillPlaceHolder("size") << ")"; else SS << Parm->getIdentifier()->getName().str(); if (i != NumParms - 1) @@ -1947,8 +1921,7 @@ createOverloadsForFixedParams(unsigned ParmIdx, StringRef NewTyText, // Adds the unsafe-buffer attribute (if not already there) to `FReDecl`: if (!FReDecl->hasAttr()) { FixIts.emplace_back(FixItHint::CreateInsertion( - FReDecl->getBeginLoc(), getUnsafeBufferUsageAttributeTextAt( - FReDecl->getBeginLoc(), Sema, " "))); + FReDecl->getBeginLoc(), getUnsafeBufferUsageAttributeText())); } // Inserts a declaration with the new signature to the end of `FReDecl`: if (auto NewOverloadDecl = @@ -1965,7 +1938,7 @@ createOverloadsForFixedParams(unsigned ParmIdx, StringRef NewTyText, // new overload of the function so that the change is self-contained (see // `createOverloadsForFixedParams`). static FixItList fixParamWithSpan(const ParmVarDecl *PVD, const ASTContext &Ctx, - UnsafeBufferUsageHandler &Handler, Sema &Sema) { + UnsafeBufferUsageHandler &Handler) { if (PVD->hasDefaultArg()) // FIXME: generate fix-its for default values: return {}; @@ -2017,7 +1990,7 @@ static FixItList fixParamWithSpan(const ParmVarDecl *PVD, const ASTContext &Ctx, } if (ParmIdx < FD->getNumParams()) if (auto OverloadFix = createOverloadsForFixedParams(ParmIdx, SpanTyText, - FD, Ctx, Handler, Sema)) { + FD, Ctx, Handler)) { Fixes.append(*OverloadFix); return Fixes; } @@ -2040,7 +2013,7 @@ static FixItList fixVariableWithSpan(const VarDecl *VD, (void)DS; // FIXME: handle cases where DS has multiple declarations - return fixVarDeclWithSpan(VD, Ctx, getUserFillPlaceHolder()); + return fixVarDeclWithSpan(VD, Ctx, Handler.getUserFillPlaceHolder()); } // TODO: we should be consistent to use `std::nullopt` to represent no-fix due @@ -2049,7 +2022,7 @@ static FixItList fixVariable(const VarDecl *VD, Strategy::Kind K, /* The function decl under analysis */ const Decl *D, const DeclUseTracker &Tracker, ASTContext &Ctx, - UnsafeBufferUsageHandler &Handler, Sema &Sema) { + UnsafeBufferUsageHandler &Handler) { if (const auto *PVD = dyn_cast(VD)) { auto *FD = dyn_cast(PVD->getDeclContext()); if (!FD || FD != D) @@ -2076,7 +2049,7 @@ fixVariable(const VarDecl *VD, Strategy::Kind K, case Strategy::Kind::Span: { if (VD->getType()->isPointerType()) { if (const auto *PVD = dyn_cast(VD)) - return fixParamWithSpan(PVD, Ctx, Handler, Sema); + return fixParamWithSpan(PVD, Ctx, Handler); if (VD->isLocalVarDecl()) return fixVariableWithSpan(VD, Tracker, Ctx, Handler); @@ -2124,11 +2097,11 @@ getFixIts(FixableGadgetSets &FixablesForAllVars, const Strategy &S, ASTContext &Ctx, /* The function decl under analysis */ const Decl *D, const DeclUseTracker &Tracker, UnsafeBufferUsageHandler &Handler, - const DefMapTy &VarGrpMap, Sema &Sema) { + const DefMapTy &VarGrpMap) { std::map FixItsForVariable; for (const auto &[VD, Fixables] : FixablesForAllVars.byVar) { FixItsForVariable[VD] = - fixVariable(VD, S.lookup(VD), D, Tracker, Ctx, Handler, Sema); + fixVariable(VD, S.lookup(VD), D, Tracker, Ctx, Handler); // If we fail to produce Fix-It for the declaration we have to skip the // variable entirely. if (FixItsForVariable[VD].empty()) { @@ -2198,7 +2171,7 @@ getFixIts(FixableGadgetSets &FixablesForAllVars, const Strategy &S, FixItList GroupFix; if (FixItsForVariable.find(Var) == FixItsForVariable.end()) { GroupFix = fixVariable(Var, ReplacementTypeForVD, D, - Tracker, Var->getASTContext(), Handler, Sema); + Tracker, Var->getASTContext(), Handler); } else { GroupFix = FixItsForVariable[Var]; } @@ -2224,7 +2197,7 @@ getNaiveStrategy(const llvm::SmallVectorImpl &UnsafeVars) { void clang::checkUnsafeBufferUsage(const Decl *D, UnsafeBufferUsageHandler &Handler, - bool EmitSuggestions, Sema &Sema) { + bool EmitSuggestions) { assert(D && D->getBody()); // Do not emit fixit suggestions for functions declared in an @@ -2370,7 +2343,7 @@ void clang::checkUnsafeBufferUsage(const Decl *D, FixItsForVariableGroup = getFixIts(FixablesForAllVars, NaiveStrategy, D->getASTContext(), D, - Tracker, Handler, VariableGroupsMap, Sema); + Tracker, Handler, VariableGroupsMap); // FIXME Detect overlapping FixIts. diff --git a/clang/lib/Sema/AnalysisBasedWarnings.cpp b/clang/lib/Sema/AnalysisBasedWarnings.cpp index dd7a7d3643ded..de0feaa125f25 100644 --- a/clang/lib/Sema/AnalysisBasedWarnings.cpp +++ b/clang/lib/Sema/AnalysisBasedWarnings.cpp @@ -2423,7 +2423,7 @@ void clang::sema::AnalysisBasedWarnings::IssueWarnings( !Diags.isIgnored(diag::warn_unsafe_buffer_variable, Node->getBeginLoc())) { clang::checkUnsafeBufferUsage(Node, R, - UnsafeBufferUsageShouldEmitSuggestions, S); + UnsafeBufferUsageShouldEmitSuggestions); } // More analysis ... diff --git a/clang/test/SemaCXX/warn-unsafe-buffer-usage-fixits-attributes-spelling.cpp b/clang/test/SemaCXX/warn-unsafe-buffer-usage-fixits-attributes-spelling.cpp deleted file mode 100644 index 1b2f8bc9fa1b8..0000000000000 --- a/clang/test/SemaCXX/warn-unsafe-buffer-usage-fixits-attributes-spelling.cpp +++ /dev/null @@ -1,69 +0,0 @@ -// RUN: %clang_cc1 -std=c++20 -Wunsafe-buffer-usage -fdiagnostics-parseable-fixits -fsafe-buffer-usage-suggestions -DCMD_UNSAFE_ATTR=[[clang::unsafe_buffer_usage]] %s 2>&1 | FileCheck %s - - -// no need to check fix-its for definition in this test ... -void foo(int *p) { - int tmp = p[5]; -} - -// Will use the macro defined from the command line: -void foo(int *); -// CHECK: fix-it:{{.*}}:{[[@LINE-1]]:1-[[@LINE-1]]:1}:"CMD_UNSAFE_ATTR " -// CHECK: fix-it:{{.*}}:{[[@LINE-2]]:16-[[@LINE-2]]:16}:";\nvoid foo(std::span)" - - -#undef CMD_UNSAFE_ATTR -void foo(int *); -// CHECK: fix-it:{{.*}}:{[[@LINE-1]]:1-[[@LINE-1]]:1}:"{{\[}}{{\[}}clang::unsafe_buffer_usage{{\]}}{{\]}} " -// CHECK: fix-it:{{.*}}:{[[@LINE-2]]:16-[[@LINE-2]]:16}:";\nvoid foo(std::span)" - - -#define UNSAFE_ATTR [[clang::unsafe_buffer_usage]] - -void foo(int *); -// CHECK: fix-it:{{.*}}:{[[@LINE-1]]:1-[[@LINE-1]]:1}:"UNSAFE_ATTR " -// CHECK: fix-it:{{.*}}:{[[@LINE-2]]:16-[[@LINE-2]]:16}:";\nvoid foo(std::span)" - -#undef UNSAFE_ATTR - -#if __has_cpp_attribute(clang::unsafe_buffer_usage) -#define UNSAFE_ATTR [[clang::unsafe_buffer_usage]] -#endif - -void foo(int *); -// CHECK: fix-it:{{.*}}:{[[@LINE-1]]:1-[[@LINE-1]]:1}:"UNSAFE_ATTR " -// CHECK: fix-it:{{.*}}:{[[@LINE-2]]:16-[[@LINE-2]]:16}:";\nvoid foo(std::span)" - -#undef UNSAFE_ATTR - -#if __has_cpp_attribute(clang::unsafe_buffer_usage) -// we don't know how to use this macro -#define UNSAFE_ATTR(x) [[clang::unsafe_buffer_usage]] -#endif - -void foo(int *); -// CHECK: fix-it:{{.*}}:{[[@LINE-1]]:1-[[@LINE-1]]:1}:"{{\[}}{{\[}}clang::unsafe_buffer_usage{{\]}}{{\]}} " -// CHECK: fix-it:{{.*}}:{[[@LINE-2]]:16-[[@LINE-2]]:16}:";\nvoid foo(std::span)" - -#undef UNSAFE_ATTR - -#define UNSAFE_ATTR_1 [[clang::unsafe_buffer_usage]] -#define UNSAFE_ATTR_2 [[clang::unsafe_buffer_usage]] -#define UNSAFE_ATTR_3 [[clang::unsafe_buffer_usage]] - -// Should use the last defined macro (i.e., UNSAFE_ATTR_3) for -// `[[clang::unsafe_buffer_usage]]` -void foo(int *p); -// CHECK: fix-it:{{.*}}:{[[@LINE-1]]:1-[[@LINE-1]]:1}:"UNSAFE_ATTR_3 " -// CHECK: fix-it:{{.*}}:{[[@LINE-2]]:17-[[@LINE-2]]:17}:";\nvoid foo(std::span p)" - - -#define WRONG_ATTR_1 [clang::unsafe_buffer_usage]] -#define WRONG_ATTR_2 [[clang::unsafe_buffer_usage] -#define WRONG_ATTR_3 [[clang::unsafe_buffer_usag]] - -// The last defined macro for -// `[[clang::unsafe_buffer_usage]]` is still UNSAFE_ATTR_3 -void foo(int *p); -// CHECK: fix-it:{{.*}}:{[[@LINE-1]]:1-[[@LINE-1]]:1}:"UNSAFE_ATTR_3 " -// CHECK: fix-it:{{.*}}:{[[@LINE-2]]:17-[[@LINE-2]]:17}:";\nvoid foo(std::span p)" diff --git a/clang/test/SemaCXX/warn-unsafe-buffer-usage-fixits-parm-span-overload.cpp b/clang/test/SemaCXX/warn-unsafe-buffer-usage-fixits-parm-span-overload.cpp index e63ccfb77dd1e..3bc3f4e333499 100644 --- a/clang/test/SemaCXX/warn-unsafe-buffer-usage-fixits-parm-span-overload.cpp +++ b/clang/test/SemaCXX/warn-unsafe-buffer-usage-fixits-parm-span-overload.cpp @@ -46,11 +46,11 @@ namespace NS { int tmp; tmp = p[5]; } - // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:4-[[@LINE-1]]:4}:"\n{{\[}}{{\[}}clang::unsafe_buffer_usage{{\]}}{{\]}} void foo(int *p) {return foo(std::span(p, <# size #>));}\n" + // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:4-[[@LINE-1]]:4}:"\n{{\[}}{{\[}}clang::unsafe_buffer_usage{{\]}}{{\]}}\nvoid foo(int *p) {return foo(std::span(p, <# size #>));}\n" // Similarly, `NS::bar` is distinct from `bar`: void bar(int *p); - // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:3}:"{{\[}}{{\[}}clang::unsafe_buffer_usage{{\]}}{{\]}} " + // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:3}:"{{\[}}{{\[}}clang::unsafe_buffer_usage{{\]}}{{\]}}\n" // CHECK: fix-it:"{{.*}}":{[[@LINE-2]]:19-[[@LINE-2]]:19}:";\nvoid bar(std::span p)" } // end of namespace NS @@ -60,7 +60,7 @@ void NS::bar(int *p) { int tmp; tmp = p[5]; } -// CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:2-[[@LINE-1]]:2}:"\n{{\[}}{{\[}}clang::unsafe_buffer_usage{{\]}}{{\]}} void NS::bar(int *p) {return NS::bar(std::span(p, <# size #>));}\n" +// CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:2-[[@LINE-1]]:2}:"\n{{\[}}{{\[}}clang::unsafe_buffer_usage{{\]}}{{\]}}\nvoid NS::bar(int *p) {return NS::bar(std::span(p, <# size #>));}\n" namespace NESTED { void alpha(int); @@ -74,7 +74,7 @@ namespace NESTED { int tmp; tmp = p[5]; } - // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:6-[[@LINE-1]]:6}:"\n{{\[}}{{\[}}clang::unsafe_buffer_usage{{\]}}{{\]}} void alpha(int *p) {return alpha(std::span(p, <# size #>));}\n" + // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:6-[[@LINE-1]]:6}:"\n{{\[}}{{\[}}clang::unsafe_buffer_usage{{\]}}{{\]}}\nvoid alpha(int *p) {return alpha(std::span(p, <# size #>));}\n" } } diff --git a/clang/test/SemaCXX/warn-unsafe-buffer-usage-fixits-parm-span-qualified-names.cpp b/clang/test/SemaCXX/warn-unsafe-buffer-usage-fixits-parm-span-qualified-names.cpp index f07264915e562..5b68fc531d3a6 100644 --- a/clang/test/SemaCXX/warn-unsafe-buffer-usage-fixits-parm-span-qualified-names.cpp +++ b/clang/test/SemaCXX/warn-unsafe-buffer-usage-fixits-parm-span-qualified-names.cpp @@ -2,15 +2,15 @@ namespace NS1 { void foo(int *); - // CHECK-DAG: fix-it:{{.*}}:{[[@LINE-1]]:3-[[@LINE-1]]:3}:"{{\[}}{{\[}}clang::unsafe_buffer_usage{{\]}}{{\]}} " + // CHECK-DAG: fix-it:{{.*}}:{[[@LINE-1]]:3-[[@LINE-1]]:3}:"{{\[}}{{\[}}clang::unsafe_buffer_usage{{\]}}{{\]}}\n" // CHECK-DAG: fix-it:"{{.*}}:{[[@LINE-2]]:18-[[@LINE-2]]:18}:";\nvoid foo(std::span)" namespace NS2 { void foo(int *); - // CHECK-DAG: fix-it:{{.*}}:{[[@LINE-1]]:5-[[@LINE-1]]:5}:"{{\[}}{{\[}}clang::unsafe_buffer_usage{{\]}}{{\]}} " + // CHECK-DAG: fix-it:{{.*}}:{[[@LINE-1]]:5-[[@LINE-1]]:5}:"{{\[}}{{\[}}clang::unsafe_buffer_usage{{\]}}{{\]}}\n" // CHECK-DAG: fix-it:"{{.*}}:{[[@LINE-2]]:20-[[@LINE-2]]:20}:";\nvoid foo(std::span)" namespace NS3 { void foo(int *); - // CHECK-DAG: fix-it:{{.*}}:{[[@LINE-1]]:7-[[@LINE-1]]:7}:"{{\[}}{{\[}}clang::unsafe_buffer_usage{{\]}}{{\]}} " + // CHECK-DAG: fix-it:{{.*}}:{[[@LINE-1]]:7-[[@LINE-1]]:7}:"{{\[}}{{\[}}clang::unsafe_buffer_usage{{\]}}{{\]}}\n" // CHECK-DAG: fix-it:"{{.*}}:{[[@LINE-2]]:22-[[@LINE-2]]:22}:";\nvoid foo(std::span)" } } @@ -23,21 +23,21 @@ void NS1::foo(int *p) { int tmp; tmp = p[5]; } -// CHECK-DAG: fix-it:{{.*}}:{[[@LINE-1]]:2-[[@LINE-1]]:2}:"\n{{\[}}{{\[}}clang::unsafe_buffer_usage{{\]}}{{\]}} void NS1::foo(int *p) {return NS1::foo(std::span(p, <# size #>));}\n" +// CHECK-DAG: fix-it:{{.*}}:{[[@LINE-1]]:2-[[@LINE-1]]:2}:"\n{{\[}}{{\[}}clang::unsafe_buffer_usage{{\]}}{{\]}}\nvoid NS1::foo(int *p) {return NS1::foo(std::span(p, <# size #>));}\n" void NS1::NS2::foo(int *p) { // CHECK-DAG: fix-it:{{.*}}:{[[@LINE-1]]:20-[[@LINE-1]]:26}:"std::span p" int tmp; tmp = p[5]; } -// CHECK-DAG: fix-it:{{.*}}:{[[@LINE-1]]:2-[[@LINE-1]]:2}:"\n{{\[}}{{\[}}clang::unsafe_buffer_usage{{\]}}{{\]}} void NS1::NS2::foo(int *p) {return NS1::NS2::foo(std::span(p, <# size #>));}\n" +// CHECK-DAG: fix-it:{{.*}}:{[[@LINE-1]]:2-[[@LINE-1]]:2}:"\n{{\[}}{{\[}}clang::unsafe_buffer_usage{{\]}}{{\]}}\nvoid NS1::NS2::foo(int *p) {return NS1::NS2::foo(std::span(p, <# size #>));}\n" void NS1::NS2::NS3::foo(int *p) { // CHECK-DAG: fix-it:{{.*}}:{[[@LINE-1]]:25-[[@LINE-1]]:31}:"std::span p" int tmp; tmp = p[5]; } -// CHECK-DAG: fix-it:{{.*}}:{[[@LINE-1]]:2-[[@LINE-1]]:2}:"\n{{\[}}{{\[}}clang::unsafe_buffer_usage{{\]}}{{\]}} void NS1::NS2::NS3::foo(int *p) {return NS1::NS2::NS3::foo(std::span(p, <# size #>));}\n" +// CHECK-DAG: fix-it:{{.*}}:{[[@LINE-1]]:2-[[@LINE-1]]:2}:"\n{{\[}}{{\[}}clang::unsafe_buffer_usage{{\]}}{{\]}}\nvoid NS1::NS2::NS3::foo(int *p) {return NS1::NS2::NS3::foo(std::span(p, <# size #>));}\n" void f(NS1::MyType * x) { @@ -45,4 +45,4 @@ void f(NS1::MyType * x) { NS1::MyType tmp; tmp = x[5]; } -// CHECK: fix-it:{{.*}}:{[[@LINE-1]]:2-[[@LINE-1]]:2}:"\n{{\[}}{{\[}}clang::unsafe_buffer_usage{{\]}}{{\]}} void f(NS1::MyType * x) {return f(std::span(x, <# size #>));}\n" +// CHECK: fix-it:{{.*}}:{[[@LINE-1]]:2-[[@LINE-1]]:2}:"\n{{\[}}{{\[}}clang::unsafe_buffer_usage{{\]}}{{\]}}\nvoid f(NS1::MyType * x) {return f(std::span(x, <# size #>));}\n" diff --git a/clang/test/SemaCXX/warn-unsafe-buffer-usage-fixits-parm-span.cpp b/clang/test/SemaCXX/warn-unsafe-buffer-usage-fixits-parm-span.cpp index cef6afd5933b3..bb9deecaefec4 100644 --- a/clang/test/SemaCXX/warn-unsafe-buffer-usage-fixits-parm-span.cpp +++ b/clang/test/SemaCXX/warn-unsafe-buffer-usage-fixits-parm-span.cpp @@ -6,13 +6,13 @@ #define INCLUDE_ME void simple(int *p); -// CHECK-DAG: fix-it:{{.*}}:{[[@LINE-1]]:1-[[@LINE-1]]:1}:"{{\[}}{{\[}}clang::unsafe_buffer_usage{{\]}}{{\]}} " +// CHECK-DAG: fix-it:{{.*}}:{[[@LINE-1]]:1-[[@LINE-1]]:1}:"{{\[}}{{\[}}clang::unsafe_buffer_usage{{\]}}{{\]}}\n" // CHECK-DAG: fix-it:{{.*}}:{[[@LINE-2]]:20-[[@LINE-2]]:20}:";\nvoid simple(std::span p)" #else void simple(int *); -// CHECK-DAG: fix-it:{{.*}}:{[[@LINE-1]]:1-[[@LINE-1]]:1}:"{{\[}}{{\[}}clang::unsafe_buffer_usage{{\]}}{{\]}} " +// CHECK-DAG: fix-it:{{.*}}:{[[@LINE-1]]:1-[[@LINE-1]]:1}:"{{\[}}{{\[}}clang::unsafe_buffer_usage{{\]}}{{\]}}\n" // CHECK-DAG: fix-it:{{.*}}:{[[@LINE-2]]:19-[[@LINE-2]]:19}:";\nvoid simple(std::span)" void simple(int *p) { @@ -20,7 +20,7 @@ void simple(int *p) { int tmp; tmp = p[5]; } -// CHECK-DAG: fix-it:{{.*}}:{[[@LINE-1]]:2-[[@LINE-1]]:2}:"\n{{\[}}{{\[}}clang::unsafe_buffer_usage{{\]}}{{\]}} void simple(int *p) {return simple(std::span(p, <# size #>));}\n" +// CHECK-DAG: fix-it:{{.*}}:{[[@LINE-1]]:2-[[@LINE-1]]:2}:"\n{{\[}}{{\[}}clang::unsafe_buffer_usage{{\]}}{{\]}}\nvoid simple(int *p) {return simple(std::span(p, <# size #>));}\n" void twoParms(int *p, int * q) { @@ -29,14 +29,14 @@ void twoParms(int *p, int * q) { int tmp; tmp = p[5] + q[5]; } -// CHECK-DAG: fix-it:{{.*}}:{[[@LINE-1]]:2-[[@LINE-1]]:2}:"\n{{\[}}{{\[}}clang::unsafe_buffer_usage{{\]}}{{\]}} void twoParms(int *p, int * q) {return twoParms(std::span(p, <# size #>), q);}\n" -// CHECK-DAG: fix-it:{{.*}}:{[[@LINE-2]]:2-[[@LINE-2]]:2}:"\n{{\[}}{{\[}}clang::unsafe_buffer_usage{{\]}}{{\]}} void twoParms(int *p, int * q) {return twoParms(p, std::span(q, <# size #>));}\n" +// CHECK-DAG: fix-it:{{.*}}:{[[@LINE-1]]:2-[[@LINE-1]]:2}:"\n{{\[}}{{\[}}clang::unsafe_buffer_usage{{\]}}{{\]}}\nvoid twoParms(int *p, int * q) {return twoParms(std::span(p, <# size #>), q);}\n" +// CHECK-DAG: fix-it:{{.*}}:{[[@LINE-2]]:2-[[@LINE-2]]:2}:"\n{{\[}}{{\[}}clang::unsafe_buffer_usage{{\]}}{{\]}}\nvoid twoParms(int *p, int * q) {return twoParms(p, std::span(q, <# size #>));}\n" void ptrToConst(const int * x) { // CHECK-DAG: fix-it:{{.*}}:{[[@LINE-1]]:17-[[@LINE-1]]:30}:"std::span x" int tmp = x[5]; } -// CHECK-DAG: fix-it:{{.*}}:{[[@LINE-1]]:2-[[@LINE-1]]:2}:"\n{{\[}}{{\[}}clang::unsafe_buffer_usage{{\]}}{{\]}} void ptrToConst(const int * x) {return ptrToConst(std::span(x, <# size #>));}\n" +// CHECK-DAG: fix-it:{{.*}}:{[[@LINE-1]]:2-[[@LINE-1]]:2}:"\n{{\[}}{{\[}}clang::unsafe_buffer_usage{{\]}}{{\]}}\nvoid ptrToConst(const int * x) {return ptrToConst(std::span(x, <# size #>));}\n" // The followings test cases where multiple FileIDs maybe involved // when the analyzer loads characters from source files. @@ -50,7 +50,7 @@ void FUN_NAME(macro_defined_name)(int * x) { // CHECK-DAG: fix-it:{{.*}}:{[[@LINE-1]]:35-[[@LINE-1]]:42}:"std::span x" int tmp = x[5]; } -// CHECK-DAG: fix-it:{{.*}}:{[[@LINE-1]]:2-[[@LINE-1]]:2}:"\n{{\[}}{{\[}}clang::unsafe_buffer_usage{{\]}}{{\]}} void FUN_NAME(macro_defined_name)(int * x) {return FUN_NAME(macro_defined_name)(std::span(x, <# size #>));}\n" +// CHECK-DAG: fix-it:{{.*}}:{[[@LINE-1]]:2-[[@LINE-1]]:2}:"\n{{\[}}{{\[}}clang::unsafe_buffer_usage{{\]}}{{\]}}\nvoid FUN_NAME(macro_defined_name)(int * x) {return FUN_NAME(macro_defined_name)(std::span(x, <# size #>));}\n" // The followings test various type specifiers @@ -59,13 +59,13 @@ namespace { // CHECK-DAG: fix-it:{{.*}}:{[[@LINE-1]]:24-[[@LINE-1]]:49}:"std::span p" auto tmp = p[5]; } - // CHECK-DAG: fix-it:{{.*}}:{[[@LINE-1]]:4-[[@LINE-1]]:4}:"\n{{\[}}{{\[}}clang::unsafe_buffer_usage{{\]}}{{\]}} void simpleSpecifier(unsigned long long int *p) {return simpleSpecifier(std::span(p, <# size #>));}\n" + // CHECK-DAG: fix-it:{{.*}}:{[[@LINE-1]]:4-[[@LINE-1]]:4}:"\n{{\[}}{{\[}}clang::unsafe_buffer_usage{{\]}}{{\]}}\nvoid simpleSpecifier(unsigned long long int *p) {return simpleSpecifier(std::span(p, <# size #>));}\n" void attrParm([[maybe_unused]] int * p) { // CHECK-DAG: fix-it:{{.*}}:{[[@LINE-1]]:34-[[@LINE-1]]:41}:"std::span p" int tmp = p[5]; } - // CHECK-DAG: fix-it:{{.*}}:{[[@LINE-1]]:4-[[@LINE-1]]:4}:"\n{{\[}}{{\[}}clang::unsafe_buffer_usage{{\]}}{{\]}} void attrParm({{\[}}{{\[}}maybe_unused{{\]}}{{\]}} int * p) {return attrParm(std::span(p, <# size #>));}\n" + // CHECK-DAG: fix-it:{{.*}}:{[[@LINE-1]]:4-[[@LINE-1]]:4}:"\n{{\[}}{{\[}}clang::unsafe_buffer_usage{{\]}}{{\]}}\nvoid attrParm({{\[}}{{\[}}maybe_unused{{\]}}{{\]}} int * p) {return attrParm(std::span(p, <# size #>));}\n" using T = unsigned long long int; @@ -73,7 +73,7 @@ namespace { // CHECK-DAG: fix-it:{{.*}}:{[[@LINE-1]]:31-[[@LINE-1]]:36}:"std::span p" int tmp = p[5]; } - // CHECK-DAG: fix-it:{{.*}}:{[[@LINE-1]]:4-[[@LINE-1]]:4}:"\n{{\[}}{{\[}}clang::unsafe_buffer_usage{{\]}}{{\]}} void usingTypenameSpecifier(T * p) {return usingTypenameSpecifier(std::span(p, <# size #>));}\n" + // CHECK-DAG: fix-it:{{.*}}:{[[@LINE-1]]:4-[[@LINE-1]]:4}:"\n{{\[}}{{\[}}clang::unsafe_buffer_usage{{\]}}{{\]}}\nvoid usingTypenameSpecifier(T * p) {return usingTypenameSpecifier(std::span(p, <# size #>));}\n" typedef unsigned long long int T2; @@ -81,7 +81,7 @@ namespace { // CHECK-DAG: fix-it:{{.*}}:{[[@LINE-1]]:25-[[@LINE-1]]:31}:"std::span p" int tmp = p[5]; } - // CHECK-DAG: fix-it:{{.*}}:{[[@LINE-1]]:4-[[@LINE-1]]:4}:"\n{{\[}}{{\[}}clang::unsafe_buffer_usage{{\]}}{{\]}} void typedefSpecifier(T2 * p) {return typedefSpecifier(std::span(p, <# size #>));}\n" + // CHECK-DAG: fix-it:{{.*}}:{[[@LINE-1]]:4-[[@LINE-1]]:4}:"\n{{\[}}{{\[}}clang::unsafe_buffer_usage{{\]}}{{\]}}\nvoid typedefSpecifier(T2 * p) {return typedefSpecifier(std::span(p, <# size #>));}\n" class SomeClass { } C; @@ -90,7 +90,7 @@ namespace { // CHECK-DAG: fix-it:{{.*}}:{[[@LINE-1]]:27-[[@LINE-1]]:52}:"std::span p" if (++p) {} } - // CHECK-DAG: fix-it:{{.*}}:{[[@LINE-1]]:4-[[@LINE-1]]:4}:"\n{{\[}}{{\[}}clang::unsafe_buffer_usage{{\]}}{{\]}} void classTypeSpecifier(const class SomeClass * p) {return classTypeSpecifier(std::span(p, <# size #>));}\n" + // CHECK-DAG: fix-it:{{.*}}:{[[@LINE-1]]:4-[[@LINE-1]]:4}:"\n{{\[}}{{\[}}clang::unsafe_buffer_usage{{\]}}{{\]}}\nvoid classTypeSpecifier(const class SomeClass * p) {return classTypeSpecifier(std::span(p, <# size #>));}\n" struct { // anon @@ -113,9 +113,9 @@ namespace { if (++r) {} if (++rr) {} } - // CHECK-DAG: fix-it:{{.*}}:{[[@LINE-1]]:4-[[@LINE-1]]:4}:"\n{{\[}}{{\[}}clang::unsafe_buffer_usage{{\]}}{{\]}} void decltypeSpecifier(decltype(C) * p, decltype(ANON_S) * q, decltype(NAMED_S) * r,\n{{.*}}decltype(NAMED_S) ** rr) {return decltypeSpecifier(std::span(p, <# size #>), q, r, rr);}\n - // CHECK-DAG: fix-it:{{.*}}:{[[@LINE-2]]:4-[[@LINE-2]]:4}:"\n{{\[}}{{\[}}clang::unsafe_buffer_usage{{\]}}{{\]}} void decltypeSpecifier(decltype(C) * p, decltype(ANON_S) * q, decltype(NAMED_S) * r,\n{{.*}}decltype(NAMED_S) ** rr) {return decltypeSpecifier(p, q, std::span(r, <# size #>), rr);}\n" - // CHECK-DAG: fix-it:{{.*}}:{[[@LINE-3]]:4-[[@LINE-3]]:4}:"\n{{\[}}{{\[}}clang::unsafe_buffer_usage{{\]}}{{\]}} void decltypeSpecifier(decltype(C) * p, decltype(ANON_S) * q, decltype(NAMED_S) * r,\n{{.*}}decltype(NAMED_S) ** rr) {return decltypeSpecifier(p, q, r, std::span(rr, <# size #>));}\n" + // CHECK-DAG: fix-it:{{.*}}:{[[@LINE-1]]:4-[[@LINE-1]]:4}:"\n{{\[}}{{\[}}clang::unsafe_buffer_usage{{\]}}{{\]}}\nvoid decltypeSpecifier(decltype(C) * p, decltype(ANON_S) * q, decltype(NAMED_S) * r,\n{{.*}}decltype(NAMED_S) ** rr) {return decltypeSpecifier(std::span(p, <# size #>), q, r, rr);}\n + // CHECK-DAG: fix-it:{{.*}}:{[[@LINE-2]]:4-[[@LINE-2]]:4}:"\n{{\[}}{{\[}}clang::unsafe_buffer_usage{{\]}}{{\]}}\nvoid decltypeSpecifier(decltype(C) * p, decltype(ANON_S) * q, decltype(NAMED_S) * r,\n{{.*}}decltype(NAMED_S) ** rr) {return decltypeSpecifier(p, q, std::span(r, <# size #>), rr);}\n" + // CHECK-DAG: fix-it:{{.*}}:{[[@LINE-3]]:4-[[@LINE-3]]:4}:"\n{{\[}}{{\[}}clang::unsafe_buffer_usage{{\]}}{{\]}}\nvoid decltypeSpecifier(decltype(C) * p, decltype(ANON_S) * q, decltype(NAMED_S) * r,\n{{.*}}decltype(NAMED_S) ** rr) {return decltypeSpecifier(p, q, r, std::span(rr, <# size #>));}\n" #define MACRO_TYPE(T) long T @@ -125,8 +125,8 @@ namespace { int tmp = p[5]; tmp = q[5]; } - // CHECK-DAG: fix-it:{{.*}}:{[[@LINE-1]]:4-[[@LINE-1]]:4}:"\n{{\[}}{{\[}}clang::unsafe_buffer_usage{{\]}}{{\]}} void macroType(unsigned MACRO_TYPE(int) * p, unsigned MACRO_TYPE(long) * q) {return macroType(std::span(p, <# size #>), q);}\n" - // CHECK-DAG: fix-it:{{.*}}:{[[@LINE-2]]:4-[[@LINE-2]]:4}:"\n{{\[}}{{\[}}clang::unsafe_buffer_usage{{\]}}{{\]}} void macroType(unsigned MACRO_TYPE(int) * p, unsigned MACRO_TYPE(long) * q) {return macroType(p, std::span(q, <# size #>));}\n" + // CHECK-DAG: fix-it:{{.*}}:{[[@LINE-1]]:4-[[@LINE-1]]:4}:"\n{{\[}}{{\[}}clang::unsafe_buffer_usage{{\]}}{{\]}}\nvoid macroType(unsigned MACRO_TYPE(int) * p, unsigned MACRO_TYPE(long) * q) {return macroType(std::span(p, <# size #>), q);}\n" + // CHECK-DAG: fix-it:{{.*}}:{[[@LINE-2]]:4-[[@LINE-2]]:4}:"\n{{\[}}{{\[}}clang::unsafe_buffer_usage{{\]}}{{\]}}\nvoid macroType(unsigned MACRO_TYPE(int) * p, unsigned MACRO_TYPE(long) * q) {return macroType(p, std::span(q, <# size #>));}\n" } // The followings test various declarators: @@ -135,7 +135,7 @@ void decayedArray(int a[]) { int tmp; tmp = a[5]; } -// CHECK-DAG: fix-it:{{.*}}:{[[@LINE-1]]:2-[[@LINE-1]]:2}:"\n{{\[}}{{\[}}clang::unsafe_buffer_usage{{\]}}{{\]}} void decayedArray(int a[]) {return decayedArray(std::span(a, <# size #>));}\n" +// CHECK-DAG: fix-it:{{.*}}:{[[@LINE-1]]:2-[[@LINE-1]]:2}:"\n{{\[}}{{\[}}clang::unsafe_buffer_usage{{\]}}{{\]}}\nvoid decayedArray(int a[]) {return decayedArray(std::span(a, <# size #>));}\n" void decayedArrayOfArray(int a[10][10]) { // CHECK-NOT: fix-it:{{.*}}:{[[@LINE-1]] diff --git a/clang/test/SemaCXX/warn-unsafe-buffer-usage-fixits-parm-unsupported.cpp b/clang/test/SemaCXX/warn-unsafe-buffer-usage-fixits-parm-unsupported.cpp index f5be80b518ad3..bc918a7b53e9c 100644 --- a/clang/test/SemaCXX/warn-unsafe-buffer-usage-fixits-parm-unsupported.cpp +++ b/clang/test/SemaCXX/warn-unsafe-buffer-usage-fixits-parm-unsupported.cpp @@ -5,13 +5,13 @@ void const_ptr(int * const x) { // expected-warning{{'x' is an unsafe pointer us // CHECK: fix-it:{{.*}}:{[[@LINE-1]]:16-[[@LINE-1]]:29}:"std::span const x" int tmp = x[5]; // expected-note{{used in buffer access here}} } -// CHECK-DAG: fix-it:{{.*}}:{[[@LINE-1]]:2-[[@LINE-1]]:2}:"\n{{\[}}{{\[}}clang::unsafe_buffer_usage{{\]}}{{\]}} void const_ptr(int * const x) {return const_ptr(std::span(x, <# size #>));}\n" +// CHECK-DAG: fix-it:{{.*}}:{[[@LINE-1]]:2-[[@LINE-1]]:2}:"\n{{\[}}{{\[}}clang::unsafe_buffer_usage{{\]}}{{\]}}\nvoid const_ptr(int * const x) {return const_ptr(std::span(x, <# size #>));}\n" void const_ptr_to_const(const int * const x) {// expected-warning{{'x' is an unsafe pointer used for buffer access}} expected-note{{change type of 'x' to 'std::span' to preserve bounds information}} // CHECK-DAG: fix-it:{{.*}}:{[[@LINE-1]]:25-[[@LINE-1]]:44}:"std::span const x" int tmp = x[5]; // expected-note{{used in buffer access here}} } -// CHECK-DAG: fix-it:{{.*}}:{[[@LINE-1]]:2-[[@LINE-1]]:2}:"\n{{\[}}{{\[}}clang::unsafe_buffer_usage{{\]}}{{\]}} void const_ptr_to_const(const int * const x) {return const_ptr_to_const(std::span(x, <# size #>));}\n" +// CHECK-DAG: fix-it:{{.*}}:{[[@LINE-1]]:2-[[@LINE-1]]:2}:"\n{{\[}}{{\[}}clang::unsafe_buffer_usage{{\]}}{{\]}}\nvoid const_ptr_to_const(const int * const x) {return const_ptr_to_const(std::span(x, <# size #>));}\n" typedef struct {int x;} NAMED_UNNAMED_STRUCT; // an unnamed struct type named by a typedef typedef struct {int x;} * PTR_TO_ANON; // pointer to an unnamed struct @@ -24,7 +24,7 @@ void namedPointeeType(NAMED_UNNAMED_STRUCT * p) { // expected-warning{{'p' is a // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:7-[[@LINE-1]]:10}:"(p = p.subspan(1)).data()" } } -// CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:2-[[@LINE-1]]:2}:"\n{{\[}}{{\[}}clang::unsafe_buffer_usage{{\]}}{{\]}} void namedPointeeType(NAMED_UNNAMED_STRUCT * p) {return namedPointeeType(std::span(p, <# size #>));}\n" +// CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:2-[[@LINE-1]]:2}:"\n{{\[}}{{\[}}clang::unsafe_buffer_usage{{\]}}{{\]}}\nvoid namedPointeeType(NAMED_UNNAMED_STRUCT * p) {return namedPointeeType(std::span(p, <# size #>));}\n" // We CANNOT fix a pointer to an unnamed type // CHECK-NOT: fix-it: