Coverage Report

Created: 2020-02-18 08:44

/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.68k
                                                  ExprValueKind FromVK) {
27
1.68k
  if (!To.isAtLeastAsQualifiedAs(From))
28
529
    return false;
29
1.15k
30
1.15k
  From = From.getNonReferenceType();
31
1.15k
  To = To.getNonReferenceType();
32
1.15k
33
1.15k
  // If both are pointer types, work with the pointee types.
34
1.15k
  if (isa<PointerType>(From) && 
isa<PointerType>(To)907
) {
35
901
    From = S.Context.getCanonicalType(
36
901
        (cast<PointerType>(From))->getPointeeType());
37
901
    To = S.Context.getCanonicalType(
38
901
        (cast<PointerType>(To))->getPointeeType());
39
901
  }
40
1.15k
41
1.15k
  const CanQualType FromUnq = From.getUnqualifiedType();
42
1.15k
  const CanQualType ToUnq = To.getUnqualifiedType();
43
1.15k
44
1.15k
  if ((FromUnq == ToUnq || 
(S.IsDerivedFrom(Loc, FromUnq, ToUnq))1.11k
) &&
45
1.15k
      
To.isAtLeastAsQualifiedAs(From)51
)
46
51
    return true;
47
1.10k
  return false;
48
1.10k
}
49
50
bool ConversionFixItGenerator::tryToFixConversion(const Expr *FullExpr,
51
                                                  const QualType FromTy,
52
                                                  const QualType ToTy,
53
9.57k
                                                  Sema &S) {
54
9.57k
  if (!FullExpr)
55
707
    return false;
56
8.86k
57
8.86k
  const CanQualType FromQTy = S.Context.getCanonicalType(FromTy);
58
8.86k
  const CanQualType ToQTy = S.Context.getCanonicalType(ToTy);
59
8.86k
  const SourceLocation Begin = FullExpr->getSourceRange().getBegin();
60
8.86k
  const SourceLocation End = S.getLocForEndOfToken(FullExpr->getSourceRange()
61
8.86k
                                                   .getEnd());
62
8.86k
63
8.86k
  // Strip the implicit casts - those are implied by the compiler, not the
64
8.86k
  // original source code.
65
8.86k
  const Expr* Expr = FullExpr->IgnoreImpCasts();
66
8.86k
67
8.86k
  bool NeedParen = true;
68
8.86k
  if (isa<ArraySubscriptExpr>(Expr) ||
69
8.86k
      
isa<CallExpr>(Expr)8.86k
||
70
8.86k
      
isa<DeclRefExpr>(Expr)8.34k
||
71
8.86k
      
isa<CastExpr>(Expr)4.05k
||
72
8.86k
      
isa<CXXNewExpr>(Expr)3.95k
||
73
8.86k
      
isa<CXXConstructExpr>(Expr)3.95k
||
74
8.86k
      
isa<CXXDeleteExpr>(Expr)3.46k
||
75
8.86k
      
isa<CXXNoexceptExpr>(Expr)3.46k
||
76
8.86k
      
isa<CXXPseudoDestructorExpr>(Expr)3.46k
||
77
8.86k
      
isa<CXXScalarValueInitExpr>(Expr)3.46k
||
78
8.86k
      
isa<CXXThisExpr>(Expr)3.46k
||
79
8.86k
      
isa<CXXTypeidExpr>(Expr)3.46k
||
80
8.86k
      
isa<CXXUnresolvedConstructExpr>(Expr)3.45k
||
81
8.86k
      
isa<ObjCMessageExpr>(Expr)3.45k
||
82
8.86k
      
isa<ObjCPropertyRefExpr>(Expr)3.28k
||
83
8.86k
      
isa<ObjCProtocolExpr>(Expr)3.28k
||
84
8.86k
      
isa<MemberExpr>(Expr)3.28k
||
85
8.86k
      
isa<ParenExpr>(FullExpr)3.24k
||
86
8.86k
      
isa<ParenListExpr>(Expr)2.19k
||
87
8.86k
      
isa<SizeOfPackExpr>(Expr)2.19k
||
88
8.86k
      
isa<UnaryOperator>(Expr)2.19k
)
89
6.84k
    NeedParen = false;
90
8.86k
91
8.86k
  // Check if the argument needs to be dereferenced:
92
8.86k
  //   (type * -> type) or (type * -> type &).
93
8.86k
  if (const PointerType *FromPtrTy = dyn_cast<PointerType>(FromQTy)) {
94
966
    OverloadFixItKind FixKind = OFIK_Dereference;
95
966
96
966
    bool CanConvert = CompareTypes(
97
966
      S.Context.getCanonicalType(FromPtrTy->getPointeeType()), ToQTy,
98
966
                                 S, Begin, VK_LValue);
99
966
    if (CanConvert) {
100
57
      // Do not suggest dereferencing a Null pointer.
101
57
      if (Expr->IgnoreParenCasts()->
102
57
          isNullPointerConstant(S.Context, Expr::NPC_ValueDependentIsNotNull))
103
12
        return false;
104
45
105
45
      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
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
45
118
45
      NumConversionsFixed++;
119
45
      if (NumConversionsFixed == 1)
120
44
        Kind = FixKind;
121
45
      return true;
122
45
    }
123
966
  }
124
8.80k
125
8.80k
  // Check if the pointer to the argument needs to be passed:
126
8.80k
  //   (type -> type *) or (type & -> type *).
127
8.80k
  if (isa<PointerType>(ToQTy)) {
128
1.47k
    bool CanConvert = false;
129
1.47k
    OverloadFixItKind FixKind = OFIK_TakeAddress;
130
1.47k
131
1.47k
    // Only suggest taking address of L-values.
132
1.47k
    if (!Expr->isLValue() || 
Expr->getObjectKind() != OK_Ordinary1.02k
)
133
442
      return false;
134
1.02k
135
1.02k
    CanConvert = CompareTypes(S.Context.getPointerType(FromQTy), ToQTy,
136
1.02k
                              S, Begin, VK_RValue);
137
1.02k
    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
8.31k
  }
158
8.31k
159
8.31k
  return false;
160
8.31k
}
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
885
    const Type &T, SourceLocation Loc, const Sema &S) {
169
885
  assert(T.isScalarType() && "use scalar types only");
170
885
  // Suggest "0" for non-enumeration scalar types, unless we can find a
171
885
  // better initializer.
172
885
  if (T.isEnumeralType())
173
1
    return std::string();
174
884
  if ((T.isObjCObjectPointerType() || T.isBlockPointerType()) &&
175
884
      
isMacroDefined(S, Loc, "nil")0
)
176
0
    return "nil";
177
884
  if (T.isRealFloatingType())
178
16
    return "0.0";
179
868
  if (T.isBooleanType() &&
180
868
      
(47
S.LangOpts.CPlusPlus47
||
isMacroDefined(S, Loc, "false")6
))
181
43
    return "false";
182
825
  if (T.isPointerType() || 
T.isMemberPointerType()793
) {
183
32
    if (S.LangOpts.CPlusPlus11)
184
18
      return "nullptr";
185
14
    if (isMacroDefined(S, Loc, "NULL"))
186
4
      return "NULL";
187
803
  }
188
803
  if (T.isCharType())
189
19
    return "'\\0'";
190
784
  if (T.isWideCharType())
191
2
    return "L'\\0'";
192
782
  if (T.isChar16Type())
193
2
    return "u'\\0'";
194
780
  if (T.isChar32Type())
195
2
    return "U'\\0'";
196
778
  return "0";
197
778
}
198
199
std::string
200
858
Sema::getFixItZeroInitializerForType(QualType T, SourceLocation Loc) const {
201
858
  if (T->isScalarType()) {
202
808
    std::string s = getScalarZeroExpressionForType(*T, Loc, *this);
203
808
    if (!s.empty())
204
807
      s = " = " + s;
205
808
    return s;
206
808
  }
207
50
208
50
  const CXXRecordDecl *RD = T->getAsCXXRecordDecl();
209
50
  if (!RD || 
!RD->hasDefinition()44
)
210
10
    return std::string();
211
40
  if (LangOpts.CPlusPlus11 && 
!RD->hasUserProvidedDefaultConstructor()29
)
212
28
    return "{}";
213
12
  if (RD->isAggregate())
214
9
    return " = {}";
215
3
  return std::string();
216
3
}
217
218
std::string
219
77
Sema::getFixItZeroLiteralForType(QualType T, SourceLocation Loc) const {
220
77
  return getScalarZeroExpressionForType(*T, Loc, *this);
221
77
}