Coverage Report

Created: 2020-09-22 08:39

/Users/buildslave/jenkins/workspace/coverage/llvm-project/clang/lib/Sema/SemaFixItUtils.cpp
Line
Count
Source (jump to first uncovered line)
1
//===--- SemaFixItUtils.cpp - Sema FixIts ---------------------------------===//
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
//  This file defines helper classes for generation of Sema FixItHints.
10
//
11
//===----------------------------------------------------------------------===//
12
13
#include "clang/AST/ASTContext.h"
14
#include "clang/AST/ExprCXX.h"
15
#include "clang/AST/ExprObjC.h"
16
#include "clang/Lex/Preprocessor.h"
17
#include "clang/Sema/Sema.h"
18
#include "clang/Sema/SemaFixItUtils.h"
19
20
using namespace clang;
21
22
bool ConversionFixItGenerator::compareTypesSimple(CanQualType From,
23
                                                  CanQualType To,
24
                                                  Sema &S,
25
                                                  SourceLocation Loc,
26
1.65k
                                                  ExprValueKind FromVK) {
27
1.65k
  if (!To.isAtLeastAsQualifiedAs(From))
28
488
    return false;
29
30
1.16k
  From = From.getNonReferenceType();
31
1.16k
  To = To.getNonReferenceType();
32
33
  // If both are pointer types, work with the pointee types.
34
1.16k
  if (isa<PointerType>(From) && 
isa<PointerType>(To)909
) {
35
903
    From = S.Context.getCanonicalType(
36
903
        (cast<PointerType>(From))->getPointeeType());
37
903
    To = S.Context.getCanonicalType(
38
903
        (cast<PointerType>(To))->getPointeeType());
39
903
  }
40
41
1.16k
  const CanQualType FromUnq = From.getUnqualifiedType();
42
1.16k
  const CanQualType ToUnq = To.getUnqualifiedType();
43
44
1.16k
  if ((FromUnq == ToUnq || 
(S.IsDerivedFrom(Loc, FromUnq, ToUnq))1.12k
) &&
45
51
      To.isAtLeastAsQualifiedAs(From))
46
51
    return true;
47
1.11k
  return false;
48
1.11k
}
49
50
bool ConversionFixItGenerator::tryToFixConversion(const Expr *FullExpr,
51
                                                  const QualType FromTy,
52
                                                  const QualType ToTy,
53
15.0k
                                                  Sema &S) {
54
15.0k
  if (!FullExpr)
55
690
    return false;
56
57
14.3k
  const CanQualType FromQTy = S.Context.getCanonicalType(FromTy);
58
14.3k
  const CanQualType ToQTy = S.Context.getCanonicalType(ToTy);
59
14.3k
  const SourceLocation Begin = FullExpr->getSourceRange().getBegin();
60
14.3k
  const SourceLocation End = S.getLocForEndOfToken(FullExpr->getSourceRange()
61
14.3k
                                                   .getEnd());
62
63
  // Strip the implicit casts - those are implied by the compiler, not the
64
  // original source code.
65
14.3k
  const Expr* Expr = FullExpr->IgnoreImpCasts();
66
67
14.3k
  bool NeedParen = true;
68
14.3k
  if (isa<ArraySubscriptExpr>(Expr) ||
69
14.3k
      isa<CallExpr>(Expr) ||
70
9.58k
      isa<DeclRefExpr>(Expr) ||
71
5.12k
      isa<CastExpr>(Expr) ||
72
5.02k
      isa<CXXNewExpr>(Expr) ||
73
5.01k
      isa<CXXConstructExpr>(Expr) ||
74
4.52k
      isa<CXXDeleteExpr>(Expr) ||
75
4.52k
      isa<CXXNoexceptExpr>(Expr) ||
76
4.52k
      isa<CXXPseudoDestructorExpr>(Expr) ||
77
4.52k
      isa<CXXScalarValueInitExpr>(Expr) ||
78
4.51k
      isa<CXXThisExpr>(Expr) ||
79
4.51k
      isa<CXXTypeidExpr>(Expr) ||
80
4.51k
      isa<CXXUnresolvedConstructExpr>(Expr) ||
81
4.51k
      isa<ObjCMessageExpr>(Expr) ||
82
4.33k
      isa<ObjCPropertyRefExpr>(Expr) ||
83
4.33k
      isa<ObjCProtocolExpr>(Expr) ||
84
4.33k
      isa<MemberExpr>(Expr) ||
85
4.29k
      isa<ParenExpr>(FullExpr) ||
86
3.24k
      isa<ParenListExpr>(Expr) ||
87
3.24k
      isa<SizeOfPackExpr>(Expr) ||
88
3.24k
      isa<UnaryOperator>(Expr))
89
11.2k
    NeedParen = false;
90
91
  // Check if the argument needs to be dereferenced:
92
  //   (type * -> type) or (type * -> type &).
93
14.3k
  if (const PointerType *FromPtrTy = dyn_cast<PointerType>(FromQTy)) {
94
943
    OverloadFixItKind FixKind = OFIK_Dereference;
95
96
943
    bool CanConvert = CompareTypes(
97
943
      S.Context.getCanonicalType(FromPtrTy->getPointeeType()), ToQTy,
98
943
                                 S, Begin, VK_LValue);
99
943
    if (CanConvert) {
100
      // Do not suggest dereferencing a Null pointer.
101
59
      if (Expr->IgnoreParenCasts()->
102
59
          isNullPointerConstant(S.Context, Expr::NPC_ValueDependentIsNotNull))
103
12
        return false;
104
105
47
      if (const UnaryOperator *UO = dyn_cast<UnaryOperator>(Expr)) {
106
8
        if (UO->getOpcode() == UO_AddrOf) {
107
8
          FixKind = OFIK_RemoveTakeAddress;
108
8
          Hints.push_back(FixItHint::CreateRemoval(
109
8
                            CharSourceRange::getTokenRange(Begin, Begin)));
110
8
        }
111
39
      } else if (NeedParen) {
112
5
        Hints.push_back(FixItHint::CreateInsertion(Begin, "*("));
113
5
        Hints.push_back(FixItHint::CreateInsertion(End, ")"));
114
34
      } else {
115
34
        Hints.push_back(FixItHint::CreateInsertion(Begin, "*"));
116
34
      }
117
118
47
      NumConversionsFixed++;
119
47
      if (NumConversionsFixed == 1)
120
46
        Kind = FixKind;
121
47
      return true;
122
47
    }
123
943
  }
124
125
  // Check if the pointer to the argument needs to be passed:
126
  //   (type -> type *) or (type & -> type *).
127
14.2k
  if (isa<PointerType>(ToQTy)) {
128
1.50k
    bool CanConvert = false;
129
1.50k
    OverloadFixItKind FixKind = OFIK_TakeAddress;
130
131
    // Only suggest taking address of L-values.
132
1.50k
    if (!Expr->isLValue() || 
Expr->getObjectKind() != OK_Ordinary1.03k
)
133
471
      return false;
134
135
1.03k
    CanConvert = CompareTypes(S.Context.getPointerType(FromQTy), ToQTy,
136
1.03k
                              S, Begin, VK_RValue);
137
1.03k
    if (CanConvert) {
138
139
48
      if (const UnaryOperator *UO = dyn_cast<UnaryOperator>(Expr)) {
140
3
        if (UO->getOpcode() == UO_Deref) {
141
3
          FixKind = OFIK_RemoveDereference;
142
3
          Hints.push_back(FixItHint::CreateRemoval(
143
3
                            CharSourceRange::getTokenRange(Begin, Begin)));
144
3
        }
145
45
      } else if (NeedParen) {
146
0
        Hints.push_back(FixItHint::CreateInsertion(Begin, "&("));
147
0
        Hints.push_back(FixItHint::CreateInsertion(End, ")"));
148
45
      } else {
149
45
        Hints.push_back(FixItHint::CreateInsertion(Begin, "&"));
150
45
      }
151
152
48
      NumConversionsFixed++;
153
48
      if (NumConversionsFixed == 1)
154
47
        Kind = FixKind;
155
48
      return true;
156
48
    }
157
13.7k
  }
158
159
13.7k
  return false;
160
13.7k
}
161
162
24
static bool isMacroDefined(const Sema &S, SourceLocation Loc, StringRef Name) {
163
24
  return (bool)S.PP.getMacroDefinitionAtLoc(&S.getASTContext().Idents.get(Name),
164
24
                                            Loc);
165
24
}
166
167
static std::string getScalarZeroExpressionForType(
168
1.18k
    const Type &T, SourceLocation Loc, const Sema &S) {
169
1.18k
  assert(T.isScalarType() && "use scalar types only");
170
  // Suggest "0" for non-enumeration scalar types, unless we can find a
171
  // better initializer.
172
1.18k
  if (T.isEnumeralType())
173
1
    return std::string();
174
1.18k
  if ((T.isObjCObjectPointerType() || T.isBlockPointerType()) &&
175
0
      isMacroDefined(S, Loc, "nil"))
176
0
    return "nil";
177
1.18k
  if (T.isRealFloatingType())
178
16
    return "0.0";
179
1.16k
  if (T.isBooleanType() &&
180
47
      (S.LangOpts.CPlusPlus || 
isMacroDefined(S, Loc, "false")6
))
181
43
    return "false";
182
1.12k
  if (T.isPointerType() || 
T.isMemberPointerType()1.08k
) {
183
36
    if (S.LangOpts.CPlusPlus11)
184
18
      return "nullptr";
185
18
    if (isMacroDefined(S, Loc, "NULL"))
186
6
      return "NULL";
187
1.09k
  }
188
1.09k
  if (T.isCharType())
189
19
    return "'\\0'";
190
1.07k
  if (T.isWideCharType())
191
2
    return "L'\\0'";
192
1.07k
  if (T.isChar16Type())
193
2
    return "u'\\0'";
194
1.07k
  if (T.isChar32Type())
195
2
    return "U'\\0'";
196
1.07k
  return "0";
197
1.07k
}
198
199
std::string
200
1.16k
Sema::getFixItZeroInitializerForType(QualType T, SourceLocation Loc) const {
201
1.16k
  if (T->isScalarType()) {
202
1.10k
    std::string s = getScalarZeroExpressionForType(*T, Loc, *this);
203
1.10k
    if (!s.empty())
204
1.10k
      s = " = " + s;
205
1.10k
    return s;
206
1.10k
  }
207
208
58
  const CXXRecordDecl *RD = T->getAsCXXRecordDecl();
209
58
  if (!RD || 
!RD->hasDefinition()44
)
210
18
    return std::string();
211
40
  if (LangOpts.CPlusPlus11 && 
!RD->hasUserProvidedDefaultConstructor()29
)
212
27
    return "{}";
213
13
  if (RD->isAggregate())
214
9
    return " = {}";
215
4
  return std::string();
216
4
}
217
218
std::string
219
77
Sema::getFixItZeroLiteralForType(QualType T, SourceLocation Loc) const {
220
77
  return getScalarZeroExpressionForType(*T, Loc, *this);
221
77
}