1 //===--- SemaFixItUtils.cpp - Sema FixIts ---------------------------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 // 9 // This file defines helper classes for generation of Sema FixItHints. 10 // 11 //===----------------------------------------------------------------------===// 12 13 #include "clang/AST/ASTContext.h" 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(Loc, 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.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, S, 136 Begin, VK_PRValue); 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 162 static bool isMacroDefined(const Sema &S, SourceLocation Loc, StringRef Name) { 163 return (bool)S.PP.getMacroDefinitionAtLoc(&S.getASTContext().Idents.get(Name), 164 Loc); 165 } 166 167 static std::string getScalarZeroExpressionForType( 168 const Type &T, SourceLocation Loc, const Sema &S) { 169 assert(T.isScalarType() && "use scalar types only"); 170 // Suggest "0" for non-enumeration scalar types, unless we can find a 171 // better initializer. 172 if (T.isEnumeralType()) 173 return std::string(); 174 if ((T.isObjCObjectPointerType() || T.isBlockPointerType()) && 175 isMacroDefined(S, Loc, "nil")) 176 return "nil"; 177 if (T.isRealFloatingType()) 178 return "0.0"; 179 if (T.isBooleanType() && 180 (S.LangOpts.CPlusPlus || isMacroDefined(S, Loc, "false"))) 181 return "false"; 182 if (T.isPointerType() || T.isMemberPointerType()) { 183 if (S.LangOpts.CPlusPlus11) 184 return "nullptr"; 185 if (isMacroDefined(S, Loc, "NULL")) 186 return "NULL"; 187 } 188 if (T.isCharType()) 189 return "'\\0'"; 190 if (T.isWideCharType()) 191 return "L'\\0'"; 192 if (T.isChar16Type()) 193 return "u'\\0'"; 194 if (T.isChar32Type()) 195 return "U'\\0'"; 196 return "0"; 197 } 198 199 std::string 200 Sema::getFixItZeroInitializerForType(QualType T, SourceLocation Loc) const { 201 if (T->isScalarType()) { 202 std::string s = getScalarZeroExpressionForType(*T, Loc, *this); 203 if (!s.empty()) 204 s = " = " + s; 205 return s; 206 } 207 208 const CXXRecordDecl *RD = T->getAsCXXRecordDecl(); 209 if (!RD || !RD->hasDefinition()) 210 return std::string(); 211 if (LangOpts.CPlusPlus11 && !RD->hasUserProvidedDefaultConstructor()) 212 return "{}"; 213 if (RD->isAggregate()) 214 return " = {}"; 215 return std::string(); 216 } 217 218 std::string 219 Sema::getFixItZeroLiteralForType(QualType T, SourceLocation Loc) const { 220 return getScalarZeroExpressionForType(*T, Loc, *this); 221 } 222