llvm-project/clang/lib/Analysis/CFGStmtMap.cpp
David Stone 1eea63811a
[clang][NFC] Use constructor instead of factory function in CFGStmtMap (#172530)
`CFGStmtMap::Build` accepts pointers and returns a pointer to
dynamically allocated memory. In the one location where the type is
actually constructed, the pointers are guaranteed to be non-null. By
accepting references to statically enforce this, we can remove the only
way for the construction to fail.

By making this change, we also allow our user to decide how they want to
own the memory (either directly or indirectly). The user does not
actually need dynamic allocation here, so we replace the
`std::unique_ptr` with `std::optional`.

This simplifies the code by requiring fewer checks, makes comments on
what happens redundant because the code can obviously do only one thing,
avoids potential bugs, and improves performance by allocating less.
2025-12-24 20:25:00 +00:00

57 lines
1.7 KiB
C++

//===--- CFGStmtMap.h - Map from Stmt* to CFGBlock* -----------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// This file defines the CFGStmtMap class, which defines a mapping from
// Stmt* to CFGBlock*
//
//===----------------------------------------------------------------------===//
#include "clang/AST/ParentMap.h"
#include "clang/Analysis/CFG.h"
#include "clang/Analysis/CFGStmtMap.h"
#include <optional>
using namespace clang;
const CFGBlock *CFGStmtMap::getBlock(const Stmt *S) const {
const Stmt *X = S;
// If 'S' isn't in the map, walk the ParentMap to see if one of its ancestors
// is in the map.
while (X) {
auto I = M.find(X);
if (I != M.end())
return I->second;
X = PM->getParentIgnoreParens(X);
}
return nullptr;
}
CFGStmtMap::CFGStmtMap(const CFG &C, const ParentMap &PM) : PM(&PM) {
// Walk all blocks, accumulating the block-level expressions, labels,
// and terminators.
for (const CFGBlock *B : C) {
// First walk the block-level expressions.
for (const CFGElement &CE : *B) {
if (std::optional<CFGStmt> CS = CE.getAs<CFGStmt>())
M.try_emplace(CS->getStmt(), B);
}
// Look at the label of the block.
if (const Stmt *Label = B->getLabel())
M[Label] = B;
// Finally, look at the terminator. If the terminator was already added
// because it is a block-level expression in another block, overwrite
// that mapping.
if (const Stmt *Term = B->getTerminatorStmt())
M[Term] = B;
}
}