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