29#include "llvm/ADT/STLExtras.h"
30#include "llvm/ADT/SmallVector.h"
40 "cpp-bounded-buffers-skipped";
47 return U->isPointerType() ||
U->isArrayType();
56 if (!
T->isTypedefNameType())
57 if (
const auto *RT =
T->getAs<RecordType>()) {
68 return "bounded_ptr<" + R.InnerSpelling +
"> ";
70 std::string N = std::to_string(CAT->getSize().getZExtValue());
71 return "bounded_array<" + R.InnerSpelling +
", " + N +
">";
85 const auto *
Other = dyn_cast<DeclaratorDecl>(Sibling);
87 Other->getTypeSourceInfo()->getTypeLoc().getBeginLoc() == Begin)
109 return PTL.getPointeeLoc();
111 return ATL.getElementLoc();
116bool isCVQualifier(
const Token &
T) {
117 return T.is(tok::raw_identifier) && (
T.getRawIdentifier() ==
"const" ||
118 T.getRawIdentifier() ==
"volatile");
132std::optional<ReportReason> extendLeadingQualifiers(
SourceLocation DeclBegin,
138 std::optional<SourceLocation> FirstCVBegin;
145 if (isCVQualifier(*
Tok)) {
148 FirstCVBegin =
Tok->getLocation();
150 }
else if (FirstCVBegin)
160 TypeBegin = *FirstCVBegin;
175std::optional<ReportReason> extendTrailingQualifiers(
SourceLocation &TypeEnd,
181 std::optional<SourceLocation> LastCVBegin;
182 bool RunEnded =
false;
189 if (isCVQualifier(*
Tok)) {
194 LastCVBegin =
Tok->getLocation();
203 TypeEnd = *LastCVBegin;
207using Levels = llvm::SmallSet<unsigned, 4>;
208using DeclLevels = std::map<const Decl *, Levels>;
209using ReturnLevels = std::map<const FunctionDecl *, Levels>;
213class ReachabilityMap {
214 const std::map<EntityId, EntityPointerLevelSet> &Reachables;
215 std::map<EntityName, EntityId> NameToId;
218 ReachabilityMap(
const WPASuite &Suite,
219 const std::map<EntityId, EntityPointerLevelSet> &Reachables)
220 : Reachables(Reachables) {
222 NameToId.emplace(Name, Id);
226 llvm::SmallSet<unsigned, 4> levelsFor(std::optional<EntityName> Name)
const {
227 llvm::SmallSet<unsigned, 4> Levels;
230 auto NameIt = NameToId.find(*Name);
231 if (NameIt == NameToId.end())
233 auto ReachIt = Reachables.find(NameIt->second);
234 if (ReachIt == Reachables.end())
236 for (
const EntityPointerLevel &EPL : ReachIt->second)
237 Levels.insert(EPL.getPointerLevel());
246 CollectVisitor(
const ReachabilityMap &Reach, DeclLevels &Decls,
247 ReturnLevels &Returns)
248 : Reach(Reach), Decls(Decls), Returns(Returns) {}
250 bool VisitVarDecl(
VarDecl *D)
override {
255 bool VisitFieldDecl(
FieldDecl *D)
override {
262 llvm::SmallSet<unsigned, 4> Levels =
265 Returns[FD] = std::move(Levels);
271 void collect(
const Decl *D,
QualType T, std::optional<EntityName> Name) {
274 llvm::SmallSet<unsigned, 4> Levels = Reach.levelsFor(Name);
276 Decls[D] = std::move(Levels);
279 const ReachabilityMap &Reach;
281 ReturnLevels &Returns;
287 RewriteVisitor(
ASTContext &Ctx, DeclLevels &Decls, ReturnLevels &Returns,
289 : Ctx(Ctx), Decls(Decls), Returns(Returns), Edits(Edits),
Report(
Report) {
292 bool VisitVarDecl(
VarDecl *D)
override {
297 bool VisitFieldDecl(
FieldDecl *D)
override {
303 auto It = Returns.find(FD);
304 if (It == Returns.end())
306 const Levels &ReachableLevels = It->second;
307 if (hasTrailingReturnType(FD))
315 return report(FD, *R.Skip);
327 auto It = Decls.find(D);
328 if (It == Decls.end())
330 const Levels &ReachableLevels = It->second;
331 if (sharesTypeSpecifier(D))
343 return (
void)report(D, *R.Skip);
366 std::optional<ReportReason>
370 TypeLoc InnerTypeLoc = getInnerTypeLoc(TLoc);
381 if (!PTL || TLoc.
getEndLoc() != PTL.getStarLoc())
384 extendLeadingQualifiers(DeclBegin, RewriteRangeBegin, Ctx))
386 Result = {RewriteRangeBegin, PTL.getStarLoc()};
391 extendLeadingQualifiers(DeclBegin, RewriteRangeBegin, Ctx))
393 if (
auto Reason = extendTrailingQualifiers(RewriteRangeEnd, NameLoc, Ctx))
395 Result = {RewriteRangeBegin, RewriteRangeEnd};
398 if (
Result.getBegin().isMacroID() ||
Result.getEnd().isMacroID())
400 if (
Result.getBegin().isInvalid() ||
Result.getEnd().isInvalid())
419 if (
auto Reason = computeRewriteRange(DeclBegin, NameLoc, TLoc, R.NewType,
420 Ctx, TypeRewriteRange))
430 Edited.emplace_back(SM, TypeRewriteCharRange, renderNewType(R,
T, Ctx),
448 Edited.emplace_back(SM,
462 bool report(
const DeclaratorDecl *D, std::optional<ReportReason> Reason) {
471 ReturnLevels &Returns;
483 return "the array type does not end in a closing bracket";
485 return "declarator of a multi-declarator group is not yet rewritten";
487 return "no source edit could be formed for this declarator";
489 return "array of unknown bound is not yet rewritten";
491 return "declarator spelled through a macro is not yet rewritten";
493 return "multi-dimensional array is not yet rewritten";
495 return "multi-level pointer indirection is not yet rewritten";
497 return "no TypeLoc for the pointee or array element type";
499 return "pointer declarator does not end at its '*'";
501 return "this declaration was not transformed";
503 return "pointer to array is not yet rewritten";
505 return "reference to pointer is not yet rewritten";
507 return "trailing return type is not yet rewritten";
509 return "unexpected token between a leading cv-qualifier and the type";
511 return "unexpected token between the type and a trailing cv-qualifier";
513 return "the pointee or array element type has no name that can be written "
514 "as a template argument";
516 llvm_unreachable(
"unhandled ReportReason");
523 if (!ReachableLevels.count(1))
528 if (llvm::any_of(ReachableLevels, [](
unsigned L) {
return L > 1; })) {
533 if (
T->isReferenceType()) {
534 QualType Pointee =
T.getNonReferenceType();
544 "function pointer entities are not expected to be reachable");
555 if (!isNamable(Pointee)) {
560 R.InnerSpelling = Pointee->
isVoidType() ?
"char" : spell(Pointee, Ctx);
561 R.Skip = std::nullopt;
566 QualType Element = CAT->getElementType();
571 if (!isNamable(Element)) {
576 R.InnerSpelling = spell(Element, Ctx);
577 R.Skip = std::nullopt;
581 if (
T->isArrayType())
589 llvm::consumeError(Reachable.takeError());
593 ReachabilityMap Reach(
Suite, Reachable->Reachables);
595 ReturnLevels Returns;
598 CollectVisitor(Reach, Decls, Returns).TraverseDecl(TU);
599 RewriteVisitor(Ctx, Decls, Returns,
Edits,
Report).TraverseDecl(TU);
609static clang::ssaf::TransformationRegistry::Add<CppBoundedBuffers>
611 "Rewrites buffers into bounded types");
Defines the clang::ASTContext interface.
static void emit(Program &P, llvm::SmallVectorImpl< std::byte > &Code, const T &Val, bool &Success)
Helper to write bytecode and bail out if 32-bit offsets become invalid.
static clang::ssaf::TransformationRegistry::Add< CppBoundedBuffers > RegisterCppBoundedBuffers("cpp-bounded-buffers", "Rewrites buffers into bounded types")
static constexpr llvm::StringLiteral SkippedRuleId
Defines the C++ Decl subclasses, other than those for templates (found in DeclTemplate....
Result
Implement __builtin_bit_cast and related operations.
Defines the clang::LangOptions interface.
Defines the clang::SourceLocation class and associated facilities.
Defines the SourceManager interface.
Defines the clang::TypeLoc interface and its subclasses.
C Language Family Type Representation.
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
SourceManager & getSourceManager()
TranslationUnitDecl * getTranslationUnitDecl() const
const ConstantArrayType * getAsConstantArrayType(QualType T) const
const LangOptions & getLangOpts() const
const clang::PrintingPolicy & getPrintingPolicy() const
Wrapper for source info for arrays.
SourceLocation getLBracketLoc() const
SourceLocation getRBracketLoc() const
Represents a byte-granular source range.
static CharSourceRange getTokenRange(SourceRange R)
DeclContext - This is used only as base class of specific decl types that can act as declaration cont...
decl_range decls() const
decls_begin/decls_end - Iterate over the declarations stored in this context.
Decl - This represents one declaration (or definition), e.g.
bool isTemplated() const
Determine whether this declaration is a templated entity (whether it is.
SourceLocation getLocation() const
DeclContext * getLexicalDeclContext()
getLexicalDeclContext - The declaration context where this Decl was lexically declared (LexicalDC).
Represents a ValueDecl that came out of a declarator.
SourceRange getSourceRange() const override LLVM_READONLY
Source range that this declaration covers.
SourceLocation getBeginLoc() const LLVM_READONLY
TypeSourceInfo * getTypeSourceInfo() const
Represents a member of a struct/union/class.
Represents a function declaration or definition.
QualType getReturnType() const
FunctionTypeLoc getFunctionTypeLoc() const
Find the source location information for how the type of this function was written.
Represents a prototype with parameter type info, e.g.
bool hasTrailingReturn() const
Whether this function prototype has a trailing return type.
Wrapper for source info for functions.
TypeLoc getReturnLoc() const
Keeps track of the various options that can be enabled, which controls the dialect of C or C++ that i...
static CharSourceRange getAsCharRange(SourceRange Range, const SourceManager &SM, const LangOptions &LangOpts)
Given a token range, produce a corresponding CharSourceRange that is not a token range.
static std::optional< Token > findNextToken(SourceLocation Loc, const SourceManager &SM, const LangOptions &LangOpts, bool IncludeComments=false)
Finds the token that comes right after the given location.
static bool getRawToken(SourceLocation Loc, Token &Result, const SourceManager &SM, const LangOptions &LangOpts, bool IgnoreWhiteSpace=false)
Relex the token at the specified location.
IdentifierInfo * getIdentifier() const
Get the identifier that names this declaration, if there is one.
Wrapper for source info for pointers.
PointerType - C99 6.7.5.1 - Pointer Declarators.
A (possibly-)qualified type.
Represents a struct/union/class.
Encodes a location in the source.
This class handles loading and caching of source files into memory.
FileID getFileID(SourceLocation SpellingLoc) const
Return the FileID for a SourceLocation.
bool isBeforeInTranslationUnit(SourceLocation LHS, SourceLocation RHS) const
Determines the order of 2 source locations in the translation unit.
A trivial tuple used to represent a source range.
TypedefNameDecl * getTypedefNameForAnonDecl() const
Token - This structure provides full information about a lexed token.
Base wrapper for a particular "section" of type source info.
UnqualTypeLoc getUnqualifiedLoc() const
Skips past any qualifiers, if this is qualified.
T getAs() const
Convert to the specified TypeLoc type, returning a null TypeLoc if this TypeLoc is not of the desired...
SourceLocation getEndLoc() const
Get the end source location.
SourceLocation getBeginLoc() const
Get the begin source location.
A container of type source information.
TypeLoc getTypeLoc() const
Return the TypeLoc wrapper for the type source info.
bool isPointerType() const
QualType getPointeeType() const
If this is a pointer, ObjC object pointer, or block pointer, this returns the respective pointee.
bool isFunctionType() const
const T * getAs() const
Member-template getAs<specific type>'.
Represents a variable declaration or definition.
void HandleTranslationUnit(clang::ASTContext &Ctx) override
HandleTranslationUnit - This method is called when the ASTs for entire translation unit have been par...
void forEach(llvm::function_ref< void(const EntityName &, EntityId)> Callback) const
Invokes the callback for each entity in the table.
Lightweight opaque handle representing an entity in an EntityIdTable.
Uniquely identifies an entity in a program.
virtual void addReplacement(clang::tooling::Replacement R)=0
Bundles the EntityIdTable (moved from the LUSummary) and the analysis results produced by one Analysi...
const EntityIdTable & getIdTable() const
Returns the EntityIdTable that maps EntityId values to their symbolic names.
BoundedType
The bounded type a raw declarator is rewritten to.
volatile int CppBoundedBuffersAnchorSource
std::optional< EntityName > getEntityNameForReturn(const FunctionDecl *FD)
Maps return entity of a function to an EntityName.
ClassifyResult classifyDeclType(QualType T, const llvm::SmallSet< unsigned, 4 > &ReachableLevels, const ASTContext &Ctx)
Classifies the declared type T of a reachable entity.
std::optional< EntityName > getEntityName(const Decl *D)
Maps a declaration to an EntityName.
llvm::StringRef messageFor(ReportReason Reason)
Returns the report message for Reason.
ReportReason
Why a reachable declarator was reported instead of rewritten.
@ NotPointerTypeEndWithStar
@ UnexpectedTrailingQualifier
@ UnexpectedLeadingQualifier
Top level wrappers for InstallAPI frontend operations.
const FunctionProtoType * T
DynamicRecursiveASTVisitorBase< false > DynamicRecursiveASTVisitor
@ Other
Other implicit parameter.
The outcome of classifying a declared type against the reachable pointer levels of its entity: a boun...