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