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/Sema/SemaFixItUtils.h" 15 #include "clang/AST/ASTContext.h" 16 #include "clang/AST/DeclCXX.h" 17 #include "clang/AST/DeclarationName.h" 18 #include "clang/AST/Expr.h" 19 #include "clang/AST/ExprCXX.h" 20 #include "clang/AST/ExprObjC.h" 21 #include "clang/AST/Type.h" 22 #include "clang/Basic/Diagnostic.h" 23 #include "clang/Basic/LLVM.h" 24 #include "clang/Basic/LangOptions.h" 25 #include "clang/Basic/SourceLocation.h" 26 #include "clang/Lex/Preprocessor.h" 27 #include "clang/Sema/Sema.h" 28 #include "llvm/ADT/StringRef.h" 29 #include "llvm/Support/Casting.h" 30 #include <cassert> 31 #include <string> 32 33 using namespace clang; 34 35 bool ConversionFixItGenerator::compareTypesSimple(CanQualType From, 36 CanQualType To, 37 Sema &S, 38 SourceLocation Loc, 39 ExprValueKind FromVK) { 40 if (!To.isAtLeastAsQualifiedAs(From)) 41 return false; 42 43 From = From.getNonReferenceType(); 44 To = To.getNonReferenceType(); 45 46 // If both are pointer types, work with the pointee types. 47 if (isa<PointerType>(From) && isa<PointerType>(To)) { 48 From = S.Context.getCanonicalType( 49 (cast<PointerType>(From))->getPointeeType()); 50 To = S.Context.getCanonicalType( 51 (cast<PointerType>(To))->getPointeeType()); 52 } 53 54 const CanQualType FromUnq = From.getUnqualifiedType(); 55 const CanQualType ToUnq = To.getUnqualifiedType(); 56 57 if ((FromUnq == ToUnq || (S.IsDerivedFrom(Loc, FromUnq, ToUnq)) ) && 58 To.isAtLeastAsQualifiedAs(From)) 59 return true; 60 return false; 61 } 62 63 bool ConversionFixItGenerator::tryToFixConversion(const Expr *FullExpr, 64 const QualType FromTy, 65 const QualType ToTy, 66 Sema &S) { 67 if (!FullExpr) 68 return false; 69 70 const CanQualType FromQTy = S.Context.getCanonicalType(FromTy); 71 const CanQualType ToQTy = S.Context.getCanonicalType(ToTy); 72 const SourceLocation Begin = FullExpr->getSourceRange().getBegin(); 73 const SourceLocation End = S.getLocForEndOfToken(FullExpr->getSourceRange() 74 .getEnd()); 75 76 // Strip the implicit casts - those are implied by the compiler, not the 77 // original source code. 78 const Expr* Expr = FullExpr->IgnoreImpCasts(); 79 80 bool NeedParen = true; 81 if (isa<ArraySubscriptExpr>(Expr) || 82 isa<CallExpr>(Expr) || 83 isa<DeclRefExpr>(Expr) || 84 isa<CastExpr>(Expr) || 85 isa<CXXNewExpr>(Expr) || 86 isa<CXXConstructExpr>(Expr) || 87 isa<CXXDeleteExpr>(Expr) || 88 isa<CXXNoexceptExpr>(Expr) || 89 isa<CXXPseudoDestructorExpr>(Expr) || 90 isa<CXXScalarValueInitExpr>(Expr) || 91 isa<CXXThisExpr>(Expr) || 92 isa<CXXTypeidExpr>(Expr) || 93 isa<CXXUnresolvedConstructExpr>(Expr) || 94 isa<ObjCMessageExpr>(Expr) || 95 isa<ObjCPropertyRefExpr>(Expr) || 96 isa<ObjCProtocolExpr>(Expr) || 97 isa<MemberExpr>(Expr) || 98 isa<ParenExpr>(FullExpr) || 99 isa<ParenListExpr>(Expr) || 100 isa<SizeOfPackExpr>(Expr) || 101 isa<UnaryOperator>(Expr)) 102 NeedParen = false; 103 104 // Check if the argument needs to be dereferenced: 105 // (type * -> type) or (type * -> type &). 106 if (const auto *FromPtrTy = dyn_cast<PointerType>(FromQTy)) { 107 OverloadFixItKind FixKind = OFIK_Dereference; 108 109 bool CanConvert = CompareTypes( 110 S.Context.getCanonicalType(FromPtrTy->getPointeeType()), ToQTy, 111 S, Begin, VK_LValue); 112 if (CanConvert) { 113 // Do not suggest dereferencing a Null pointer. 114 if (Expr->IgnoreParenCasts()-> 115 isNullPointerConstant(S.Context, Expr::NPC_ValueDependentIsNotNull)) 116 return false; 117 118 if (const auto *UO = dyn_cast<UnaryOperator>(Expr)) { 119 if (UO->getOpcode() == UO_AddrOf) { 120 FixKind = OFIK_RemoveTakeAddress; 121 Hints.push_back(FixItHint::CreateRemoval( 122 CharSourceRange::getTokenRange(Begin, Begin))); 123 } 124 } else if (NeedParen) { 125 Hints.push_back(FixItHint::CreateInsertion(Begin, "*(")); 126 Hints.push_back(FixItHint::CreateInsertion(End, ")")); 127 } else { 128 Hints.push_back(FixItHint::CreateInsertion(Begin, "*")); 129 } 130 131 NumConversionsFixed++; 132 if (NumConversionsFixed == 1) 133 Kind = FixKind; 134 return true; 135 } 136 } 137 138 // Check if the pointer to the argument needs to be passed: 139 // (type -> type *) or (type & -> type *). 140 if (isa<PointerType>(ToQTy)) { 141 bool CanConvert = false; 142 OverloadFixItKind FixKind = OFIK_TakeAddress; 143 144 // Only suggest taking address of L-values. 145 if (!Expr->isLValue() || Expr->getObjectKind() != OK_Ordinary) 146 return false; 147 148 CanConvert = CompareTypes(S.Context.getPointerType(FromQTy), ToQTy, 149 S, Begin, VK_RValue); 150 if (CanConvert) { 151 if (const auto *UO = dyn_cast<UnaryOperator>(Expr)) { 152 if (UO->getOpcode() == UO_Deref) { 153 FixKind = OFIK_RemoveDereference; 154 Hints.push_back(FixItHint::CreateRemoval( 155 CharSourceRange::getTokenRange(Begin, Begin))); 156 } 157 } else if (NeedParen) { 158 Hints.push_back(FixItHint::CreateInsertion(Begin, "&(")); 159 Hints.push_back(FixItHint::CreateInsertion(End, ")")); 160 } else { 161 Hints.push_back(FixItHint::CreateInsertion(Begin, "&")); 162 } 163 164 NumConversionsFixed++; 165 if (NumConversionsFixed == 1) 166 Kind = FixKind; 167 return true; 168 } 169 } 170 171 return false; 172 } 173 174 static bool isMacroDefined(const Sema &S, SourceLocation Loc, StringRef Name) { 175 return (bool)S.PP.getMacroDefinitionAtLoc(&S.getASTContext().Idents.get(Name), 176 Loc); 177 } 178 179 static std::string getScalarZeroExpressionForType( 180 const Type &T, SourceLocation Loc, const Sema &S) { 181 assert(T.isScalarType() && "use scalar types only"); 182 // Suggest "0" for non-enumeration scalar types, unless we can find a 183 // better initializer. 184 if (T.isEnumeralType()) 185 return {}; 186 if ((T.isObjCObjectPointerType() || T.isBlockPointerType()) && 187 isMacroDefined(S, Loc, "nil")) 188 return "nil"; 189 if (T.isRealFloatingType()) 190 return "0.0"; 191 if (T.isBooleanType() && 192 (S.LangOpts.CPlusPlus || isMacroDefined(S, Loc, "false"))) 193 return "false"; 194 if (T.isPointerType() || T.isMemberPointerType()) { 195 if (S.LangOpts.CPlusPlus11) 196 return "nullptr"; 197 if (isMacroDefined(S, Loc, "NULL")) 198 return "NULL"; 199 } 200 if (T.isCharType()) 201 return "'\\0'"; 202 if (T.isWideCharType()) 203 return "L'\\0'"; 204 if (T.isChar16Type()) 205 return "u'\\0'"; 206 if (T.isChar32Type()) 207 return "U'\\0'"; 208 return "0"; 209 } 210 211 std::string 212 Sema::getFixItZeroInitializerForType(QualType T, SourceLocation Loc) const { 213 if (T->isScalarType()) { 214 std::string s = getScalarZeroExpressionForType(*T, Loc, *this); 215 if (!s.empty()) 216 s = " = " + s; 217 return s; 218 } 219 220 const CXXRecordDecl *RD = T->getAsCXXRecordDecl(); 221 if (!RD || !RD->hasDefinition()) 222 return {}; 223 if (LangOpts.CPlusPlus11 && !RD->hasUserProvidedDefaultConstructor()) 224 return "{}"; 225 if (RD->isAggregate()) 226 return " = {}"; 227 return {}; 228 } 229 230 std::string 231 Sema::getFixItZeroLiteralForType(QualType T, SourceLocation Loc) const { 232 return getScalarZeroExpressionForType(*T, Loc, *this); 233 } 234