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