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