Coverage Report

Created: 2024-01-17 10:31

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