clang  15.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 
76  const ASTContext &Context) {
77  StringRef Text = getText(E, Context);
78  if (Text.empty())
79  return llvm::None;
80  if (mayEverNeedParens(E))
81  return ("(" + Text + ")").str();
82  return Text.str();
83 }
84 
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 llvm::None;
94  return Text.str();
95  }
96 
97  StringRef Text = getText(E, Context);
98  if (Text.empty())
99  return llvm::None;
100  // Add leading '*'.
102  return ("*(" + Text + ")").str();
103  return ("*" + Text).str();
104 }
105 
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 llvm::None;
117  return Text.str();
118  }
119  // Add leading '&'.
120  StringRef Text = getText(E, Context);
121  if (Text.empty())
122  return llvm::None;
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.
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 llvm::None;
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 llvm::None;
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.
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 llvm::None;
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 llvm::None;
176  return ("(" + Text + ")->").str();
177  return (Text + "->").str();
178 }
179 
181  const ASTContext &Context) {
182  return buildAccessForValue(E, Context);
183 }
184 
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.
214  ASTContext &Context,
215  PLTClass Classification) {
216  if (RawExpression.isImplicitCXXThis())
217  // Return the empty string, because `None` signifies some sort of failure.
218  return std::string();
219 
220  const Expr *E = RawExpression.IgnoreImplicitAsWritten();
221 
222  if (E->getType()->isAnyPointerType() ||
223  treatLikePointer(E->getType(), Classification, Context)) {
224  // Strip off operator-> calls. They can only occur inside an actual arrow
225  // member access, so we treat them as equivalent to an actual object
226  // expression.
227  if (const auto *Obj = maybeGetOperatorObjectArg(*E, clang::OO_Arrow))
228  E = Obj;
229  return buildAccessForPointer(*E, Context);
230  }
231 
232  if (const auto *Obj = maybeGetOperatorObjectArg(*E, clang::OO_Star)) {
233  if (treatLikePointer(Obj->getType(), Classification, Context))
234  return buildAccessForPointer(*Obj, Context);
235  };
236 
237  return buildAccessForValue(*E, Context);
238 }
buildAccessForPointer
static llvm::Optional< std::string > buildAccessForPointer(const Expr &E, const ASTContext &Context)
Definition: SourceCodeBuilders.cpp:158
clang::tooling::buildDot
llvm::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,...
Definition: SourceCodeBuilders.cpp:180
clang::ast_matchers::hasAnyName
const internal::VariadicFunction< internal::Matcher< NamedDecl >, StringRef, internal::hasAnyNameFunc > hasAnyName
Matches NamedDecl nodes that have any of the specified names.
Definition: ASTMatchersInternal.cpp:997
maybeGetOperatorObjectArg
static const Expr * maybeGetOperatorObjectArg(const Expr &E, OverloadedOperatorKind K)
Definition: SourceCodeBuilders.cpp:192
treatLikePointer
static bool treatLikePointer(QualType Ty, PLTClass C, ASTContext &Context)
Definition: SourceCodeBuilders.cpp:201
string
string(SUBSTRING ${CMAKE_CURRENT_BINARY_DIR} 0 ${PATH_LIB_START} PATH_HEAD) string(SUBSTRING $
Definition: CMakeLists.txt:22
clang::Expr::IgnoreImplicit
Expr * IgnoreImplicit() LLVM_READONLY
Skip past any implicit AST nodes which might surround this expression until reaching a fixed point.
Definition: Expr.cpp:2935
clang::Stmt::getSourceRange
SourceRange getSourceRange() const LLVM_READONLY
SourceLocation tokens are not useful in isolation - they are low level value objects created/interpre...
Definition: Stmt.cpp:324
clang::QualType
A (possibly-)qualified type.
Definition: Type.h:675
clang::tooling::buildArrow
llvm::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,...
Definition: SourceCodeBuilders.cpp:185
clang::ast_matchers::type
const internal::VariadicAllOfMatcher< Type > type
Matches Types in the clang AST.
Definition: ASTMatchersInternal.cpp:773
llvm::Optional< std::string >
ASTMatchFinder.h
clang::tooling::mayEverNeedParens
bool mayEverNeedParens(const Expr &E)
Determines whether printing this expression in any expression requires parentheses to preserve its me...
Definition: SourceCodeBuilders.cpp:32
buildAccessForValue
static llvm::Optional< std::string > buildAccessForValue(const Expr &E, const ASTContext &Context)
Definition: SourceCodeBuilders.cpp:132
clang::tooling::buildParens
llvm::Optional< std::string > buildParens(const Expr &E, const ASTContext &Context)
Builds source for an expression, adding parens if needed for unambiguous parsing.
Definition: SourceCodeBuilders.cpp:75
clang::Expr::IgnoreImplicitAsWritten
Expr * IgnoreImplicitAsWritten() LLVM_READONLY
Skip past any implicit AST nodes which might surround this expression until reaching a fixed point.
Definition: Expr.cpp:2939
clang::tooling::buildAddressOf
llvm::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...
Definition: SourceCodeBuilders.cpp:106
clang::ASTContext
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
Definition: ASTContext.h:208
ASTMatchers.h
SourceCodeBuilders.h
Expr.h
ASTContext.h
clang::tooling::isKnownPointerLikeType
bool isKnownPointerLikeType(QualType Ty, ASTContext &Context)
Definition: SourceCodeBuilders.cpp:65
ExprCXX.h
clang::OverloadedOperatorKind
OverloadedOperatorKind
Enumeration specifying the different kinds of C++ overloaded operators.
Definition: OperatorKinds.h:21
clang::tooling::buildDereference
llvm::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...
Definition: SourceCodeBuilders.cpp:86
clang::Expr::isImplicitCXXThis
bool isImplicitCXXThis() const
Whether this expression is an implicit reference to 'this' in C++.
Definition: Expr.cpp:3123
clang::tooling::PLTClass::Pointer
@ Pointer
clang::tooling::reallyIgnoreImplicit
const Expr * reallyIgnoreImplicit(const Expr &E)
Definition: SourceCodeBuilders.cpp:22
SourceCode.h
clang::Expr::IgnoreParenImpCasts
Expr * IgnoreParenImpCasts() LLVM_READONLY
Skip past any parentheses and implicit casts which might surround this expression until reaching a fi...
Definition: Expr.cpp:2947
clang::ast_matchers::recordType
const AstTypeMatcher< RecordType > recordType
Matches record types (e.g.
Definition: ASTMatchersInternal.cpp:1059
clang::tooling::buildAccess
llvm::Optional< std::string > buildAccess(const Expr &E, ASTContext &Context, PLTClass Classification=PLTClass::Pointer)
Adds an appropriate access operator (.
Definition: SourceCodeBuilders.cpp:213
clang
Definition: CalledOnceCheck.h:17
clang::Type::isAnyPointerType
bool isAnyPointerType() const
Definition: Type.h:6752
Text
StringRef Text
Definition: Format.cpp:2569
clang::tooling::needParensBeforeDotOrArrow
bool needParensBeforeDotOrArrow(const Expr &E)
Determines whether printing this expression to the left of a dot or arrow operator requires a parenth...
Definition: SourceCodeBuilders.h:39
clang::ast_matchers::match
SmallVector< BoundNodes, 1 > match(MatcherT Matcher, const NodeT &Node, ASTContext &Context)
Returns the results of matching Matcher on Node.
Definition: ASTMatchFinder.h:312
clang::tooling::getText
StringRef getText(CharSourceRange Range, const ASTContext &Context)
Returns the source-code text in the specified range.
Definition: SourceCode.cpp:31
clang::Expr::getType
QualType getType() const
Definition: Expr.h:141
clang::tooling::needParensAfterUnaryOperator
bool needParensAfterUnaryOperator(const Expr &E)
Determines whether printing this expression to the right of a unary operator requires a parentheses t...
Definition: SourceCodeBuilders.cpp:52
clang::ast_matchers::cxxRecordDecl
const internal::VariadicDynCastAllOfMatcher< Decl, CXXRecordDecl > cxxRecordDecl
Matches C++ class declarations.
Definition: ASTMatchersInternal.cpp:745
clang::tooling::PLTClass::Value
@ Value
clang::Expr
This represents one expression.
Definition: Expr.h:109
clang::tooling::PLTClass
PLTClass
Specifies how to classify pointer-like types – like values or like pointers – with regard to generati...
Definition: SourceCodeBuilders.h:98
clang::ast_matchers::hasDeclaration
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:3565