1 //===--- SemaFixItUtils.cpp - Sema FixIts ---------------------------------===//
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
7 //===----------------------------------------------------------------------===//
9 // This file defines helper classes for generation of Sema FixItHints.
11 //===----------------------------------------------------------------------===//
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"
20 using namespace clang
;
22 bool ConversionFixItGenerator::compareTypesSimple(CanQualType From
,
26 ExprValueKind FromVK
) {
27 if (!To
.isAtLeastAsQualifiedAs(From
))
30 From
= From
.getNonReferenceType();
31 To
= To
.getNonReferenceType();
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());
41 const CanQualType FromUnq
= From
.getUnqualifiedType();
42 const CanQualType ToUnq
= To
.getUnqualifiedType();
44 if ((FromUnq
== ToUnq
|| (S
.IsDerivedFrom(Loc
, FromUnq
, ToUnq
)) ) &&
45 To
.isAtLeastAsQualifiedAs(From
))
50 bool ConversionFixItGenerator::tryToFixConversion(const Expr
*FullExpr
,
51 const QualType FromTy
,
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()
63 // Strip the implicit casts - those are implied by the compiler, not the
64 // original source code.
65 const Expr
* Expr
= FullExpr
->IgnoreImpCasts();
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
))
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
;
96 bool CanConvert
= CompareTypes(
97 S
.Context
.getCanonicalType(FromPtrTy
->getPointeeType()), ToQTy
,
100 // Do not suggest dereferencing a Null pointer.
101 if (Expr
->IgnoreParenCasts()->
102 isNullPointerConstant(S
.Context
, Expr::NPC_ValueDependentIsNotNull
))
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
)));
111 } else if (NeedParen
) {
112 Hints
.push_back(FixItHint::CreateInsertion(Begin
, "*("));
113 Hints
.push_back(FixItHint::CreateInsertion(End
, ")"));
115 Hints
.push_back(FixItHint::CreateInsertion(Begin
, "*"));
118 NumConversionsFixed
++;
119 if (NumConversionsFixed
== 1)
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
;
131 // Only suggest taking address of L-values.
132 if (!Expr
->isLValue() || Expr
->getObjectKind() != OK_Ordinary
)
135 // Do no take address of const pointer to get void*
136 if (isa
<PointerType
>(FromQTy
) && ToPtrTy
->isVoidPointerType())
139 CanConvert
= CompareTypes(S
.Context
.getPointerType(FromQTy
), ToQTy
, S
,
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
)));
149 } else if (NeedParen
) {
150 Hints
.push_back(FixItHint::CreateInsertion(Begin
, "&("));
151 Hints
.push_back(FixItHint::CreateInsertion(End
, ")"));
153 Hints
.push_back(FixItHint::CreateInsertion(Begin
, "&"));
156 NumConversionsFixed
++;
157 if (NumConversionsFixed
== 1)
166 static bool isMacroDefined(const Sema
&S
, SourceLocation Loc
, StringRef Name
) {
167 return (bool)S
.PP
.getMacroDefinitionAtLoc(&S
.getASTContext().Idents
.get(Name
),
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"))
181 if (T
.isRealFloatingType())
183 if (T
.isBooleanType() &&
184 (S
.LangOpts
.CPlusPlus
|| isMacroDefined(S
, Loc
, "false")))
186 if (T
.isPointerType() || T
.isMemberPointerType()) {
187 if (S
.LangOpts
.CPlusPlus11
)
189 if (isMacroDefined(S
, Loc
, "NULL"))
194 if (T
.isWideCharType())
196 if (T
.isChar16Type())
198 if (T
.isChar32Type())
204 Sema::getFixItZeroInitializerForType(QualType T
, SourceLocation Loc
) const {
205 if (T
->isScalarType()) {
206 std::string s
= getScalarZeroExpressionForType(*T
, Loc
, *this);
212 const CXXRecordDecl
*RD
= T
->getAsCXXRecordDecl();
213 if (!RD
|| !RD
->hasDefinition())
214 return std::string();
215 if (LangOpts
.CPlusPlus11
&& !RD
->hasUserProvidedDefaultConstructor())
217 if (RD
->isAggregate())
219 return std::string();
223 Sema::getFixItZeroLiteralForType(QualType T
, SourceLocation Loc
) const {
224 return getScalarZeroExpressionForType(*T
, Loc
, *this);