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