clang 18.0.0git
SourceCodeBuilders.cpp
Go to the documentation of this file.
1//===--- SourceCodeBuilder.cpp ----------------------------------*- C++ -*-===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
11#include "clang/AST/Expr.h"
12#include "clang/AST/ExprCXX.h"
16#include "llvm/ADT/Twine.h"
17#include <string>
18
19using namespace clang;
20using namespace tooling;
21
23 const Expr *Expr = E.IgnoreImplicit();
24 if (const auto *CE = dyn_cast<CXXConstructExpr>(Expr)) {
25 if (CE->getNumArgs() > 0 &&
26 CE->getArg(0)->getSourceRange() == Expr->getSourceRange())
27 return CE->getArg(0)->IgnoreImplicit();
28 }
29 return Expr;
30}
31
33 const Expr *Expr = reallyIgnoreImplicit(E);
34 // We always want parens around unary, binary, and ternary operators, because
35 // they are lower precedence.
36 if (isa<UnaryOperator>(Expr) || isa<BinaryOperator>(Expr) ||
37 isa<AbstractConditionalOperator>(Expr))
38 return true;
39
40 // We need parens around calls to all overloaded operators except: function
41 // calls, subscripts, and expressions that are already part of an (implicit)
42 // call to operator->. These latter are all in the same precedence level as
43 // dot/arrow and that level is left associative, so they don't need parens
44 // when appearing on the left.
45 if (const auto *Op = dyn_cast<CXXOperatorCallExpr>(Expr))
46 return Op->getOperator() != OO_Call && Op->getOperator() != OO_Subscript &&
47 Op->getOperator() != OO_Arrow;
48
49 return false;
50}
51
53 const Expr *Expr = reallyIgnoreImplicit(E);
54 if (isa<BinaryOperator>(Expr) || isa<AbstractConditionalOperator>(Expr))
55 return true;
56
57 if (const auto *Op = dyn_cast<CXXOperatorCallExpr>(Expr))
58 return Op->getNumArgs() == 2 && Op->getOperator() != OO_PlusPlus &&
59 Op->getOperator() != OO_MinusMinus && Op->getOperator() != OO_Call &&
60 Op->getOperator() != OO_Subscript;
61
62 return false;
63}
64
66 using namespace ast_matchers;
67 const auto PointerLikeTy = type(hasUnqualifiedDesugaredType(
69 "::std::unique_ptr", "::std::shared_ptr", "::std::weak_ptr",
70 "::std::optional", "::absl::optional", "::llvm::Optional",
71 "absl::StatusOr", "::llvm::Expected"))))));
72 return match(PointerLikeTy, Ty, Context).size() > 0;
73}
74
75std::optional<std::string> tooling::buildParens(const Expr &E,
76 const ASTContext &Context) {
77 StringRef Text = getText(E, Context);
78 if (Text.empty())
79 return std::nullopt;
80 if (mayEverNeedParens(E))
81 return ("(" + Text + ")").str();
82 return Text.str();
83}
84
85std::optional<std::string>
86tooling::buildDereference(const Expr &E, const ASTContext &Context) {
87 if (const auto *Op = dyn_cast<UnaryOperator>(&E))
88 if (Op->getOpcode() == UO_AddrOf) {
89 // Strip leading '&'.
90 StringRef Text =
91 getText(*Op->getSubExpr()->IgnoreParenImpCasts(), Context);
92 if (Text.empty())
93 return std::nullopt;
94 return Text.str();
95 }
96
97 StringRef Text = getText(E, Context);
98 if (Text.empty())
99 return std::nullopt;
100 // Add leading '*'.
102 return ("*(" + Text + ")").str();
103 return ("*" + Text).str();
104}
105
106std::optional<std::string> tooling::buildAddressOf(const Expr &E,
107 const ASTContext &Context) {
108 if (E.isImplicitCXXThis())
109 return std::string("this");
110 if (const auto *Op = dyn_cast<UnaryOperator>(&E))
111 if (Op->getOpcode() == UO_Deref) {
112 // Strip leading '*'.
113 StringRef Text =
114 getText(*Op->getSubExpr()->IgnoreParenImpCasts(), Context);
115 if (Text.empty())
116 return std::nullopt;
117 return Text.str();
118 }
119 // Add leading '&'.
120 StringRef Text = getText(E, Context);
121 if (Text.empty())
122 return std::nullopt;
124 return ("&(" + Text + ")").str();
125 }
126 return ("&" + Text).str();
127}
128
129// Append the appropriate access operation (syntactically) to `E`, assuming `E`
130// is a non-pointer value.
131static std::optional<std::string>
132buildAccessForValue(const Expr &E, const ASTContext &Context) {
133 if (const auto *Op = llvm::dyn_cast<UnaryOperator>(&E))
134 if (Op->getOpcode() == UO_Deref) {
135 // Strip leading '*', add following '->'.
136 const Expr *SubExpr = Op->getSubExpr()->IgnoreParenImpCasts();
137 StringRef DerefText = getText(*SubExpr, Context);
138 if (DerefText.empty())
139 return std::nullopt;
140 if (needParensBeforeDotOrArrow(*SubExpr))
141 return ("(" + DerefText + ")->").str();
142 return (DerefText + "->").str();
143 }
144
145 // Add following '.'.
146 StringRef Text = getText(E, Context);
147 if (Text.empty())
148 return std::nullopt;
150 return ("(" + Text + ").").str();
151 }
152 return (Text + ".").str();
153}
154
155// Append the appropriate access operation (syntactically) to `E`, assuming `E`
156// is a pointer value.
157static std::optional<std::string>
158buildAccessForPointer(const Expr &E, const ASTContext &Context) {
159 if (const auto *Op = llvm::dyn_cast<UnaryOperator>(&E))
160 if (Op->getOpcode() == UO_AddrOf) {
161 // Strip leading '&', add following '.'.
162 const Expr *SubExpr = Op->getSubExpr()->IgnoreParenImpCasts();
163 StringRef DerefText = getText(*SubExpr, Context);
164 if (DerefText.empty())
165 return std::nullopt;
166 if (needParensBeforeDotOrArrow(*SubExpr))
167 return ("(" + DerefText + ").").str();
168 return (DerefText + ".").str();
169 }
170
171 // Add following '->'.
172 StringRef Text = getText(E, Context);
173 if (Text.empty())
174 return std::nullopt;
176 return ("(" + Text + ")->").str();
177 return (Text + "->").str();
178}
179
180std::optional<std::string> tooling::buildDot(const Expr &E,
181 const ASTContext &Context) {
182 return buildAccessForValue(E, Context);
183}
184
185std::optional<std::string> tooling::buildArrow(const Expr &E,
186 const ASTContext &Context) {
187 return buildAccessForPointer(E, Context);
188}
189
190// If `E` is an overloaded-operator call of kind `K` on an object `O`, returns
191// `O`. Otherwise, returns `nullptr`.
192static const Expr *maybeGetOperatorObjectArg(const Expr &E,
194 if (const auto *OpCall = dyn_cast<clang::CXXOperatorCallExpr>(&E)) {
195 if (OpCall->getOperator() == K && OpCall->getNumArgs() == 1)
196 return OpCall->getArg(0);
197 }
198 return nullptr;
199}
200
201static bool treatLikePointer(QualType Ty, PLTClass C, ASTContext &Context) {
202 switch (C) {
203 case PLTClass::Value:
204 return false;
205 case PLTClass::Pointer:
206 return isKnownPointerLikeType(Ty, Context);
207 }
208 llvm_unreachable("Unknown PLTClass enum");
209}
210
211// FIXME: move over the other `maybe` functionality from Stencil. Should all be
212// in one place.
213std::optional<std::string> tooling::buildAccess(const Expr &RawExpression,
214 ASTContext &Context,
215 PLTClass Classification) {
216 if (RawExpression.isImplicitCXXThis())
217 // Return the empty string, because `std::nullopt` signifies some sort of
218 // failure.
219 return std::string();
220
221 const Expr *E = RawExpression.IgnoreImplicitAsWritten();
222
223 if (E->getType()->isAnyPointerType() ||
224 treatLikePointer(E->getType(), Classification, Context)) {
225 // Strip off operator-> calls. They can only occur inside an actual arrow
226 // member access, so we treat them as equivalent to an actual object
227 // expression.
228 if (const auto *Obj = maybeGetOperatorObjectArg(*E, clang::OO_Arrow))
229 E = Obj;
230 return buildAccessForPointer(*E, Context);
231 }
232
233 if (const auto *Obj = maybeGetOperatorObjectArg(*E, clang::OO_Star)) {
234 if (treatLikePointer(Obj->getType(), Classification, Context))
235 return buildAccessForPointer(*Obj, Context);
236 };
237
238 return buildAccessForValue(*E, Context);
239}
Defines the clang::ASTContext interface.
Defines the clang::Expr interface and subclasses for C++ expressions.
StringRef Text
Definition: Format.cpp:2974
static bool treatLikePointer(QualType Ty, PLTClass C, ASTContext &Context)
static std::optional< std::string > buildAccessForPointer(const Expr &E, const ASTContext &Context)
static std::optional< std::string > buildAccessForValue(const Expr &E, const ASTContext &Context)
static const Expr * maybeGetOperatorObjectArg(const Expr &E, OverloadedOperatorKind K)
This file collects facilities for generating source code strings.
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
Definition: ASTContext.h:182
This represents one expression.
Definition: Expr.h:110
bool isImplicitCXXThis() const
Whether this expression is an implicit reference to 'this' in C++.
Definition: Expr.cpp:3207
Expr * IgnoreParenImpCasts() LLVM_READONLY
Skip past any parentheses and implicit casts which might surround this expression until reaching a fi...
Definition: Expr.cpp:3031
Expr * IgnoreImplicit() LLVM_READONLY
Skip past any implicit AST nodes which might surround this expression until reaching a fixed point.
Definition: Expr.cpp:3019
Expr * IgnoreImplicitAsWritten() LLVM_READONLY
Skip past any implicit AST nodes which might surround this expression until reaching a fixed point.
Definition: Expr.cpp:3023
QualType getType() const
Definition: Expr.h:142
A (possibly-)qualified type.
Definition: Type.h:736
SourceRange getSourceRange() const LLVM_READONLY
SourceLocation tokens are not useful in isolation - they are low level value objects created/interpre...
Definition: Stmt.cpp:325
bool isAnyPointerType() const
Definition: Type.h:7037
SmallVector< BoundNodes, 1 > match(MatcherT Matcher, const NodeT &Node, ASTContext &Context)
Returns the results of matching Matcher on Node.
const internal::VariadicAllOfMatcher< Type > type
Matches Types in the clang AST.
const internal::VariadicFunction< internal::Matcher< NamedDecl >, StringRef, internal::hasAnyNameFunc > hasAnyName
Matches NamedDecl nodes that have any of the specified names.
const AstTypeMatcher< RecordType > recordType
Matches record types (e.g.
const internal::VariadicDynCastAllOfMatcher< Decl, CXXRecordDecl > cxxRecordDecl
Matches C++ class declarations.
internal::PolymorphicMatcher< internal::HasDeclarationMatcher, void(internal::HasDeclarationSupportedTypes), internal::Matcher< Decl > > hasDeclaration(const internal::Matcher< Decl > &InnerMatcher)
Matches a node if the declaration associated with that node matches the given matcher.
Definition: ASTMatchers.h:3640
std::optional< std::string > buildDereference(const Expr &E, const ASTContext &Context)
Builds idiomatic source for the dereferencing of E: prefix with * but simplify when it already begins...
std::optional< std::string > buildAddressOf(const Expr &E, const ASTContext &Context)
Builds idiomatic source for taking the address of E: prefix with & but simplify when it already begin...
bool isKnownPointerLikeType(QualType Ty, ASTContext &Context)
std::optional< std::string > buildArrow(const Expr &E, const ASTContext &Context)
Adds an arrow to the end of the given expression, but adds parentheses when needed by the syntax,...
bool needParensBeforeDotOrArrow(const Expr &E)
Determines whether printing this expression to the left of a dot or arrow operator requires a parenth...
std::optional< std::string > buildParens(const Expr &E, const ASTContext &Context)
Builds source for an expression, adding parens if needed for unambiguous parsing.
const Expr * reallyIgnoreImplicit(const Expr &E)
std::optional< std::string > buildAccess(const Expr &E, ASTContext &Context, PLTClass Classification=PLTClass::Pointer)
Adds an appropriate access operator (.
PLTClass
Specifies how to classify pointer-like types – like values or like pointers – with regard to generati...
bool mayEverNeedParens(const Expr &E)
Determines whether printing this expression in any expression requires parentheses to preserve its me...
bool needParensAfterUnaryOperator(const Expr &E)
Determines whether printing this expression to the right of a unary operator requires a parentheses t...
StringRef getText(CharSourceRange Range, const ASTContext &Context)
Returns the source-code text in the specified range.
Definition: SourceCode.cpp:31
std::optional< std::string > buildDot(const Expr &E, const ASTContext &Context)
Adds a dot to the end of the given expression, but adds parentheses when needed by the syntax,...
OverloadedOperatorKind
Enumeration specifying the different kinds of C++ overloaded operators.
Definition: OperatorKinds.h:21