Coverage Report

Created: 2021-08-24 07:12

/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
63
const Expr *tooling::reallyIgnoreImplicit(const Expr &E) {
21
63
  const Expr *Expr = E.IgnoreImplicit();
22
63
  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
2
  }
27
61
  return Expr;
28
63
}
29
30
37
bool tooling::mayEverNeedParens(const Expr &E) {
31
37
  const Expr *Expr = reallyIgnoreImplicit(E);
32
  // We always want parens around unary, binary, and ternary operators, because
33
  // they are lower precedence.
34
37
  if (isa<UnaryOperator>(Expr) || 
isa<BinaryOperator>(Expr)34
||
35
37
      
isa<AbstractConditionalOperator>(Expr)28
)
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
26
  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
25
  return false;
48
26
}
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
3
           
Op->getOperator() != OO_MinusMinus2
&&
Op->getOperator() != OO_Call2
&&
58
3
           
Op->getOperator() != OO_Subscript2
;
59
60
16
  return false;
61
19
}
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
8
}
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
9
}
93
94
llvm::Optional<std::string> tooling::buildAddressOf(const Expr &E,
95
11
                                                    const ASTContext &Context) {
96
11
  if (E.isImplicitCXXThis())
97
1
    return std::string("this");
98
10
  if (const auto *Op = dyn_cast<UnaryOperator>(&E))
99
4
    if (Op->getOpcode() == UO_Deref) {
100
      // Strip leading '*'.
101
4
      StringRef Text =
102
4
          getText(*Op->getSubExpr()->IgnoreParenImpCasts(), Context);
103
4
      if (Text.empty())
104
0
        return llvm::None;
105
4
      return Text.str();
106
4
    }
107
  // Add leading '&'.
108
6
  StringRef Text = getText(E, Context);
109
6
  if (Text.empty())
110
0
    return llvm::None;
111
6
  if (needParensAfterUnaryOperator(E)) {
112
2
    return ("&(" + Text + ")").str();
113
2
  }
114
4
  return ("&" + Text).str();
115
6
}
116
117
llvm::Optional<std::string> tooling::buildDot(const Expr &E,
118
8
                                              const ASTContext &Context) {
119
8
  if (const auto *Op = llvm::dyn_cast<UnaryOperator>(&E))
120
4
    if (Op->getOpcode() == UO_Deref) {
121
      // Strip leading '*', add following '->'.
122
4
      const Expr *SubExpr = Op->getSubExpr()->IgnoreParenImpCasts();
123
4
      StringRef DerefText = getText(*SubExpr, Context);
124
4
      if (DerefText.empty())
125
0
        return llvm::None;
126
4
      if (needParensBeforeDotOrArrow(*SubExpr))
127
1
        return ("(" + DerefText + ")->").str();
128
3
      return (DerefText + "->").str();
129
4
    }
130
131
  // Add following '.'.
132
4
  StringRef Text = getText(E, Context);
133
4
  if (Text.empty())
134
0
    return llvm::None;
135
4
  if (needParensBeforeDotOrArrow(E)) {
136
1
    return ("(" + Text + ").").str();
137
1
  }
138
3
  return (Text + ".").str();
139
4
}
140
141
llvm::Optional<std::string> tooling::buildArrow(const Expr &E,
142
11
                                                const ASTContext &Context) {
143
11
  if (const auto *Op = llvm::dyn_cast<UnaryOperator>(&E))
144
4
    if (Op->getOpcode() == UO_AddrOf) {
145
      // Strip leading '&', add following '.'.
146
4
      const Expr *SubExpr = Op->getSubExpr()->IgnoreParenImpCasts();
147
4
      StringRef DerefText = getText(*SubExpr, Context);
148
4
      if (DerefText.empty())
149
0
        return llvm::None;
150
4
      if (needParensBeforeDotOrArrow(*SubExpr))
151
1
        return ("(" + DerefText + ").").str();
152
3
      return (DerefText + ".").str();
153
4
    }
154
155
  // Add following '->'.
156
7
  StringRef Text = getText(E, Context);
157
7
  if (Text.empty())
158
0
    return llvm::None;
159
7
  if (needParensBeforeDotOrArrow(E))
160
1
    return ("(" + Text + ")->").str();
161
6
  return (Text + "->").str();
162
7
}