Skip to content

Commit 8437847

Browse files
committed
[-Wunsafe-buffer-usage][NFC] Slightly refactor and optimize the code
Slightly refactor and optimize the code in preparation for implementing grouping parameters for a single fix-it. Reviewed by: NoQ (Artem Dergachev), t-rasmud (Rashmi Mudduluru) Differential revision: https://reviews.llvm.org/D156474
1 parent d37642b commit 8437847

File tree

3 files changed

+118
-86
lines changed

3 files changed

+118
-86
lines changed

clang/include/clang/Analysis/Analyses/UnsafeBufferUsage.h

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,19 @@
2020

2121
namespace clang {
2222

23-
using DefMapTy = llvm::DenseMap<const VarDecl *, std::vector<const VarDecl *>>;
23+
using VarGrpTy = std::vector<const VarDecl *>;
24+
using VarGrpRef = ArrayRef<const VarDecl *>;
25+
26+
class VariableGroupsManager {
27+
public:
28+
VariableGroupsManager() = default;
29+
virtual ~VariableGroupsManager() = default;
30+
/// Returns the set of variables (including `Var`) that need to be fixed
31+
/// together in one step.
32+
///
33+
/// `Var` must be a variable that needs fix (so it must be in a group).
34+
virtual VarGrpRef getGroupOfVar(const VarDecl *Var) const;
35+
};
2436

2537
/// The interface that lets the caller handle unsafe buffer usage analysis
2638
/// results by overriding this class's handle... methods.
@@ -53,7 +65,7 @@ class UnsafeBufferUsageHandler {
5365
/// all variables that must be fixed together (i.e their types must be changed to the
5466
/// same target type to prevent type mismatches) into a single fixit.
5567
virtual void handleUnsafeVariableGroup(const VarDecl *Variable,
56-
const DefMapTy &VarGrpMap,
68+
const VariableGroupsManager &VarGrpMgr,
5769
FixItList &&Fixes) = 0;
5870

5971
#ifndef NDEBUG

clang/lib/Analysis/UnsafeBufferUsage.cpp

Lines changed: 62 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1176,7 +1176,11 @@ groupWarningGadgetsByVar(const WarningGadgetList &AllUnsafeOperations) {
11761176
}
11771177

11781178
struct FixableGadgetSets {
1179-
std::map<const VarDecl *, std::set<const FixableGadget *>> byVar;
1179+
std::map<const VarDecl *, std::set<const FixableGadget *>,
1180+
// To keep keys sorted by their locations in the map so that the
1181+
// order is deterministic:
1182+
CompareNode<VarDecl>>
1183+
byVar;
11801184
};
11811185

11821186
static FixableGadgetSets
@@ -1382,7 +1386,7 @@ static std::optional<StringRef> getRangeText(SourceRange SR,
13821386
const SourceManager &SM,
13831387
const LangOptions &LangOpts) {
13841388
bool Invalid = false;
1385-
CharSourceRange CSR = CharSourceRange::getCharRange(SR.getBegin(), SR.getEnd());
1389+
CharSourceRange CSR = CharSourceRange::getCharRange(SR);
13861390
StringRef Text = Lexer::getSourceText(CSR, SM, LangOpts, &Invalid);
13871391

13881392
if (!Invalid)
@@ -2225,7 +2229,7 @@ getFixIts(FixableGadgetSets &FixablesForAllVars, const Strategy &S,
22252229
ASTContext &Ctx,
22262230
/* The function decl under analysis */ const Decl *D,
22272231
const DeclUseTracker &Tracker, UnsafeBufferUsageHandler &Handler,
2228-
const DefMapTy &VarGrpMap) {
2232+
const VariableGroupsManager &VarGrpMgr) {
22292233
std::map<const VarDecl *, FixItList> FixItsForVariable;
22302234
for (const auto &[VD, Fixables] : FixablesForAllVars.byVar) {
22312235
FixItsForVariable[VD] =
@@ -2261,9 +2265,10 @@ getFixIts(FixableGadgetSets &FixablesForAllVars, const Strategy &S,
22612265
continue;
22622266
}
22632267

2264-
const auto VarGroupForVD = VarGrpMap.find(VD);
2265-
if (VarGroupForVD != VarGrpMap.end()) {
2266-
for (const VarDecl * V : VarGroupForVD->second) {
2268+
2269+
{
2270+
const auto VarGroupForVD = VarGrpMgr.getGroupOfVar(VD);
2271+
for (const VarDecl * V : VarGroupForVD) {
22672272
if (V == VD) {
22682273
continue;
22692274
}
@@ -2275,7 +2280,7 @@ getFixIts(FixableGadgetSets &FixablesForAllVars, const Strategy &S,
22752280

22762281
if (ImpossibleToFix) {
22772282
FixItsForVariable.erase(VD);
2278-
for (const VarDecl * V : VarGroupForVD->second) {
2283+
for (const VarDecl * V : VarGroupForVD) {
22792284
FixItsForVariable.erase(V);
22802285
}
22812286
continue;
@@ -2293,30 +2298,24 @@ getFixIts(FixableGadgetSets &FixablesForAllVars, const Strategy &S,
22932298
}
22942299
}
22952300

2296-
for (auto VD : FixItsForVariable) {
2297-
const auto VarGroupForVD = VarGrpMap.find(VD.first);
2298-
const Strategy::Kind ReplacementTypeForVD = S.lookup(VD.first);
2299-
if (VarGroupForVD != VarGrpMap.end()) {
2300-
for (const VarDecl * Var : VarGroupForVD->second) {
2301-
if (Var == VD.first) {
2302-
continue;
2303-
}
2301+
// The map that maps each variable `v` to fix-its for the whole group where
2302+
// `v` is in:
2303+
std::map<const VarDecl *, FixItList> FinalFixItsForVariable{
2304+
FixItsForVariable};
23042305

2305-
FixItList GroupFix;
2306-
if (FixItsForVariable.find(Var) == FixItsForVariable.end()) {
2307-
GroupFix = fixVariable(Var, ReplacementTypeForVD, D, Tracker,
2308-
Var->getASTContext(), Handler);
2309-
} else {
2310-
GroupFix = FixItsForVariable[Var];
2311-
}
2306+
for (auto &[Var, Ignore] : FixItsForVariable) {
2307+
const auto VarGroupForVD = VarGrpMgr.getGroupOfVar(Var);
23122308

2313-
for (auto Fix : GroupFix) {
2314-
FixItsForVariable[VD.first].push_back(Fix);
2315-
}
2316-
}
2309+
for (const VarDecl *GrpMate : VarGroupForVD) {
2310+
if (Var == GrpMate)
2311+
continue;
2312+
if (FixItsForVariable.count(GrpMate))
2313+
FinalFixItsForVariable[Var].insert(FinalFixItsForVariable[Var].end(),
2314+
FixItsForVariable[GrpMate].begin(),
2315+
FixItsForVariable[GrpMate].end());
23172316
}
23182317
}
2319-
return FixItsForVariable;
2318+
return FinalFixItsForVariable;
23202319
}
23212320

23222321

@@ -2329,6 +2328,24 @@ getNaiveStrategy(const llvm::SmallVectorImpl<const VarDecl *> &UnsafeVars) {
23292328
return S;
23302329
}
23312330

2331+
// Manages variable groups:
2332+
class VariableGroupsManagerImpl : public VariableGroupsManager {
2333+
const std::vector<VarGrpTy> Groups;
2334+
const std::map<const VarDecl *, unsigned> &VarGrpMap;
2335+
2336+
public:
2337+
VariableGroupsManagerImpl(
2338+
const std::vector<VarGrpTy> &Groups,
2339+
const std::map<const VarDecl *, unsigned> &VarGrpMap)
2340+
: Groups(Groups), VarGrpMap(VarGrpMap) {}
2341+
2342+
VarGrpRef getGroupOfVar(const VarDecl *Var) const override {
2343+
auto I = VarGrpMap.find(Var);
2344+
assert(I != VarGrpMap.end());
2345+
return Groups[I->second];
2346+
}
2347+
};
2348+
23322349
void clang::checkUnsafeBufferUsage(const Decl *D,
23332350
UnsafeBufferUsageHandler &Handler,
23342351
bool EmitSuggestions) {
@@ -2408,7 +2425,6 @@ void clang::checkUnsafeBufferUsage(const Decl *D,
24082425
FixablesForAllVars = groupFixablesByVar(std::move(FixableGadgets));
24092426

24102427
std::map<const VarDecl *, FixItList> FixItsForVariableGroup;
2411-
DefMapTy VariableGroupsMap{};
24122428

24132429
// Filter out non-local vars and vars with unclaimed DeclRefExpr-s.
24142430
for (auto it = FixablesForAllVars.byVar.cbegin();
@@ -2451,7 +2467,7 @@ void clang::checkUnsafeBufferUsage(const Decl *D,
24512467
UnsafeVars.push_back(VD);
24522468

24532469
// Fixpoint iteration for pointer assignments
2454-
using DepMapTy = DenseMap<const VarDecl *, std::set<const VarDecl *>>;
2470+
using DepMapTy = DenseMap<const VarDecl *, llvm::SetVector<const VarDecl *>>;
24552471
DepMapTy DependenciesMap{};
24562472
DepMapTy PtrAssignmentGraph{};
24572473

@@ -2460,7 +2476,7 @@ void clang::checkUnsafeBufferUsage(const Decl *D,
24602476
std::optional<std::pair<const VarDecl *, const VarDecl *>> ImplPair =
24612477
fixable->getStrategyImplications();
24622478
if (ImplPair) {
2463-
std::pair<const VarDecl *, const VarDecl *> Impl = ImplPair.value();
2479+
std::pair<const VarDecl *, const VarDecl *> Impl = std::move(*ImplPair);
24642480
PtrAssignmentGraph[Impl.first].insert(Impl.second);
24652481
}
24662482
}
@@ -2505,14 +2521,21 @@ void clang::checkUnsafeBufferUsage(const Decl *D,
25052521
}
25062522
}
25072523

2524+
// `Groups` stores the set of Connected Components in the graph.
2525+
std::vector<VarGrpTy> Groups;
2526+
// `VarGrpMap` maps variables that need fix to the groups (indexes) that the
2527+
// variables belong to. Group indexes refer to the elements in `Groups`.
2528+
// `VarGrpMap` is complete in that every variable that needs fix is in it.
2529+
std::map<const VarDecl *, unsigned> VarGrpMap;
2530+
25082531
// Group Connected Components for Unsafe Vars
25092532
// (Dependencies based on pointer assignments)
25102533
std::set<const VarDecl *> VisitedVars{};
25112534
for (const auto &[Var, ignore] : UnsafeOps.byVar) {
25122535
if (VisitedVars.find(Var) == VisitedVars.end()) {
2513-
std::vector<const VarDecl *> VarGroup{};
2514-
2536+
VarGrpTy &VarGroup = Groups.emplace_back();
25152537
std::queue<const VarDecl*> Queue{};
2538+
25162539
Queue.push(Var);
25172540
while(!Queue.empty()) {
25182541
const VarDecl* CurrentVar = Queue.front();
@@ -2526,10 +2549,10 @@ void clang::checkUnsafeBufferUsage(const Decl *D,
25262549
}
25272550
}
25282551
}
2529-
for (const VarDecl * V : VarGroup) {
2530-
if (UnsafeOps.byVar.find(V) != UnsafeOps.byVar.end()) {
2531-
VariableGroupsMap[V] = VarGroup;
2532-
}
2552+
unsigned GrpIdx = Groups.size() - 1;
2553+
2554+
for (const VarDecl *V : VarGroup) {
2555+
VarGrpMap[V] = GrpIdx;
25332556
}
25342557
}
25352558
}
@@ -2563,20 +2586,19 @@ void clang::checkUnsafeBufferUsage(const Decl *D,
25632586
}
25642587

25652588
Strategy NaiveStrategy = getNaiveStrategy(UnsafeVars);
2589+
VariableGroupsManagerImpl VarGrpMgr(Groups, VarGrpMap);
25662590

25672591
FixItsForVariableGroup =
25682592
getFixIts(FixablesForAllVars, NaiveStrategy, D->getASTContext(), D,
2569-
Tracker, Handler, VariableGroupsMap);
2570-
2571-
// FIXME Detect overlapping FixIts.
2593+
Tracker, Handler, VarGrpMgr);
25722594

25732595
for (const auto &G : UnsafeOps.noVar) {
25742596
Handler.handleUnsafeOperation(G->getBaseStmt(), /*IsRelatedToDecl=*/false);
25752597
}
25762598

25772599
for (const auto &[VD, WarningGadgets] : UnsafeOps.byVar) {
25782600
auto FixItsIt = FixItsForVariableGroup.find(VD);
2579-
Handler.handleUnsafeVariableGroup(VD, VariableGroupsMap,
2601+
Handler.handleUnsafeVariableGroup(VD, VarGrpMgr,
25802602
FixItsIt != FixItsForVariableGroup.end()
25812603
? std::move(FixItsIt->second)
25822604
: FixItList{});

clang/lib/Sema/AnalysisBasedWarnings.cpp

Lines changed: 42 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -2175,6 +2175,41 @@ class UnsafeBufferUsageReporter : public UnsafeBufferUsageHandler {
21752175
Sema &S;
21762176
bool SuggestSuggestions; // Recommend -fsafe-buffer-usage-suggestions?
21772177

2178+
// Lists as a string the names of variables in `VarGroupForVD` except for `VD`
2179+
// itself:
2180+
std::string listVariableGroupAsString(
2181+
const VarDecl *VD, const ArrayRef<const VarDecl *> &VarGroupForVD) const {
2182+
if (VarGroupForVD.size() <= 1)
2183+
return "";
2184+
2185+
std::vector<StringRef> VarNames;
2186+
auto PutInQuotes = [](StringRef S) -> std::string {
2187+
return "'" + S.str() + "'";
2188+
};
2189+
2190+
for (auto *V : VarGroupForVD) {
2191+
if (V == VD)
2192+
continue;
2193+
VarNames.push_back(V->getName());
2194+
}
2195+
if (VarNames.size() == 1) {
2196+
return PutInQuotes(VarNames[0]);
2197+
}
2198+
if (VarNames.size() == 2) {
2199+
return PutInQuotes(VarNames[0]) + " and " + PutInQuotes(VarNames[1]);
2200+
}
2201+
assert(VarGroupForVD.size() > 3);
2202+
const unsigned N = VarNames.size() -
2203+
2; // need to print the last two names as "..., X, and Y"
2204+
std::string AllVars = "";
2205+
2206+
for (unsigned I = 0; I < N; ++I)
2207+
AllVars.append(PutInQuotes(VarNames[I]) + ", ");
2208+
AllVars.append(PutInQuotes(VarNames[N]) + ", and " +
2209+
PutInQuotes(VarNames[N + 1]));
2210+
return AllVars;
2211+
}
2212+
21782213
public:
21792214
UnsafeBufferUsageReporter(Sema &S, bool SuggestSuggestions)
21802215
: S(S), SuggestSuggestions(SuggestSuggestions) {}
@@ -2231,62 +2266,25 @@ class UnsafeBufferUsageReporter : public UnsafeBufferUsageHandler {
22312266
}
22322267

22332268
void handleUnsafeVariableGroup(const VarDecl *Variable,
2234-
const DefMapTy &VarGrpMap,
2235-
FixItList &&Fixes) override {
2269+
const VariableGroupsManager &VarGrpMgr,
2270+
FixItList &&Fixes) override {
22362271
assert(!SuggestSuggestions &&
22372272
"Unsafe buffer usage fixits displayed without suggestions!");
22382273
S.Diag(Variable->getLocation(), diag::warn_unsafe_buffer_variable)
22392274
<< Variable << (Variable->getType()->isPointerType() ? 0 : 1)
22402275
<< Variable->getSourceRange();
22412276
if (!Fixes.empty()) {
2242-
const auto VarGroupForVD = VarGrpMap.find(Variable)->second;
2277+
const auto VarGroupForVD = VarGrpMgr.getGroupOfVar(Variable);
22432278
unsigned FixItStrategy = 0; // For now we only have 'std::span' strategy
22442279
const auto &FD = S.Diag(Variable->getLocation(),
22452280
diag::note_unsafe_buffer_variable_fixit_group);
22462281

22472282
FD << Variable << FixItStrategy;
2248-
std::string AllVars = "";
2249-
if (VarGroupForVD.size() > 1) {
2250-
if (VarGroupForVD.size() == 2) {
2251-
if (VarGroupForVD[0] == Variable) {
2252-
AllVars.append("'" + VarGroupForVD[1]->getName().str() + "'");
2253-
} else {
2254-
AllVars.append("'" + VarGroupForVD[0]->getName().str() + "'");
2255-
}
2256-
} else {
2257-
bool first = false;
2258-
if (VarGroupForVD.size() == 3) {
2259-
for (const VarDecl * V : VarGroupForVD) {
2260-
if (V == Variable) {
2261-
continue;
2262-
}
2263-
if (!first) {
2264-
first = true;
2265-
AllVars.append("'" + V->getName().str() + "'" + " and ");
2266-
} else {
2267-
AllVars.append("'" + V->getName().str() + "'");
2268-
}
2269-
}
2270-
} else {
2271-
for (const VarDecl * V : VarGroupForVD) {
2272-
if (V == Variable) {
2273-
continue;
2274-
}
2275-
if (VarGroupForVD.back() != V) {
2276-
AllVars.append("'" + V->getName().str() + "'" + ", ");
2277-
} else {
2278-
AllVars.append("and '" + V->getName().str() + "'");
2279-
}
2280-
}
2281-
}
2282-
}
2283-
FD << AllVars << 1;
2284-
} else {
2285-
FD << "" << 0;
2286-
}
2287-
2288-
for (const auto &F : Fixes)
2283+
FD << listVariableGroupAsString(Variable, VarGroupForVD)
2284+
<< (VarGroupForVD.size() > 1);
2285+
for (const auto &F : Fixes) {
22892286
FD << F;
2287+
}
22902288
}
22912289

22922290
#ifndef NDEBUG

0 commit comments

Comments
 (0)