Coverage Report

Created: 2022-01-18 06:27

/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
847
                                                  ExprValueKind FromVK) {
27
847
  if (!To.isAtLeastAsQualifiedAs(From))
28
59
    return false;
29
30
788
  From = From.getNonReferenceType();
31
788
  To = To.getNonReferenceType();
32
33
  // If both are pointer types, work with the pointee types.
34
788
  if (isa<PointerType>(From) && 
isa<PointerType>(To)494
) {
35
484
    From = S.Context.getCanonicalType(
36
484
        (cast<PointerType>(From))->getPointeeType());
37
484
    To = S.Context.getCanonicalType(
38
484
        (cast<PointerType>(To))->getPointeeType());
39
484
  }
40
41
788
  const CanQualType FromUnq = From.getUnqualifiedType();
42
788
  const CanQualType ToUnq = To.getUnqualifiedType();
43
44
788
  if ((FromUnq == ToUnq || 
(S.IsDerivedFrom(Loc, FromUnq, ToUnq))738
) &&
45
788
      
To.isAtLeastAsQualifiedAs(From)60
)
46
60
    return true;
47
728
  return false;
48
788
}
49
50
bool ConversionFixItGenerator::tryToFixConversion(const Expr *FullExpr,
51
                                                  const QualType FromTy,
52
                                                  const QualType ToTy,
53
16.0k
                                                  Sema &S) {
54
16.0k
  if (!FullExpr)
55
614
    return false;
56
57
15.4k
  const CanQualType FromQTy = S.Context.getCanonicalType(FromTy);
58
15.4k
  const CanQualType ToQTy = S.Context.getCanonicalType(ToTy);
59
15.4k
  const SourceLocation Begin = FullExpr->getSourceRange().getBegin();
60
15.4k
  const SourceLocation End = S.getLocForEndOfToken(FullExpr->getSourceRange()
61
15.4k
                                                   .getEnd());
62
63
  // Strip the implicit casts - those are implied by the compiler, not the
64
  // original source code.
65
15.4k
  const Expr* Expr = FullExpr->IgnoreImpCasts();
66
67
15.4k
  bool NeedParen = true;
68
15.4k
  if (isa<ArraySubscriptExpr>(Expr) ||
69
15.4k
      
isa<CallExpr>(Expr)15.4k
||
70
15.4k
      
isa<DeclRefExpr>(Expr)10.8k
||
71
15.4k
      
isa<CastExpr>(Expr)6.73k
||
72
15.4k
      
isa<CXXNewExpr>(Expr)4.40k
||
73
15.4k
      
isa<CXXConstructExpr>(Expr)4.40k
||
74
15.4k
      
isa<CXXDeleteExpr>(Expr)3.88k
||
75
15.4k
      
isa<CXXNoexceptExpr>(Expr)3.88k
||
76
15.4k
      
isa<CXXPseudoDestructorExpr>(Expr)3.88k
||
77
15.4k
      
isa<CXXScalarValueInitExpr>(Expr)3.88k
||
78
15.4k
      
isa<CXXThisExpr>(Expr)3.87k
||
79
15.4k
      
isa<CXXTypeidExpr>(Expr)3.87k
||
80
15.4k
      
isa<CXXUnresolvedConstructExpr>(Expr)3.87k
||
81
15.4k
      
isa<ObjCMessageExpr>(Expr)3.87k
||
82
15.4k
      
isa<ObjCPropertyRefExpr>(Expr)3.68k
||
83
15.4k
      
isa<ObjCProtocolExpr>(Expr)3.68k
||
84
15.4k
      
isa<MemberExpr>(Expr)3.68k
||
85
15.4k
      
isa<ParenExpr>(FullExpr)3.65k
||
86
15.4k
      
isa<ParenListExpr>(Expr)3.54k
||
87
15.4k
      
isa<SizeOfPackExpr>(Expr)3.54k
||
88
15.4k
      
isa<UnaryOperator>(Expr)3.54k
)
89
12.0k
    NeedParen = false;
90
91
  // Check if the argument needs to be dereferenced:
92
  //   (type * -> type) or (type * -> type &).
93
15.4k
  if (const PointerType *FromPtrTy = dyn_cast<PointerType>(FromQTy)) {
94
572
    OverloadFixItKind FixKind = OFIK_Dereference;
95
96
572
    bool CanConvert = CompareTypes(
97
572
      S.Context.getCanonicalType(FromPtrTy->getPointeeType()), ToQTy,
98
572
                                 S, Begin, VK_LValue);
99
572
    if (CanConvert) {
100
      // Do not suggest dereferencing a Null pointer.
101
67
      if (Expr->IgnoreParenCasts()->
102
67
          isNullPointerConstant(S.Context, Expr::NPC_ValueDependentIsNotNull))
103
13
        return false;
104
105
54
      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
46
      } else if (NeedParen) {
112
5
        Hints.push_back(FixItHint::CreateInsertion(Begin, "*("));
113
5
        Hints.push_back(FixItHint::CreateInsertion(End, ")"));
114
41
      } else {
115
41
        Hints.push_back(FixItHint::CreateInsertion(Begin, "*"));
116
41
      }
117
118
54
      NumConversionsFixed++;
119
54
      if (NumConversionsFixed == 1)
120
53
        Kind = FixKind;
121
54
      return true;
122
67
    }
123
572
  }
124
125
  // Check if the pointer to the argument needs to be passed:
126
  //   (type -> type *) or (type & -> type *).
127
15.3k
  if (isa<PointerType>(ToQTy)) {
128
1.14k
    bool CanConvert = false;
129
1.14k
    OverloadFixItKind FixKind = OFIK_TakeAddress;
130
131
    // Only suggest taking address of L-values.
132
1.14k
    if (!Expr->isLValue() || 
Expr->getObjectKind() != OK_Ordinary677
)
133
469
      return false;
134
135
676
    CanConvert = CompareTypes(S.Context.getPointerType(FromQTy), ToQTy, S,
136
676
                              Begin, VK_PRValue);
137
676
    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
676
  }
158
159
14.8k
  return false;
160
15.3k
}
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.23k
    const Type &T, SourceLocation Loc, const Sema &S) {
169
1.23k
  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.23k
  if (T.isEnumeralType())
173
3
    return std::string();
174
1.23k
  if ((T.isObjCObjectPointerType() || 
T.isBlockPointerType()1.23k
) &&
175
1.23k
      
isMacroDefined(S, Loc, "nil")1
)
176
0
    return "nil";
177
1.23k
  if (T.isRealFloatingType())
178
16
    return "0.0";
179
1.21k
  if (T.isBooleanType() &&
180
1.21k
      
(60
S.LangOpts.CPlusPlus60
||
isMacroDefined(S, Loc, "false")6
))
181
56
    return "false";
182
1.15k
  if (T.isPointerType() || 
T.isMemberPointerType()1.12k
) {
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.13k
  if (T.isCharType())
189
19
    return "'\\0'";
190
1.11k
  if (T.isWideCharType())
191
2
    return "L'\\0'";
192
1.11k
  if (T.isChar16Type())
193
2
    return "u'\\0'";
194
1.11k
  if (T.isChar32Type())
195
2
    return "U'\\0'";
196
1.11k
  return "0";
197
1.11k
}
198
199
std::string
200
1.22k
Sema::getFixItZeroInitializerForType(QualType T, SourceLocation Loc) const {
201
1.22k
  if (T->isScalarType()) {
202
1.15k
    std::string s = getScalarZeroExpressionForType(*T, Loc, *this);
203
1.15k
    if (!s.empty())
204
1.15k
      s = " = " + s;
205
1.15k
    return s;
206
1.15k
  }
207
208
63
  const CXXRecordDecl *RD = T->getAsCXXRecordDecl();
209
63
  if (!RD || 
!RD->hasDefinition()44
)
210
23
    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
}