xref: /aosp_15_r20/external/clang/lib/Sema/SemaFixItUtils.cpp (revision 67e74705e28f6214e480b399dd47ea732279e315)
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