SemaFixItUtils.cpp revision 226586
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/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
20using namespace clang;
21
22bool 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  // If both are pointer types, work with the pointee types.
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(FromUnq, ToUnq)) ) &&
45      To.isAtLeastAsQualifiedAs(From))
46    return true;
47  return false;
48}
49
50bool 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.PP.getLocForEndOfToken(FullExpr->getSourceRange()
61                                                      .getEnd());
62
63  // Strip the implicit casts - those are implied by the compiler, not the
64  // original source code.
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  // Check if the argument needs to be dereferenced:
92  //   (type * -> type) or (type * -> type &).
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      // Do not suggest dereferencing a Null pointer.
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  // Check if the pointer to the argument needs to be passed:
126  //   (type -> type *) or (type & -> type *).
127  if (isa<PointerType>(ToQTy)) {
128    bool CanConvert = false;
129    OverloadFixItKind FixKind = OFIK_TakeAddress;
130
131    // Only suggest taking address of L-values.
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