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