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 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 } 162 163 static bool isMacroDefined(const Sema &S, StringRef Name) { 164 return S.PP.getMacroInfo(&S.getASTContext().Idents.get(Name)); 165 } 166 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.CPlusPlus11) 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 { 198 if (T->isScalarType()) { 199 std::string s = getScalarZeroExpressionForType(*T, *this); 200 if (!s.empty()) 201 s = " = " + s; 202 return s; 203 } 204 205 const CXXRecordDecl *RD = T->getAsCXXRecordDecl(); 206 if (!RD || !RD->hasDefinition()) 207 return std::string(); 208 if (LangOpts.CPlusPlus11 && !RD->hasUserProvidedDefaultConstructor()) 209 return "{}"; 210 if (RD->isAggregate()) 211 return " = {}"; 212 return std::string(); 213 } 214 215 std::string Sema::getFixItZeroLiteralForType(QualType T) const { 216 return getScalarZeroExpressionForType(*T, *this); 217 } 218