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