xref: /minix3/external/bsd/llvm/dist/clang/lib/Sema/SemaFixItUtils.cpp (revision f4a2713ac843a11c696ec80c0a5e3e5d80b4d338)
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