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 
10 #include "clang/AST/ASTContext.h"
11 #include "clang/AST/Expr.h"
12 #include "clang/AST/ExprCXX.h"
16 #include "llvm/ADT/Twine.h"
17 #include <string>
18 
19 using namespace clang;
20 using 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 
75 std::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 
85 std::optional<std::string>
86 tooling::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 
106 std::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.
131 static std::optional<std::string>
132 buildAccessForValue(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.
157 static std::optional<std::string>
158 buildAccessForPointer(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 
180 std::optional<std::string> tooling::buildDot(const Expr &E,
181  const ASTContext &Context) {
182  return buildAccessForValue(E, Context);
183 }
184 
185 std::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`.
192 static 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 
201 static 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.
213 std::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:2977
static const Expr * maybeGetOperatorObjectArg(const Expr &E, OverloadedOperatorKind K)
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)
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:185
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:3287
Expr * IgnoreParenImpCasts() LLVM_READONLY
Skip past any parentheses and implicit casts which might surround this expression until reaching a fi...
Definition: Expr.cpp:3111
Expr * IgnoreImplicit() LLVM_READONLY
Skip past any implicit AST nodes which might surround this expression until reaching a fixed point.
Definition: Expr.cpp:3099
Expr * IgnoreImplicitAsWritten() LLVM_READONLY
Skip past any implicit AST nodes which might surround this expression until reaching a fixed point.
Definition: Expr.cpp:3103
QualType getType() const
Definition: Expr.h:142
A (possibly-)qualified type.
Definition: Type.h:940
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:7628
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.
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:3653
const AstTypeMatcher< RecordType > recordType
Matches record types (e.g.
const internal::VariadicDynCastAllOfMatcher< Decl, CXXRecordDecl > cxxRecordDecl
Matches C++ class declarations.
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