• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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(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.PP.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,StringRef Name)163 static bool isMacroDefined(const Sema &S, StringRef Name) {
164   return S.PP.getMacroInfo(&S.getASTContext().Idents.get(Name));
165 }
166 
getScalarZeroExpressionForType(const Type & T,const Sema & S)167 static std::string getScalarZeroExpressionForType(const Type& T, const Sema& S) {
168   assert(T.isScalarType() && "use scalar types only");
169   // Suggest "0" for non-enumeration scalar types, unless we can find a
170   // better initializer.
171   if (T.isEnumeralType())
172     return std::string();
173   if ((T.isObjCObjectPointerType() || T.isBlockPointerType()) &&
174       isMacroDefined(S, "nil"))
175     return "nil";
176   if (T.isRealFloatingType())
177     return "0.0";
178   if (T.isBooleanType() && S.LangOpts.CPlusPlus)
179     return "false";
180   if (T.isPointerType() || T.isMemberPointerType()) {
181     if (S.LangOpts.CPlusPlus0x)
182       return "nullptr";
183     if (isMacroDefined(S, "NULL"))
184       return "NULL";
185   }
186   if (T.isCharType())
187     return "'\\0'";
188   if (T.isWideCharType())
189     return "L'\\0'";
190   if (T.isChar16Type())
191     return "u'\\0'";
192   if (T.isChar32Type())
193     return "U'\\0'";
194   return "0";
195 }
196 
getFixItZeroInitializerForType(QualType T) const197 std::string Sema::getFixItZeroInitializerForType(QualType T) const {
198   if (T->isScalarType()) {
199     std::string s = getScalarZeroExpressionForType(*T, *this);
200     if (!s.empty())
201       s = " = " + s;
202     return s;
203   }
204 
205   const CXXRecordDecl *RD = T->getAsCXXRecordDecl();
206   if (!RD || !RD->hasDefinition())
207     return std::string();
208   if (LangOpts.CPlusPlus0x && !RD->hasUserProvidedDefaultConstructor())
209     return "{}";
210   if (RD->isAggregate())
211     return " = {}";
212   return std::string();
213 }
214 
getFixItZeroLiteralForType(QualType T) const215 std::string Sema::getFixItZeroLiteralForType(QualType T) const {
216   return getScalarZeroExpressionForType(*T, *this);
217 }
218