diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2022-01-27 22:17:16 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2022-05-14 11:44:34 +0000 |
commit | 04eeddc0aa8e0a417a16eaf9d7d095207f4a8623 (patch) | |
tree | 2a5d3b2fe5c852e91531d128d9177754572d5338 /contrib/llvm-project/clang/lib/Tooling/Transformer/SourceCodeBuilders.cpp | |
parent | 0eae32dcef82f6f06de6419a0d623d7def0cc8f6 (diff) | |
parent | 6f8fc217eaa12bf657be1c6468ed9938d10168b3 (diff) |
Diffstat (limited to 'contrib/llvm-project/clang/lib/Tooling/Transformer/SourceCodeBuilders.cpp')
-rw-r--r-- | contrib/llvm-project/clang/lib/Tooling/Transformer/SourceCodeBuilders.cpp | 84 |
1 files changed, 80 insertions, 4 deletions
diff --git a/contrib/llvm-project/clang/lib/Tooling/Transformer/SourceCodeBuilders.cpp b/contrib/llvm-project/clang/lib/Tooling/Transformer/SourceCodeBuilders.cpp index a1c99b60216b..7496e968469c 100644 --- a/contrib/llvm-project/clang/lib/Tooling/Transformer/SourceCodeBuilders.cpp +++ b/contrib/llvm-project/clang/lib/Tooling/Transformer/SourceCodeBuilders.cpp @@ -10,6 +10,8 @@ #include "clang/AST/ASTContext.h" #include "clang/AST/Expr.h" #include "clang/AST/ExprCXX.h" +#include "clang/ASTMatchers/ASTMatchFinder.h" +#include "clang/ASTMatchers/ASTMatchers.h" #include "clang/Tooling/Transformer/SourceCode.h" #include "llvm/ADT/Twine.h" #include <string> @@ -60,6 +62,16 @@ bool tooling::needParensAfterUnaryOperator(const Expr &E) { return false; } +bool tooling::isKnownPointerLikeType(QualType Ty, ASTContext &Context) { + using namespace ast_matchers; + const auto PointerLikeTy = type(hasUnqualifiedDesugaredType( + recordType(hasDeclaration(cxxRecordDecl(hasAnyName( + "::std::unique_ptr", "::std::shared_ptr", "::std::weak_ptr", + "::std::optional", "::absl::optional", "::llvm::Optional", + "absl::StatusOr", "::llvm::Expected")))))); + return match(PointerLikeTy, Ty, Context).size() > 0; +} + llvm::Optional<std::string> tooling::buildParens(const Expr &E, const ASTContext &Context) { StringRef Text = getText(E, Context); @@ -114,8 +126,10 @@ llvm::Optional<std::string> tooling::buildAddressOf(const Expr &E, return ("&" + Text).str(); } -llvm::Optional<std::string> tooling::buildDot(const Expr &E, - const ASTContext &Context) { +// Append the appropriate access operation (syntactically) to `E`, assuming `E` +// is a non-pointer value. +static llvm::Optional<std::string> +buildAccessForValue(const Expr &E, const ASTContext &Context) { if (const auto *Op = llvm::dyn_cast<UnaryOperator>(&E)) if (Op->getOpcode() == UO_Deref) { // Strip leading '*', add following '->'. @@ -138,8 +152,10 @@ llvm::Optional<std::string> tooling::buildDot(const Expr &E, return (Text + ".").str(); } -llvm::Optional<std::string> tooling::buildArrow(const Expr &E, - const ASTContext &Context) { +// Append the appropriate access operation (syntactically) to `E`, assuming `E` +// is a pointer value. +static llvm::Optional<std::string> +buildAccessForPointer(const Expr &E, const ASTContext &Context) { if (const auto *Op = llvm::dyn_cast<UnaryOperator>(&E)) if (Op->getOpcode() == UO_AddrOf) { // Strip leading '&', add following '.'. @@ -160,3 +176,63 @@ llvm::Optional<std::string> tooling::buildArrow(const Expr &E, return ("(" + Text + ")->").str(); return (Text + "->").str(); } + +llvm::Optional<std::string> tooling::buildDot(const Expr &E, + const ASTContext &Context) { + return buildAccessForValue(E, Context); +} + +llvm::Optional<std::string> tooling::buildArrow(const Expr &E, + const ASTContext &Context) { + return buildAccessForPointer(E, Context); +} + +// If `E` is an overloaded-operator call of kind `K` on an object `O`, returns +// `O`. Otherwise, returns `nullptr`. +static const Expr *maybeGetOperatorObjectArg(const Expr &E, + OverloadedOperatorKind K) { + if (const auto *OpCall = dyn_cast<clang::CXXOperatorCallExpr>(&E)) { + if (OpCall->getOperator() == K && OpCall->getNumArgs() == 1) + return OpCall->getArg(0); + } + return nullptr; +} + +static bool treatLikePointer(QualType Ty, PLTClass C, ASTContext &Context) { + switch (C) { + case PLTClass::Value: + return false; + case PLTClass::Pointer: + return isKnownPointerLikeType(Ty, Context); + } + llvm_unreachable("Unknown PLTClass enum"); +} + +// FIXME: move over the other `maybe` functionality from Stencil. Should all be +// in one place. +llvm::Optional<std::string> tooling::buildAccess(const Expr &RawExpression, + ASTContext &Context, + PLTClass Classification) { + if (RawExpression.isImplicitCXXThis()) + // Return the empty string, because `None` signifies some sort of failure. + return std::string(); + + const Expr *E = RawExpression.IgnoreImplicitAsWritten(); + + if (E->getType()->isAnyPointerType() || + treatLikePointer(E->getType(), Classification, Context)) { + // Strip off operator-> calls. They can only occur inside an actual arrow + // member access, so we treat them as equivalent to an actual object + // expression. + if (const auto *Obj = maybeGetOperatorObjectArg(*E, clang::OO_Arrow)) + E = Obj; + return buildAccessForPointer(*E, Context); + } + + if (const auto *Obj = maybeGetOperatorObjectArg(*E, clang::OO_Star)) { + if (treatLikePointer(Obj->getType(), Classification, Context)) + return buildAccessForPointer(*Obj, Context); + }; + + return buildAccessForValue(*E, Context); +} |