| Anna Zaks | f3546ee | 2011-07-28 19:46:48 +0000 | [diff] [blame] | 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 |  | 
 | 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 |   // 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 |  | 
 | 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.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 | } | 
| Richard Smith | 7984de3 | 2012-01-12 23:53:29 +0000 | [diff] [blame] | 161 |  | 
| Richard Smith | e401415 | 2012-01-13 19:34:55 +0000 | [diff] [blame] | 162 | static bool isMacroDefined(const Sema &S, StringRef Name) { | 
 | 163 |   return S.PP.getMacroInfo(&S.getASTContext().Idents.get(Name)); | 
 | 164 | } | 
 | 165 |  | 
| David Blaikie | 2c0abf4 | 2012-04-30 18:27:22 +0000 | [diff] [blame] | 166 | static std::string getScalarZeroExpressionForType(const Type& T, const Sema& S) { | 
 | 167 |   assert(T.isScalarType() && "use scalar types only"); | 
 | 168 |   // Suggest "0" for non-enumeration scalar types, unless we can find a | 
 | 169 |   // better initializer. | 
 | 170 |   if (T.isEnumeralType()) | 
 | 171 |     return std::string(); | 
 | 172 |   if ((T.isObjCObjectPointerType() || T.isBlockPointerType()) && | 
 | 173 |       isMacroDefined(S, "nil")) | 
 | 174 |     return "nil"; | 
 | 175 |   if (T.isRealFloatingType()) | 
 | 176 |     return "0.0"; | 
 | 177 |   if (T.isBooleanType() && S.LangOpts.CPlusPlus) | 
 | 178 |     return "false"; | 
 | 179 |   if (T.isPointerType() || T.isMemberPointerType()) { | 
 | 180 |     if (S.LangOpts.CPlusPlus0x) | 
 | 181 |       return "nullptr"; | 
 | 182 |     if (isMacroDefined(S, "NULL")) | 
 | 183 |       return "NULL"; | 
 | 184 |   } | 
 | 185 |   if (T.isCharType()) | 
 | 186 |     return "'\\0'"; | 
 | 187 |   if (T.isWideCharType()) | 
 | 188 |     return "L'\\0'"; | 
 | 189 |   if (T.isChar16Type()) | 
 | 190 |     return "u'\\0'"; | 
 | 191 |   if (T.isChar32Type()) | 
 | 192 |     return "U'\\0'"; | 
 | 193 |   return "0"; | 
 | 194 | } | 
 | 195 |  | 
 | 196 | std::string Sema::getFixItZeroInitializerForType(QualType T) const { | 
| Richard Smith | e401415 | 2012-01-13 19:34:55 +0000 | [diff] [blame] | 197 |   if (T->isScalarType()) { | 
| David Blaikie | 2c0abf4 | 2012-04-30 18:27:22 +0000 | [diff] [blame] | 198 |     std::string s = getScalarZeroExpressionForType(*T, *this); | 
 | 199 |     if (!s.empty()) | 
 | 200 |       s = " = " + s; | 
 | 201 |     return s; | 
| Richard Smith | e401415 | 2012-01-13 19:34:55 +0000 | [diff] [blame] | 202 |   } | 
 | 203 |  | 
| Richard Smith | 7984de3 | 2012-01-12 23:53:29 +0000 | [diff] [blame] | 204 |   const CXXRecordDecl *RD = T->getAsCXXRecordDecl(); | 
| Richard Smith | f037541 | 2012-01-13 02:14:39 +0000 | [diff] [blame] | 205 |   if (!RD || !RD->hasDefinition()) | 
| David Blaikie | 2c0abf4 | 2012-04-30 18:27:22 +0000 | [diff] [blame] | 206 |     return std::string(); | 
| Richard Smith | f037541 | 2012-01-13 02:14:39 +0000 | [diff] [blame] | 207 |   if (LangOpts.CPlusPlus0x && !RD->hasUserProvidedDefaultConstructor()) | 
| Richard Smith | 7984de3 | 2012-01-12 23:53:29 +0000 | [diff] [blame] | 208 |     return "{}"; | 
| Richard Smith | f037541 | 2012-01-13 02:14:39 +0000 | [diff] [blame] | 209 |   if (RD->isAggregate()) | 
| Richard Smith | 7984de3 | 2012-01-12 23:53:29 +0000 | [diff] [blame] | 210 |     return " = {}"; | 
| David Blaikie | 2c0abf4 | 2012-04-30 18:27:22 +0000 | [diff] [blame] | 211 |   return std::string(); | 
 | 212 | } | 
 | 213 |  | 
 | 214 | std::string Sema::getFixItZeroLiteralForType(QualType T) const { | 
 | 215 |   return getScalarZeroExpressionForType(*T, *this); | 
| Richard Smith | 7984de3 | 2012-01-12 23:53:29 +0000 | [diff] [blame] | 216 | } |