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