Coverage Report

Created: 2021-08-24 07:12

/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.72k
                                                  ExprValueKind FromVK) {
27
1.72k
  if (!To.isAtLeastAsQualifiedAs(From))
28
495
    return false;
29
30
1.22k
  From = From.getNonReferenceType();
31
1.22k
  To = To.getNonReferenceType();
32
33
  // If both are pointer types, work with the pointee types.
34
1.22k
  if (isa<PointerType>(From) && 
isa<PointerType>(To)931
) {
35
921
    From = S.Context.getCanonicalType(
36
921
        (cast<PointerType>(From))->getPointeeType());
37
921
    To = S.Context.getCanonicalType(
38
921
        (cast<PointerType>(To))->getPointeeType());
39
921
  }
40
41
1.22k
  const CanQualType FromUnq = From.getUnqualifiedType();
42
1.22k
  const CanQualType ToUnq = To.getUnqualifiedType();
43
44
1.22k
  if ((FromUnq == ToUnq || 
(S.IsDerivedFrom(Loc, FromUnq, ToUnq))1.17k
) &&
45
1.22k
      
To.isAtLeastAsQualifiedAs(From)59
)
46
59
    return true;
47
1.16k
  return false;
48
1.22k
}
49
50
bool ConversionFixItGenerator::tryToFixConversion(const Expr *FullExpr,
51
                                                  const QualType FromTy,
52
                                                  const QualType ToTy,
53
18.1k
                                                  Sema &S) {
54
18.1k
  if (!FullExpr)
55
614
    return false;
56
57
17.5k
  const CanQualType FromQTy = S.Context.getCanonicalType(FromTy);
58
17.5k
  const CanQualType ToQTy = S.Context.getCanonicalType(ToTy);
59
17.5k
  const SourceLocation Begin = FullExpr->getSourceRange().getBegin();
60
17.5k
  const SourceLocation End = S.getLocForEndOfToken(FullExpr->getSourceRange()
61
17.5k
                                                   .getEnd());
62
63
  // Strip the implicit casts - those are implied by the compiler, not the
64
  // original source code.
65
17.5k
  const Expr* Expr = FullExpr->IgnoreImpCasts();
66
67
17.5k
  bool NeedParen = true;
68
17.5k
  if (isa<ArraySubscriptExpr>(Expr) ||
69
17.5k
      
isa<CallExpr>(Expr)17.5k
||
70
17.5k
      
isa<DeclRefExpr>(Expr)12.7k
||
71
17.5k
      
isa<CastExpr>(Expr)7.76k
||
72
17.5k
      
isa<CXXNewExpr>(Expr)5.43k
||
73
17.5k
      
isa<CXXConstructExpr>(Expr)5.42k
||
74
17.5k
      
isa<CXXDeleteExpr>(Expr)4.91k
||
75
17.5k
      
isa<CXXNoexceptExpr>(Expr)4.91k
||
76
17.5k
      
isa<CXXPseudoDestructorExpr>(Expr)4.91k
||
77
17.5k
      
isa<CXXScalarValueInitExpr>(Expr)4.91k
||
78
17.5k
      
isa<CXXThisExpr>(Expr)4.90k
||
79
17.5k
      
isa<CXXTypeidExpr>(Expr)4.90k
||
80
17.5k
      
isa<CXXUnresolvedConstructExpr>(Expr)4.89k
||
81
17.5k
      
isa<ObjCMessageExpr>(Expr)4.89k
||
82
17.5k
      
isa<ObjCPropertyRefExpr>(Expr)4.71k
||
83
17.5k
      
isa<ObjCProtocolExpr>(Expr)4.71k
||
84
17.5k
      
isa<MemberExpr>(Expr)4.71k
||
85
17.5k
      
isa<ParenExpr>(FullExpr)4.67k
||
86
17.5k
      
isa<ParenListExpr>(Expr)3.52k
||
87
17.5k
      
isa<SizeOfPackExpr>(Expr)3.52k
||
88
17.5k
      
isa<UnaryOperator>(Expr)3.52k
)
89
14.1k
    NeedParen = false;
90
91
  // Check if the argument needs to be dereferenced:
92
  //   (type * -> type) or (type * -> type &).
93
17.5k
  if (const PointerType *FromPtrTy = dyn_cast<PointerType>(FromQTy)) {
94
995
    OverloadFixItKind FixKind = OFIK_Dereference;
95
96
995
    bool CanConvert = CompareTypes(
97
995
      S.Context.getCanonicalType(FromPtrTy->getPointeeType()), ToQTy,
98
995
                                 S, Begin, VK_LValue);
99
995
    if (CanConvert) {
100
      // Do not suggest dereferencing a Null pointer.
101
66
      if (Expr->IgnoreParenCasts()->
102
66
          isNullPointerConstant(S.Context, Expr::NPC_ValueDependentIsNotNull))
103
13
        return false;
104
105
53
      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
45
      } else if (NeedParen) {
112
5
        Hints.push_back(FixItHint::CreateInsertion(Begin, "*("));
113
5
        Hints.push_back(FixItHint::CreateInsertion(End, ")"));
114
40
      } else {
115
40
        Hints.push_back(FixItHint::CreateInsertion(Begin, "*"));
116
40
      }
117
118
53
      NumConversionsFixed++;
119
53
      if (NumConversionsFixed == 1)
120
52
        Kind = FixKind;
121
53
      return true;
122
66
    }
123
995
  }
124
125
  // Check if the pointer to the argument needs to be passed:
126
  //   (type -> type *) or (type & -> type *).
127
17.4k
  if (isa<PointerType>(ToQTy)) {
128
1.57k
    bool CanConvert = false;
129
1.57k
    OverloadFixItKind FixKind = OFIK_TakeAddress;
130
131
    // Only suggest taking address of L-values.
132
1.57k
    if (!Expr->isLValue() || 
Expr->getObjectKind() != OK_Ordinary1.09k
)
133
472
      return false;
134
135
1.09k
    CanConvert = CompareTypes(S.Context.getPointerType(FromQTy), ToQTy, S,
136
1.09k
                              Begin, VK_PRValue);
137
1.09k
    if (CanConvert) {
138
139
50
      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
47
      } else if (NeedParen) {
146
0
        Hints.push_back(FixItHint::CreateInsertion(Begin, "&("));
147
0
        Hints.push_back(FixItHint::CreateInsertion(End, ")"));
148
47
      } else {
149
47
        Hints.push_back(FixItHint::CreateInsertion(Begin, "&"));
150
47
      }
151
152
50
      NumConversionsFixed++;
153
50
      if (NumConversionsFixed == 1)
154
49
        Kind = FixKind;
155
50
      return true;
156
50
    }
157
1.09k
  }
158
159
16.9k
  return false;
160
17.4k
}
161
162
25
static bool isMacroDefined(const Sema &S, SourceLocation Loc, StringRef Name) {
163
25
  return (bool)S.PP.getMacroDefinitionAtLoc(&S.getASTContext().Idents.get(Name),
164
25
                                            Loc);
165
25
}
166
167
static std::string getScalarZeroExpressionForType(
168
1.21k
    const Type &T, SourceLocation Loc, const Sema &S) {
169
1.21k
  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.21k
  if (T.isEnumeralType())
173
3
    return std::string();
174
1.21k
  if ((T.isObjCObjectPointerType() || 
T.isBlockPointerType()1.21k
) &&
175
1.21k
      
isMacroDefined(S, Loc, "nil")1
)
176
0
    return "nil";
177
1.21k
  if (T.isRealFloatingType())
178
16
    return "0.0";
179
1.19k
  if (T.isBooleanType() &&
180
1.19k
      
(60
S.LangOpts.CPlusPlus60
||
isMacroDefined(S, Loc, "false")6
))
181
56
    return "false";
182
1.14k
  if (T.isPointerType() || 
T.isMemberPointerType()1.10k
) {
183
36
    if (S.LangOpts.CPlusPlus11)
184
18
      return "nullptr";
185
18
    if (isMacroDefined(S, Loc, "NULL"))
186
6
      return "NULL";
187
18
  }
188
1.11k
  if (T.isCharType())
189
19
    return "'\\0'";
190
1.10k
  if (T.isWideCharType())
191
2
    return "L'\\0'";
192
1.09k
  if (T.isChar16Type())
193
2
    return "u'\\0'";
194
1.09k
  if (T.isChar32Type())
195
2
    return "U'\\0'";
196
1.09k
  return "0";
197
1.09k
}
198
199
std::string
200
1.20k
Sema::getFixItZeroInitializerForType(QualType T, SourceLocation Loc) const {
201
1.20k
  if (T->isScalarType()) {
202
1.14k
    std::string s = getScalarZeroExpressionForType(*T, Loc, *this);
203
1.14k
    if (!s.empty())
204
1.13k
      s = " = " + s;
205
1.14k
    return s;
206
1.14k
  }
207
208
62
  const CXXRecordDecl *RD = T->getAsCXXRecordDecl();
209
62
  if (!RD || 
!RD->hasDefinition()44
)
210
22
    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
13
}
217
218
std::string
219
77
Sema::getFixItZeroLiteralForType(QualType T, SourceLocation Loc) const {
220
77
  return getScalarZeroExpressionForType(*T, Loc, *this);
221
77
}