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