Coverage Report

Created: 2019-07-24 05:18

/Users/buildslave/jenkins/workspace/clang-stage2-coverage-R/llvm/tools/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.57k
                                                  ExprValueKind FromVK) {
27
1.57k
  if (!To.isAtLeastAsQualifiedAs(From))
28
528
    return false;
29
1.04k
30
1.04k
  From = From.getNonReferenceType();
31
1.04k
  To = To.getNonReferenceType();
32
1.04k
33
1.04k
  // If both are pointer types, work with the pointee types.
34
1.04k
  if (isa<PointerType>(From) && 
isa<PointerType>(To)724
) {
35
718
    From = S.Context.getCanonicalType(
36
718
        (cast<PointerType>(From))->getPointeeType());
37
718
    To = S.Context.getCanonicalType(
38
718
        (cast<PointerType>(To))->getPointeeType());
39
718
  }
40
1.04k
41
1.04k
  const CanQualType FromUnq = From.getUnqualifiedType();
42
1.04k
  const CanQualType ToUnq = To.getUnqualifiedType();
43
1.04k
44
1.04k
  if ((FromUnq == ToUnq || 
(S.IsDerivedFrom(Loc, FromUnq, ToUnq))990
) &&
45
1.04k
      
To.isAtLeastAsQualifiedAs(From)65
)
46
65
    return true;
47
980
  return false;
48
980
}
49
50
bool ConversionFixItGenerator::tryToFixConversion(const Expr *FullExpr,
51
                                                  const QualType FromTy,
52
                                                  const QualType ToTy,
53
406k
                                                  Sema &S) {
54
406k
  if (!FullExpr)
55
2.03k
    return false;
56
404k
57
404k
  const CanQualType FromQTy = S.Context.getCanonicalType(FromTy);
58
404k
  const CanQualType ToQTy = S.Context.getCanonicalType(ToTy);
59
404k
  const SourceLocation Begin = FullExpr->getSourceRange().getBegin();
60
404k
  const SourceLocation End = S.getLocForEndOfToken(FullExpr->getSourceRange()
61
404k
                                                   .getEnd());
62
404k
63
404k
  // Strip the implicit casts - those are implied by the compiler, not the
64
404k
  // original source code.
65
404k
  const Expr* Expr = FullExpr->IgnoreImpCasts();
66
404k
67
404k
  bool NeedParen = true;
68
404k
  if (isa<ArraySubscriptExpr>(Expr) ||
69
404k
      
isa<CallExpr>(Expr)404k
||
70
404k
      
isa<DeclRefExpr>(Expr)404k
||
71
404k
      
isa<CastExpr>(Expr)4.78k
||
72
404k
      
isa<CXXNewExpr>(Expr)4.27k
||
73
404k
      
isa<CXXConstructExpr>(Expr)4.26k
||
74
404k
      
isa<CXXDeleteExpr>(Expr)3.59k
||
75
404k
      
isa<CXXNoexceptExpr>(Expr)3.59k
||
76
404k
      
isa<CXXPseudoDestructorExpr>(Expr)3.59k
||
77
404k
      
isa<CXXScalarValueInitExpr>(Expr)3.59k
||
78
404k
      
isa<CXXThisExpr>(Expr)3.59k
||
79
404k
      
isa<CXXTypeidExpr>(Expr)3.59k
||
80
404k
      
isa<CXXUnresolvedConstructExpr>(Expr)3.58k
||
81
404k
      
isa<ObjCMessageExpr>(Expr)3.58k
||
82
404k
      
isa<ObjCPropertyRefExpr>(Expr)3.40k
||
83
404k
      
isa<ObjCProtocolExpr>(Expr)3.40k
||
84
404k
      
isa<MemberExpr>(Expr)3.40k
||
85
404k
      
isa<ParenExpr>(FullExpr)3.12k
||
86
404k
      
isa<ParenListExpr>(Expr)1.90k
||
87
404k
      
isa<SizeOfPackExpr>(Expr)1.90k
||
88
404k
      
isa<UnaryOperator>(Expr)1.90k
)
89
403k
    NeedParen = false;
90
404k
91
404k
  // Check if the argument needs to be dereferenced:
92
404k
  //   (type * -> type) or (type * -> type &).
93
404k
  if (const PointerType *FromPtrTy = dyn_cast<PointerType>(FromQTy)) {
94
1.04k
    OverloadFixItKind FixKind = OFIK_Dereference;
95
1.04k
96
1.04k
    bool CanConvert = CompareTypes(
97
1.04k
      S.Context.getCanonicalType(FromPtrTy->getPointeeType()), ToQTy,
98
1.04k
                                 S, Begin, VK_LValue);
99
1.04k
    if (CanConvert) {
100
69
      // Do not suggest dereferencing a Null pointer.
101
69
      if (Expr->IgnoreParenCasts()->
102
69
          isNullPointerConstant(S.Context, Expr::NPC_ValueDependentIsNotNull))
103
12
        return false;
104
57
105
57
      if (const UnaryOperator *UO = dyn_cast<UnaryOperator>(Expr)) {
106
6
        if (UO->getOpcode() == UO_AddrOf) {
107
6
          FixKind = OFIK_RemoveTakeAddress;
108
6
          Hints.push_back(FixItHint::CreateRemoval(
109
6
                            CharSourceRange::getTokenRange(Begin, Begin)));
110
6
        }
111
51
      } else if (NeedParen) {
112
5
        Hints.push_back(FixItHint::CreateInsertion(Begin, "*("));
113
5
        Hints.push_back(FixItHint::CreateInsertion(End, ")"));
114
46
      } else {
115
46
        Hints.push_back(FixItHint::CreateInsertion(Begin, "*"));
116
46
      }
117
57
118
57
      NumConversionsFixed++;
119
57
      if (NumConversionsFixed == 1)
120
57
        Kind = FixKind;
121
57
      return true;
122
57
    }
123
1.04k
  }
124
404k
125
404k
  // Check if the pointer to the argument needs to be passed:
126
404k
  //   (type -> type *) or (type & -> type *).
127
404k
  if (isa<PointerType>(ToQTy)) {
128
1.29k
    bool CanConvert = false;
129
1.29k
    OverloadFixItKind FixKind = OFIK_TakeAddress;
130
1.29k
131
1.29k
    // Only suggest taking address of L-values.
132
1.29k
    if (!Expr->isLValue() || 
Expr->getObjectKind() != OK_Ordinary856
)
133
438
      return false;
134
856
135
856
    CanConvert = CompareTypes(S.Context.getPointerType(FromQTy), ToQTy,
136
856
                              S, Begin, VK_RValue);
137
856
    if (CanConvert) {
138
48
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
48
152
48
      NumConversionsFixed++;
153
48
      if (NumConversionsFixed == 1)
154
47
        Kind = FixKind;
155
48
      return true;
156
48
    }
157
404k
  }
158
404k
159
404k
  return false;
160
404k
}
161
162
20
static bool isMacroDefined(const Sema &S, SourceLocation Loc, StringRef Name) {
163
20
  return (bool)S.PP.getMacroDefinitionAtLoc(&S.getASTContext().Idents.get(Name),
164
20
                                            Loc);
165
20
}
166
167
static std::string getScalarZeroExpressionForType(
168
585
    const Type &T, SourceLocation Loc, const Sema &S) {
169
585
  assert(T.isScalarType() && "use scalar types only");
170
585
  // Suggest "0" for non-enumeration scalar types, unless we can find a
171
585
  // better initializer.
172
585
  if (T.isEnumeralType())
173
3
    return std::string();
174
582
  if ((T.isObjCObjectPointerType() || T.isBlockPointerType()) &&
175
582
      
isMacroDefined(S, Loc, "nil")0
)
176
0
    return "nil";
177
582
  if (T.isRealFloatingType())
178
16
    return "0.0";
179
566
  if (T.isBooleanType() &&
180
566
      
(59
S.LangOpts.CPlusPlus59
||
isMacroDefined(S, Loc, "false")6
))
181
55
    return "false";
182
511
  if (T.isPointerType() || 
T.isMemberPointerType()479
) {
183
32
    if (S.LangOpts.CPlusPlus11)
184
18
      return "nullptr";
185
14
    if (isMacroDefined(S, Loc, "NULL"))
186
4
      return "NULL";
187
489
  }
188
489
  if (T.isCharType())
189
19
    return "'\\0'";
190
470
  if (T.isWideCharType())
191
2
    return "L'\\0'";
192
468
  if (T.isChar16Type())
193
2
    return "u'\\0'";
194
466
  if (T.isChar32Type())
195
2
    return "U'\\0'";
196
464
  return "0";
197
464
}
198
199
std::string
200
558
Sema::getFixItZeroInitializerForType(QualType T, SourceLocation Loc) const {
201
558
  if (T->isScalarType()) {
202
509
    std::string s = getScalarZeroExpressionForType(*T, Loc, *this);
203
509
    if (!s.empty())
204
506
      s = " = " + s;
205
509
    return s;
206
509
  }
207
49
208
49
  const CXXRecordDecl *RD = T->getAsCXXRecordDecl();
209
49
  if (!RD || 
!RD->hasDefinition()43
)
210
10
    return std::string();
211
39
  if (LangOpts.CPlusPlus11 && 
!RD->hasUserProvidedDefaultConstructor()28
)
212
27
    return "{}";
213
12
  if (RD->isAggregate())
214
9
    return " = {}";
215
3
  return std::string();
216
3
}
217
218
std::string
219
76
Sema::getFixItZeroLiteralForType(QualType T, SourceLocation Loc) const {
220
76
  return getScalarZeroExpressionForType(*T, Loc, *this);
221
76
}