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