30#include "llvm/ADT/STLExtras.h"
31#include "llvm/ADT/SmallVector.h"
41 "cpp-bounded-buffers-skipped";
48 return U->isPointerType() ||
U->isArrayType();
57 if (!
T->isTypedefNameType())
58 if (
const auto *RT =
T->getAs<RecordType>()) {
69 return "bounded_ptr<" + R.InnerSpelling +
"> ";
71 std::string N = std::to_string(CAT->getSize().getZExtValue());
72 return "bounded_array<" + R.InnerSpelling +
", " + N +
">";
86 const auto *
Other = dyn_cast<DeclaratorDecl>(Sibling);
88 Other->getTypeSourceInfo()->getTypeLoc().getBeginLoc() == Begin)
110 return PTL.getPointeeLoc();
112 return ATL.getElementLoc();
117bool isCVQualifier(
const Token &
T) {
118 return T.is(tok::raw_identifier) && (
T.getRawIdentifier() ==
"const" ||
119 T.getRawIdentifier() ==
"volatile");
133std::optional<ReportReason> extendLeadingQualifiers(
SourceLocation DeclBegin,
139 std::optional<SourceLocation> FirstCVBegin;
146 if (isCVQualifier(*
Tok)) {
149 FirstCVBegin =
Tok->getLocation();
151 }
else if (FirstCVBegin)
161 TypeBegin = *FirstCVBegin;
176std::optional<ReportReason> extendTrailingQualifiers(
SourceLocation &TypeEnd,
182 std::optional<SourceLocation> LastCVBegin;
183 bool RunEnded =
false;
190 if (isCVQualifier(*
Tok)) {
195 LastCVBegin =
Tok->getLocation();
204 TypeEnd = *LastCVBegin;
208using Levels = llvm::SmallSet<unsigned, 4>;
209using DeclLevels = std::map<const Decl *, Levels>;
210using ReturnLevels = std::map<const FunctionDecl *, Levels>;
214class ReachabilityMap {
215 const EntityPointerLevelSet &Reachables;
216 std::map<EntityName, EntityId> NameToId;
219 ReachabilityMap(
const WPASuite &Suite,
220 const EntityPointerLevelSet &Reachables)
221 : Reachables(Reachables) {
223 NameToId.emplace(Name, Id);
227 llvm::SmallSet<unsigned, 4> levelsFor(std::optional<EntityName> Name)
const {
228 llvm::SmallSet<unsigned, 4> Levels;
231 auto NameIt = NameToId.find(*Name);
232 if (NameIt == NameToId.end())
234 auto [Begin, End] = Reachables.equal_range(NameIt->second);
235 for (
const EntityPointerLevel &EPL : llvm::make_range(Begin, End))
236 Levels.insert(EPL.getPointerLevel());
245 CollectVisitor(
const ReachabilityMap &Reach,
248 ReturnLevels &Returns)
249 : Reach(Reach), TUNamespace(TUNamespace), LUNamespace(LUNamespace),
250 Decls(Decls), Returns(Returns) {}
252 bool VisitVarDecl(
VarDecl *D)
override {
258 bool VisitFieldDecl(
FieldDecl *D)
override {
266 llvm::SmallSet<unsigned, 4> Levels = Reach.levelsFor(
269 Returns[FD] = std::move(Levels);
275 void collect(
const Decl *D,
QualType T, std::optional<EntityName> Name) {
278 llvm::SmallSet<unsigned, 4> Levels = Reach.levelsFor(Name);
280 Decls[D] = std::move(Levels);
283 const ReachabilityMap &Reach;
287 ReturnLevels &Returns;
293 RewriteVisitor(
ASTContext &Ctx, DeclLevels &Decls, ReturnLevels &Returns,
295 : Ctx(Ctx), Decls(Decls), Returns(Returns), Edits(Edits),
Report(
Report) {
298 bool VisitVarDecl(
VarDecl *D)
override {
303 bool VisitFieldDecl(
FieldDecl *D)
override {
309 auto It = Returns.find(FD);
310 if (It == Returns.end())
312 const Levels &ReachableLevels = It->second;
313 if (hasTrailingReturnType(FD))
321 return report(FD, *R.Skip);
333 auto It = Decls.find(D);
334 if (It == Decls.end())
336 const Levels &ReachableLevels = It->second;
337 if (sharesTypeSpecifier(D))
349 return (
void)report(D, *R.Skip);
372 std::optional<ReportReason>
376 TypeLoc InnerTypeLoc = getInnerTypeLoc(TLoc);
387 if (!PTL || TLoc.
getEndLoc() != PTL.getStarLoc())
390 extendLeadingQualifiers(DeclBegin, RewriteRangeBegin, Ctx))
392 Result = {RewriteRangeBegin, PTL.getStarLoc()};
397 extendLeadingQualifiers(DeclBegin, RewriteRangeBegin, Ctx))
399 if (
auto Reason = extendTrailingQualifiers(RewriteRangeEnd, NameLoc, Ctx))
401 Result = {RewriteRangeBegin, RewriteRangeEnd};
404 if (
Result.getBegin().isMacroID() ||
Result.getEnd().isMacroID())
406 if (
Result.getBegin().isInvalid() ||
Result.getEnd().isInvalid())
425 if (
auto Reason = computeRewriteRange(DeclBegin, NameLoc, TLoc, R.NewType,
426 Ctx, TypeRewriteRange))
436 Edited.emplace_back(SM, TypeRewriteCharRange, renderNewType(R,
T, Ctx),
454 Edited.emplace_back(SM,
468 bool report(
const DeclaratorDecl *D, std::optional<ReportReason> Reason) {
480 ReturnLevels &Returns;
492 return "the array type does not end in a closing bracket";
494 return "declarator of a multi-declarator group is not yet rewritten";
496 return "no source edit could be formed for this declarator";
498 return "array of unknown bound is not yet rewritten";
500 return "declarator spelled through a macro is not yet rewritten";
502 return "multi-dimensional array is not yet rewritten";
504 return "multi-level pointer indirection is not yet rewritten";
506 return "no TypeLoc for the pointee or array element type";
508 return "pointer declarator does not end at its '*'";
510 return "this declaration was not transformed";
512 return "pointer to array is not yet rewritten";
514 return "reference to pointer is not yet rewritten";
516 return "trailing return type is not yet rewritten";
518 return "unexpected token between a leading cv-qualifier and the type";
520 return "unexpected token between the type and a trailing cv-qualifier";
522 return "the pointee or array element type has no name that can be written "
523 "as a template argument";
525 llvm_unreachable(
"unhandled ReportReason");
532 if (!ReachableLevels.count(1))
537 if (llvm::any_of(ReachableLevels, [](
unsigned L) {
return L > 1; })) {
542 if (
T->isReferenceType()) {
543 QualType Pointee =
T.getNonReferenceType();
553 "function pointer entities are not expected to be reachable");
564 if (!isNamable(Pointee)) {
569 R.InnerSpelling = Pointee->
isVoidType() ?
"char" : spell(Pointee, Ctx);
570 R.Skip = std::nullopt;
575 QualType Element = CAT->getElementType();
580 if (!isNamable(Element)) {
585 R.InnerSpelling = spell(Element, Ctx);
586 R.Skip = std::nullopt;
590 if (
T->isArrayType())
598 llvm::consumeError(Reachable.takeError());
602 ReachabilityMap Reach(
Suite, Reachable->Reachables);
608 ReturnLevels Returns;
611 CollectVisitor(Reach, TUNamespace, LUNamespace, Decls, Returns)
613 RewriteVisitor(Ctx, Decls, Returns,
Edits,
Report).TraverseDecl(TU);
623static clang::ssaf::TransformationRegistry::Add<CppBoundedBuffers>
625 "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.
Represents a hierarchical sequence of build namespaces.
static NestedBuildNamespace makeCompilationUnit(llvm::StringRef CompilationId)
Creates a NestedBuildNamespace representing a compilation unit.
static NestedBuildNamespace makeLinkUnit(llvm::StringRef LinkUnitId)
Creates a NestedBuildNamespace representing a link unit.
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
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 > getQualifiedEntityNameForReturn(const FunctionDecl *FD, const NestedBuildNamespace &TUNamespace, const NestedBuildNamespace &LUNamespace)
Similar to getQualifiedEntityName, but for entities of function return values.
std::optional< EntityName > getQualifiedEntityName(const Decl *D, const NestedBuildNamespace &TUNamespace, const NestedBuildNamespace &LUNamespace)
Returns the EntityName qualified with the build namespaces it would carry after linking into LUNamesp...
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...