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