xref: /freebsd-src/contrib/llvm-project/clang/lib/Tooling/Transformer/SourceCodeBuilders.cpp (revision a7dea1671b87c07d2d266f836bfa8b58efc7c134)
1*a7dea167SDimitry Andric //===--- SourceCodeBuilder.cpp ----------------------------------*- C++ -*-===//
2*a7dea167SDimitry Andric //
3*a7dea167SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*a7dea167SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5*a7dea167SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*a7dea167SDimitry Andric //
7*a7dea167SDimitry Andric //===----------------------------------------------------------------------===//
8*a7dea167SDimitry Andric 
9*a7dea167SDimitry Andric #include "clang/Tooling/Transformer/SourceCodeBuilders.h"
10*a7dea167SDimitry Andric #include "clang/AST/ASTContext.h"
11*a7dea167SDimitry Andric #include "clang/AST/Expr.h"
12*a7dea167SDimitry Andric #include "clang/AST/ExprCXX.h"
13*a7dea167SDimitry Andric #include "clang/Tooling/Transformer/SourceCode.h"
14*a7dea167SDimitry Andric #include "llvm/ADT/Twine.h"
15*a7dea167SDimitry Andric #include <string>
16*a7dea167SDimitry Andric 
17*a7dea167SDimitry Andric using namespace clang;
18*a7dea167SDimitry Andric using namespace tooling;
19*a7dea167SDimitry Andric 
20*a7dea167SDimitry Andric const Expr *tooling::reallyIgnoreImplicit(const Expr &E) {
21*a7dea167SDimitry Andric   const Expr *Expr = E.IgnoreImplicit();
22*a7dea167SDimitry Andric   if (const auto *CE = dyn_cast<CXXConstructExpr>(Expr)) {
23*a7dea167SDimitry Andric     if (CE->getNumArgs() > 0 &&
24*a7dea167SDimitry Andric         CE->getArg(0)->getSourceRange() == Expr->getSourceRange())
25*a7dea167SDimitry Andric       return CE->getArg(0)->IgnoreImplicit();
26*a7dea167SDimitry Andric   }
27*a7dea167SDimitry Andric   return Expr;
28*a7dea167SDimitry Andric }
29*a7dea167SDimitry Andric 
30*a7dea167SDimitry Andric bool tooling::mayEverNeedParens(const Expr &E) {
31*a7dea167SDimitry Andric   const Expr *Expr = reallyIgnoreImplicit(E);
32*a7dea167SDimitry Andric   // We always want parens around unary, binary, and ternary operators, because
33*a7dea167SDimitry Andric   // they are lower precedence.
34*a7dea167SDimitry Andric   if (isa<UnaryOperator>(Expr) || isa<BinaryOperator>(Expr) ||
35*a7dea167SDimitry Andric       isa<AbstractConditionalOperator>(Expr))
36*a7dea167SDimitry Andric     return true;
37*a7dea167SDimitry Andric 
38*a7dea167SDimitry Andric   // We need parens around calls to all overloaded operators except: function
39*a7dea167SDimitry Andric   // calls, subscripts, and expressions that are already part of an (implicit)
40*a7dea167SDimitry Andric   // call to operator->. These latter are all in the same precedence level as
41*a7dea167SDimitry Andric   // dot/arrow and that level is left associative, so they don't need parens
42*a7dea167SDimitry Andric   // when appearing on the left.
43*a7dea167SDimitry Andric   if (const auto *Op = dyn_cast<CXXOperatorCallExpr>(Expr))
44*a7dea167SDimitry Andric     return Op->getOperator() != OO_Call && Op->getOperator() != OO_Subscript &&
45*a7dea167SDimitry Andric            Op->getOperator() != OO_Arrow;
46*a7dea167SDimitry Andric 
47*a7dea167SDimitry Andric   return false;
48*a7dea167SDimitry Andric }
49*a7dea167SDimitry Andric 
50*a7dea167SDimitry Andric bool tooling::needParensAfterUnaryOperator(const Expr &E) {
51*a7dea167SDimitry Andric   const Expr *Expr = reallyIgnoreImplicit(E);
52*a7dea167SDimitry Andric   if (isa<BinaryOperator>(Expr) || isa<AbstractConditionalOperator>(Expr))
53*a7dea167SDimitry Andric     return true;
54*a7dea167SDimitry Andric 
55*a7dea167SDimitry Andric   if (const auto *Op = dyn_cast<CXXOperatorCallExpr>(Expr))
56*a7dea167SDimitry Andric     return Op->getNumArgs() == 2 && Op->getOperator() != OO_PlusPlus &&
57*a7dea167SDimitry Andric            Op->getOperator() != OO_MinusMinus && Op->getOperator() != OO_Call &&
58*a7dea167SDimitry Andric            Op->getOperator() != OO_Subscript;
59*a7dea167SDimitry Andric 
60*a7dea167SDimitry Andric   return false;
61*a7dea167SDimitry Andric }
62*a7dea167SDimitry Andric 
63*a7dea167SDimitry Andric llvm::Optional<std::string> tooling::buildParens(const Expr &E,
64*a7dea167SDimitry Andric                                                  const ASTContext &Context) {
65*a7dea167SDimitry Andric   StringRef Text = getText(E, Context);
66*a7dea167SDimitry Andric   if (Text.empty())
67*a7dea167SDimitry Andric     return llvm::None;
68*a7dea167SDimitry Andric   if (mayEverNeedParens(E))
69*a7dea167SDimitry Andric     return ("(" + Text + ")").str();
70*a7dea167SDimitry Andric   return Text.str();
71*a7dea167SDimitry Andric }
72*a7dea167SDimitry Andric 
73*a7dea167SDimitry Andric llvm::Optional<std::string>
74*a7dea167SDimitry Andric tooling::buildDereference(const Expr &E, const ASTContext &Context) {
75*a7dea167SDimitry Andric   if (const auto *Op = dyn_cast<UnaryOperator>(&E))
76*a7dea167SDimitry Andric     if (Op->getOpcode() == UO_AddrOf) {
77*a7dea167SDimitry Andric       // Strip leading '&'.
78*a7dea167SDimitry Andric       StringRef Text =
79*a7dea167SDimitry Andric           getText(*Op->getSubExpr()->IgnoreParenImpCasts(), Context);
80*a7dea167SDimitry Andric       if (Text.empty())
81*a7dea167SDimitry Andric         return llvm::None;
82*a7dea167SDimitry Andric       return Text.str();
83*a7dea167SDimitry Andric     }
84*a7dea167SDimitry Andric 
85*a7dea167SDimitry Andric   StringRef Text = getText(E, Context);
86*a7dea167SDimitry Andric   if (Text.empty())
87*a7dea167SDimitry Andric     return llvm::None;
88*a7dea167SDimitry Andric   // Add leading '*'.
89*a7dea167SDimitry Andric   if (needParensAfterUnaryOperator(E))
90*a7dea167SDimitry Andric     return ("*(" + Text + ")").str();
91*a7dea167SDimitry Andric   return ("*" + Text).str();
92*a7dea167SDimitry Andric }
93*a7dea167SDimitry Andric 
94*a7dea167SDimitry Andric llvm::Optional<std::string> tooling::buildAddressOf(const Expr &E,
95*a7dea167SDimitry Andric                                                     const ASTContext &Context) {
96*a7dea167SDimitry Andric   if (const auto *Op = dyn_cast<UnaryOperator>(&E))
97*a7dea167SDimitry Andric     if (Op->getOpcode() == UO_Deref) {
98*a7dea167SDimitry Andric       // Strip leading '*'.
99*a7dea167SDimitry Andric       StringRef Text =
100*a7dea167SDimitry Andric           getText(*Op->getSubExpr()->IgnoreParenImpCasts(), Context);
101*a7dea167SDimitry Andric       if (Text.empty())
102*a7dea167SDimitry Andric         return llvm::None;
103*a7dea167SDimitry Andric       return Text.str();
104*a7dea167SDimitry Andric     }
105*a7dea167SDimitry Andric   // Add leading '&'.
106*a7dea167SDimitry Andric   StringRef Text = getText(E, Context);
107*a7dea167SDimitry Andric   if (Text.empty())
108*a7dea167SDimitry Andric     return llvm::None;
109*a7dea167SDimitry Andric   if (needParensAfterUnaryOperator(E)) {
110*a7dea167SDimitry Andric     return ("&(" + Text + ")").str();
111*a7dea167SDimitry Andric   }
112*a7dea167SDimitry Andric   return ("&" + Text).str();
113*a7dea167SDimitry Andric }
114*a7dea167SDimitry Andric 
115*a7dea167SDimitry Andric llvm::Optional<std::string> tooling::buildDot(const Expr &E,
116*a7dea167SDimitry Andric                                               const ASTContext &Context) {
117*a7dea167SDimitry Andric   if (const auto *Op = llvm::dyn_cast<UnaryOperator>(&E))
118*a7dea167SDimitry Andric     if (Op->getOpcode() == UO_Deref) {
119*a7dea167SDimitry Andric       // Strip leading '*', add following '->'.
120*a7dea167SDimitry Andric       const Expr *SubExpr = Op->getSubExpr()->IgnoreParenImpCasts();
121*a7dea167SDimitry Andric       StringRef DerefText = getText(*SubExpr, Context);
122*a7dea167SDimitry Andric       if (DerefText.empty())
123*a7dea167SDimitry Andric         return llvm::None;
124*a7dea167SDimitry Andric       if (needParensBeforeDotOrArrow(*SubExpr))
125*a7dea167SDimitry Andric         return ("(" + DerefText + ")->").str();
126*a7dea167SDimitry Andric       return (DerefText + "->").str();
127*a7dea167SDimitry Andric     }
128*a7dea167SDimitry Andric 
129*a7dea167SDimitry Andric   // Add following '.'.
130*a7dea167SDimitry Andric   StringRef Text = getText(E, Context);
131*a7dea167SDimitry Andric   if (Text.empty())
132*a7dea167SDimitry Andric     return llvm::None;
133*a7dea167SDimitry Andric   if (needParensBeforeDotOrArrow(E)) {
134*a7dea167SDimitry Andric     return ("(" + Text + ").").str();
135*a7dea167SDimitry Andric   }
136*a7dea167SDimitry Andric   return (Text + ".").str();
137*a7dea167SDimitry Andric }
138*a7dea167SDimitry Andric 
139*a7dea167SDimitry Andric llvm::Optional<std::string> tooling::buildArrow(const Expr &E,
140*a7dea167SDimitry Andric                                                 const ASTContext &Context) {
141*a7dea167SDimitry Andric   if (const auto *Op = llvm::dyn_cast<UnaryOperator>(&E))
142*a7dea167SDimitry Andric     if (Op->getOpcode() == UO_AddrOf) {
143*a7dea167SDimitry Andric       // Strip leading '&', add following '.'.
144*a7dea167SDimitry Andric       const Expr *SubExpr = Op->getSubExpr()->IgnoreParenImpCasts();
145*a7dea167SDimitry Andric       StringRef DerefText = getText(*SubExpr, Context);
146*a7dea167SDimitry Andric       if (DerefText.empty())
147*a7dea167SDimitry Andric         return llvm::None;
148*a7dea167SDimitry Andric       if (needParensBeforeDotOrArrow(*SubExpr))
149*a7dea167SDimitry Andric         return ("(" + DerefText + ").").str();
150*a7dea167SDimitry Andric       return (DerefText + ".").str();
151*a7dea167SDimitry Andric     }
152*a7dea167SDimitry Andric 
153*a7dea167SDimitry Andric   // Add following '->'.
154*a7dea167SDimitry Andric   StringRef Text = getText(E, Context);
155*a7dea167SDimitry Andric   if (Text.empty())
156*a7dea167SDimitry Andric     return llvm::None;
157*a7dea167SDimitry Andric   if (needParensBeforeDotOrArrow(E))
158*a7dea167SDimitry Andric     return ("(" + Text + ")->").str();
159*a7dea167SDimitry Andric   return (Text + "->").str();
160*a7dea167SDimitry Andric }
161