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
21using namespace clang;
22
23bool 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
51bool 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
163static bool isMacroDefined(const Sema &S, SourceLocation Loc, StringRef Name) {
164  const IdentifierInfo *II = &S.getASTContext().Idents.get(Name);
165  if (!II->hadMacroDefinition()) return false;
166
167  MacroDirective *Macro = S.PP.getMacroDirectiveHistory(II);
168  return Macro && Macro->findDirectiveAtLoc(Loc, S.getSourceManager());
169}
170
171static std::string getScalarZeroExpressionForType(
172    const Type &T, SourceLocation Loc, const Sema &S) {
173  assert(T.isScalarType() && "use scalar types only");
174  // Suggest "0" for non-enumeration scalar types, unless we can find a
175  // better initializer.
176  if (T.isEnumeralType())
177    return std::string();
178  if ((T.isObjCObjectPointerType() || T.isBlockPointerType()) &&
179      isMacroDefined(S, Loc, "nil"))
180    return "nil";
181  if (T.isRealFloatingType())
182    return "0.0";
183  if (T.isBooleanType() &&
184      (S.LangOpts.CPlusPlus || isMacroDefined(S, Loc, "false")))
185    return "false";
186  if (T.isPointerType() || T.isMemberPointerType()) {
187    if (S.LangOpts.CPlusPlus11)
188      return "nullptr";
189    if (isMacroDefined(S, Loc, "NULL"))
190      return "NULL";
191  }
192  if (T.isCharType())
193    return "'\\0'";
194  if (T.isWideCharType())
195    return "L'\\0'";
196  if (T.isChar16Type())
197    return "u'\\0'";
198  if (T.isChar32Type())
199    return "U'\\0'";
200  return "0";
201}
202
203std::string
204Sema::getFixItZeroInitializerForType(QualType T, SourceLocation Loc) const {
205  if (T->isScalarType()) {
206    std::string s = getScalarZeroExpressionForType(*T, Loc, *this);
207    if (!s.empty())
208      s = " = " + s;
209    return s;
210  }
211
212  const CXXRecordDecl *RD = T->getAsCXXRecordDecl();
213  if (!RD || !RD->hasDefinition())
214    return std::string();
215  if (LangOpts.CPlusPlus11 && !RD->hasUserProvidedDefaultConstructor())
216    return "{}";
217  if (RD->isAggregate())
218    return " = {}";
219  return std::string();
220}
221
222std::string
223Sema::getFixItZeroLiteralForType(QualType T, SourceLocation Loc) const {
224  return getScalarZeroExpressionForType(*T, Loc, *this);
225}
226