blob: 3cc26c09385952d69c4413df2b6cd012da335d99 [file] [log] [blame]
Eugene Zelenkobc9d4f42018-04-05 21:09:03 +00001//===- SemaFixItUtils.cpp - Sema FixIts -----------------------------------===//
Anna Zaks1b068122011-07-28 19:46:48 +00002//
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
Eugene Zelenkobc9d4f42018-04-05 21:09:03 +000014#include "clang/Sema/SemaFixItUtils.h"
Benjamin Kramer1ea8e092012-07-04 17:04:04 +000015#include "clang/AST/ASTContext.h"
Eugene Zelenkobc9d4f42018-04-05 21:09:03 +000016#include "clang/AST/DeclCXX.h"
17#include "clang/AST/DeclarationName.h"
18#include "clang/AST/Expr.h"
Anna Zaks1b068122011-07-28 19:46:48 +000019#include "clang/AST/ExprCXX.h"
20#include "clang/AST/ExprObjC.h"
Eugene Zelenkobc9d4f42018-04-05 21:09:03 +000021#include "clang/AST/Type.h"
22#include "clang/Basic/Diagnostic.h"
23#include "clang/Basic/LLVM.h"
24#include "clang/Basic/LangOptions.h"
25#include "clang/Basic/SourceLocation.h"
Anna Zaks1b068122011-07-28 19:46:48 +000026#include "clang/Lex/Preprocessor.h"
27#include "clang/Sema/Sema.h"
Eugene Zelenkobc9d4f42018-04-05 21:09:03 +000028#include "llvm/ADT/StringRef.h"
29#include "llvm/Support/Casting.h"
30#include <cassert>
31#include <string>
Anna Zaks1b068122011-07-28 19:46:48 +000032
33using namespace clang;
34
35bool ConversionFixItGenerator::compareTypesSimple(CanQualType From,
36 CanQualType To,
37 Sema &S,
38 SourceLocation Loc,
39 ExprValueKind FromVK) {
40 if (!To.isAtLeastAsQualifiedAs(From))
41 return false;
42
43 From = From.getNonReferenceType();
44 To = To.getNonReferenceType();
45
46 // If both are pointer types, work with the pointee types.
47 if (isa<PointerType>(From) && isa<PointerType>(To)) {
48 From = S.Context.getCanonicalType(
49 (cast<PointerType>(From))->getPointeeType());
50 To = S.Context.getCanonicalType(
51 (cast<PointerType>(To))->getPointeeType());
52 }
53
54 const CanQualType FromUnq = From.getUnqualifiedType();
55 const CanQualType ToUnq = To.getUnqualifiedType();
56
Richard Smith0f59cb32015-12-18 21:45:41 +000057 if ((FromUnq == ToUnq || (S.IsDerivedFrom(Loc, FromUnq, ToUnq)) ) &&
Anna Zaks1b068122011-07-28 19:46:48 +000058 To.isAtLeastAsQualifiedAs(From))
59 return true;
60 return false;
61}
62
63bool ConversionFixItGenerator::tryToFixConversion(const Expr *FullExpr,
64 const QualType FromTy,
65 const QualType ToTy,
66 Sema &S) {
67 if (!FullExpr)
68 return false;
69
70 const CanQualType FromQTy = S.Context.getCanonicalType(FromTy);
71 const CanQualType ToQTy = S.Context.getCanonicalType(ToTy);
72 const SourceLocation Begin = FullExpr->getSourceRange().getBegin();
Craig Topper07fa1762015-11-15 02:31:46 +000073 const SourceLocation End = S.getLocForEndOfToken(FullExpr->getSourceRange()
74 .getEnd());
Anna Zaks1b068122011-07-28 19:46:48 +000075
76 // Strip the implicit casts - those are implied by the compiler, not the
77 // original source code.
78 const Expr* Expr = FullExpr->IgnoreImpCasts();
79
80 bool NeedParen = true;
81 if (isa<ArraySubscriptExpr>(Expr) ||
82 isa<CallExpr>(Expr) ||
83 isa<DeclRefExpr>(Expr) ||
84 isa<CastExpr>(Expr) ||
85 isa<CXXNewExpr>(Expr) ||
86 isa<CXXConstructExpr>(Expr) ||
87 isa<CXXDeleteExpr>(Expr) ||
88 isa<CXXNoexceptExpr>(Expr) ||
89 isa<CXXPseudoDestructorExpr>(Expr) ||
90 isa<CXXScalarValueInitExpr>(Expr) ||
91 isa<CXXThisExpr>(Expr) ||
92 isa<CXXTypeidExpr>(Expr) ||
93 isa<CXXUnresolvedConstructExpr>(Expr) ||
94 isa<ObjCMessageExpr>(Expr) ||
95 isa<ObjCPropertyRefExpr>(Expr) ||
96 isa<ObjCProtocolExpr>(Expr) ||
97 isa<MemberExpr>(Expr) ||
98 isa<ParenExpr>(FullExpr) ||
99 isa<ParenListExpr>(Expr) ||
100 isa<SizeOfPackExpr>(Expr) ||
101 isa<UnaryOperator>(Expr))
102 NeedParen = false;
103
104 // Check if the argument needs to be dereferenced:
105 // (type * -> type) or (type * -> type &).
Eugene Zelenkobc9d4f42018-04-05 21:09:03 +0000106 if (const auto *FromPtrTy = dyn_cast<PointerType>(FromQTy)) {
Anna Zaks1b068122011-07-28 19:46:48 +0000107 OverloadFixItKind FixKind = OFIK_Dereference;
108
109 bool CanConvert = CompareTypes(
110 S.Context.getCanonicalType(FromPtrTy->getPointeeType()), ToQTy,
111 S, Begin, VK_LValue);
112 if (CanConvert) {
113 // Do not suggest dereferencing a Null pointer.
114 if (Expr->IgnoreParenCasts()->
115 isNullPointerConstant(S.Context, Expr::NPC_ValueDependentIsNotNull))
116 return false;
117
Eugene Zelenkobc9d4f42018-04-05 21:09:03 +0000118 if (const auto *UO = dyn_cast<UnaryOperator>(Expr)) {
Anna Zaks1b068122011-07-28 19:46:48 +0000119 if (UO->getOpcode() == UO_AddrOf) {
120 FixKind = OFIK_RemoveTakeAddress;
121 Hints.push_back(FixItHint::CreateRemoval(
122 CharSourceRange::getTokenRange(Begin, Begin)));
123 }
124 } else if (NeedParen) {
125 Hints.push_back(FixItHint::CreateInsertion(Begin, "*("));
126 Hints.push_back(FixItHint::CreateInsertion(End, ")"));
127 } else {
128 Hints.push_back(FixItHint::CreateInsertion(Begin, "*"));
129 }
130
131 NumConversionsFixed++;
132 if (NumConversionsFixed == 1)
133 Kind = FixKind;
134 return true;
135 }
136 }
137
138 // Check if the pointer to the argument needs to be passed:
139 // (type -> type *) or (type & -> type *).
140 if (isa<PointerType>(ToQTy)) {
141 bool CanConvert = false;
142 OverloadFixItKind FixKind = OFIK_TakeAddress;
143
144 // Only suggest taking address of L-values.
145 if (!Expr->isLValue() || Expr->getObjectKind() != OK_Ordinary)
146 return false;
147
148 CanConvert = CompareTypes(S.Context.getPointerType(FromQTy), ToQTy,
149 S, Begin, VK_RValue);
150 if (CanConvert) {
Eugene Zelenkobc9d4f42018-04-05 21:09:03 +0000151 if (const auto *UO = dyn_cast<UnaryOperator>(Expr)) {
Anna Zaks1b068122011-07-28 19:46:48 +0000152 if (UO->getOpcode() == UO_Deref) {
153 FixKind = OFIK_RemoveDereference;
154 Hints.push_back(FixItHint::CreateRemoval(
155 CharSourceRange::getTokenRange(Begin, Begin)));
156 }
157 } else if (NeedParen) {
158 Hints.push_back(FixItHint::CreateInsertion(Begin, "&("));
159 Hints.push_back(FixItHint::CreateInsertion(End, ")"));
160 } else {
161 Hints.push_back(FixItHint::CreateInsertion(Begin, "&"));
162 }
163
164 NumConversionsFixed++;
165 if (NumConversionsFixed == 1)
166 Kind = FixKind;
167 return true;
168 }
169 }
170
171 return false;
172}
Richard Smith8d06f422012-01-12 23:53:29 +0000173
Richard Smithf7ec86a2013-09-20 00:27:40 +0000174static bool isMacroDefined(const Sema &S, SourceLocation Loc, StringRef Name) {
Richard Smith20e883e2015-04-29 23:20:19 +0000175 return (bool)S.PP.getMacroDefinitionAtLoc(&S.getASTContext().Idents.get(Name),
176 Loc);
Richard Smithd7d57902012-01-13 19:34:55 +0000177}
178
Richard Smithf7ec86a2013-09-20 00:27:40 +0000179static std::string getScalarZeroExpressionForType(
180 const Type &T, SourceLocation Loc, const Sema &S) {
David Blaikie7665a622012-04-30 18:27:22 +0000181 assert(T.isScalarType() && "use scalar types only");
182 // Suggest "0" for non-enumeration scalar types, unless we can find a
183 // better initializer.
184 if (T.isEnumeralType())
Eugene Zelenkobc9d4f42018-04-05 21:09:03 +0000185 return {};
David Blaikie7665a622012-04-30 18:27:22 +0000186 if ((T.isObjCObjectPointerType() || T.isBlockPointerType()) &&
Richard Smithf7ec86a2013-09-20 00:27:40 +0000187 isMacroDefined(S, Loc, "nil"))
David Blaikie7665a622012-04-30 18:27:22 +0000188 return "nil";
189 if (T.isRealFloatingType())
190 return "0.0";
Richard Smithf7ec86a2013-09-20 00:27:40 +0000191 if (T.isBooleanType() &&
192 (S.LangOpts.CPlusPlus || isMacroDefined(S, Loc, "false")))
David Blaikie7665a622012-04-30 18:27:22 +0000193 return "false";
194 if (T.isPointerType() || T.isMemberPointerType()) {
Richard Smith2bf7fdb2013-01-02 11:42:31 +0000195 if (S.LangOpts.CPlusPlus11)
David Blaikie7665a622012-04-30 18:27:22 +0000196 return "nullptr";
Richard Smithf7ec86a2013-09-20 00:27:40 +0000197 if (isMacroDefined(S, Loc, "NULL"))
David Blaikie7665a622012-04-30 18:27:22 +0000198 return "NULL";
199 }
200 if (T.isCharType())
201 return "'\\0'";
202 if (T.isWideCharType())
203 return "L'\\0'";
204 if (T.isChar16Type())
205 return "u'\\0'";
206 if (T.isChar32Type())
207 return "U'\\0'";
208 return "0";
209}
210
Richard Smithf7ec86a2013-09-20 00:27:40 +0000211std::string
212Sema::getFixItZeroInitializerForType(QualType T, SourceLocation Loc) const {
Richard Smithd7d57902012-01-13 19:34:55 +0000213 if (T->isScalarType()) {
Richard Smithf7ec86a2013-09-20 00:27:40 +0000214 std::string s = getScalarZeroExpressionForType(*T, Loc, *this);
David Blaikie7665a622012-04-30 18:27:22 +0000215 if (!s.empty())
216 s = " = " + s;
217 return s;
Richard Smithd7d57902012-01-13 19:34:55 +0000218 }
219
Richard Smith8d06f422012-01-12 23:53:29 +0000220 const CXXRecordDecl *RD = T->getAsCXXRecordDecl();
Richard Smith90b748e2012-01-13 02:14:39 +0000221 if (!RD || !RD->hasDefinition())
Eugene Zelenkobc9d4f42018-04-05 21:09:03 +0000222 return {};
Richard Smith2bf7fdb2013-01-02 11:42:31 +0000223 if (LangOpts.CPlusPlus11 && !RD->hasUserProvidedDefaultConstructor())
Richard Smith8d06f422012-01-12 23:53:29 +0000224 return "{}";
Richard Smith90b748e2012-01-13 02:14:39 +0000225 if (RD->isAggregate())
Richard Smith8d06f422012-01-12 23:53:29 +0000226 return " = {}";
Eugene Zelenkobc9d4f42018-04-05 21:09:03 +0000227 return {};
David Blaikie7665a622012-04-30 18:27:22 +0000228}
229
Richard Smithf7ec86a2013-09-20 00:27:40 +0000230std::string
231Sema::getFixItZeroLiteralForType(QualType T, SourceLocation Loc) const {
232 return getScalarZeroExpressionForType(*T, Loc, *this);
Richard Smith8d06f422012-01-12 23:53:29 +0000233}