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