clang 19.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:2970
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:3241
Expr * IgnoreParenImpCasts() LLVM_READONLY
Skip past any parentheses and implicit casts which might surround this expression until reaching a fi...
Definition: Expr.cpp:3065
Expr * IgnoreImplicit() LLVM_READONLY
Skip past any implicit AST nodes which might surround this expression until reaching a fixed point.
Definition: Expr.cpp:3053
Expr * IgnoreImplicitAsWritten() LLVM_READONLY
Skip past any implicit AST nodes which might surround this expression until reaching a fixed point.
Definition: Expr.cpp:3057
QualType getType() const
Definition: Expr.h:142
A (possibly-)qualified type.
Definition: Type.h:738
SourceRange getSourceRange() const LLVM_READONLY
SourceLocation tokens are not useful in isolation - they are low level value objects created/interpre...
Definition: Stmt.cpp:326
bool isAnyPointerType() const
Definition: Type.h:7375
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:3652
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,...
The JSON file list parser is used to communicate input to InstallAPI.
OverloadedOperatorKind
Enumeration specifying the different kinds of C++ overloaded operators.
Definition: OperatorKinds.h:21