1226586Sdim//===--- SemaFixItUtils.cpp - Sema FixIts ---------------------------------===// 2226586Sdim// 3353358Sdim// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4353358Sdim// See https://llvm.org/LICENSE.txt for license information. 5353358Sdim// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6226586Sdim// 7226586Sdim//===----------------------------------------------------------------------===// 8226586Sdim// 9226586Sdim// This file defines helper classes for generation of Sema FixItHints. 10226586Sdim// 11226586Sdim//===----------------------------------------------------------------------===// 12226586Sdim 13239462Sdim#include "clang/AST/ASTContext.h" 14226586Sdim#include "clang/AST/ExprCXX.h" 15226586Sdim#include "clang/AST/ExprObjC.h" 16226586Sdim#include "clang/Lex/Preprocessor.h" 17226586Sdim#include "clang/Sema/Sema.h" 18226586Sdim#include "clang/Sema/SemaFixItUtils.h" 19226586Sdim 20226586Sdimusing namespace clang; 21226586Sdim 22226586Sdimbool ConversionFixItGenerator::compareTypesSimple(CanQualType From, 23226586Sdim CanQualType To, 24226586Sdim Sema &S, 25226586Sdim SourceLocation Loc, 26226586Sdim ExprValueKind FromVK) { 27226586Sdim if (!To.isAtLeastAsQualifiedAs(From)) 28226586Sdim return false; 29226586Sdim 30226586Sdim From = From.getNonReferenceType(); 31226586Sdim To = To.getNonReferenceType(); 32226586Sdim 33226586Sdim // If both are pointer types, work with the pointee types. 34226586Sdim if (isa<PointerType>(From) && isa<PointerType>(To)) { 35226586Sdim From = S.Context.getCanonicalType( 36226586Sdim (cast<PointerType>(From))->getPointeeType()); 37226586Sdim To = S.Context.getCanonicalType( 38226586Sdim (cast<PointerType>(To))->getPointeeType()); 39226586Sdim } 40226586Sdim 41226586Sdim const CanQualType FromUnq = From.getUnqualifiedType(); 42226586Sdim const CanQualType ToUnq = To.getUnqualifiedType(); 43226586Sdim 44296417Sdim if ((FromUnq == ToUnq || (S.IsDerivedFrom(Loc, FromUnq, ToUnq)) ) && 45226586Sdim To.isAtLeastAsQualifiedAs(From)) 46226586Sdim return true; 47226586Sdim return false; 48226586Sdim} 49226586Sdim 50226586Sdimbool ConversionFixItGenerator::tryToFixConversion(const Expr *FullExpr, 51226586Sdim const QualType FromTy, 52226586Sdim const QualType ToTy, 53226586Sdim Sema &S) { 54226586Sdim if (!FullExpr) 55226586Sdim return false; 56226586Sdim 57226586Sdim const CanQualType FromQTy = S.Context.getCanonicalType(FromTy); 58226586Sdim const CanQualType ToQTy = S.Context.getCanonicalType(ToTy); 59226586Sdim const SourceLocation Begin = FullExpr->getSourceRange().getBegin(); 60296417Sdim const SourceLocation End = S.getLocForEndOfToken(FullExpr->getSourceRange() 61296417Sdim .getEnd()); 62226586Sdim 63226586Sdim // Strip the implicit casts - those are implied by the compiler, not the 64226586Sdim // original source code. 65226586Sdim const Expr* Expr = FullExpr->IgnoreImpCasts(); 66226586Sdim 67226586Sdim bool NeedParen = true; 68226586Sdim if (isa<ArraySubscriptExpr>(Expr) || 69226586Sdim isa<CallExpr>(Expr) || 70226586Sdim isa<DeclRefExpr>(Expr) || 71226586Sdim isa<CastExpr>(Expr) || 72226586Sdim isa<CXXNewExpr>(Expr) || 73226586Sdim isa<CXXConstructExpr>(Expr) || 74226586Sdim isa<CXXDeleteExpr>(Expr) || 75226586Sdim isa<CXXNoexceptExpr>(Expr) || 76226586Sdim isa<CXXPseudoDestructorExpr>(Expr) || 77226586Sdim isa<CXXScalarValueInitExpr>(Expr) || 78226586Sdim isa<CXXThisExpr>(Expr) || 79226586Sdim isa<CXXTypeidExpr>(Expr) || 80226586Sdim isa<CXXUnresolvedConstructExpr>(Expr) || 81226586Sdim isa<ObjCMessageExpr>(Expr) || 82226586Sdim isa<ObjCPropertyRefExpr>(Expr) || 83226586Sdim isa<ObjCProtocolExpr>(Expr) || 84226586Sdim isa<MemberExpr>(Expr) || 85226586Sdim isa<ParenExpr>(FullExpr) || 86226586Sdim isa<ParenListExpr>(Expr) || 87226586Sdim isa<SizeOfPackExpr>(Expr) || 88226586Sdim isa<UnaryOperator>(Expr)) 89226586Sdim NeedParen = false; 90226586Sdim 91226586Sdim // Check if the argument needs to be dereferenced: 92226586Sdim // (type * -> type) or (type * -> type &). 93226586Sdim if (const PointerType *FromPtrTy = dyn_cast<PointerType>(FromQTy)) { 94226586Sdim OverloadFixItKind FixKind = OFIK_Dereference; 95226586Sdim 96226586Sdim bool CanConvert = CompareTypes( 97226586Sdim S.Context.getCanonicalType(FromPtrTy->getPointeeType()), ToQTy, 98226586Sdim S, Begin, VK_LValue); 99226586Sdim if (CanConvert) { 100226586Sdim // Do not suggest dereferencing a Null pointer. 101226586Sdim if (Expr->IgnoreParenCasts()-> 102226586Sdim isNullPointerConstant(S.Context, Expr::NPC_ValueDependentIsNotNull)) 103226586Sdim return false; 104226586Sdim 105226586Sdim if (const UnaryOperator *UO = dyn_cast<UnaryOperator>(Expr)) { 106226586Sdim if (UO->getOpcode() == UO_AddrOf) { 107226586Sdim FixKind = OFIK_RemoveTakeAddress; 108226586Sdim Hints.push_back(FixItHint::CreateRemoval( 109226586Sdim CharSourceRange::getTokenRange(Begin, Begin))); 110226586Sdim } 111226586Sdim } else if (NeedParen) { 112226586Sdim Hints.push_back(FixItHint::CreateInsertion(Begin, "*(")); 113226586Sdim Hints.push_back(FixItHint::CreateInsertion(End, ")")); 114226586Sdim } else { 115226586Sdim Hints.push_back(FixItHint::CreateInsertion(Begin, "*")); 116226586Sdim } 117226586Sdim 118226586Sdim NumConversionsFixed++; 119226586Sdim if (NumConversionsFixed == 1) 120226586Sdim Kind = FixKind; 121226586Sdim return true; 122226586Sdim } 123226586Sdim } 124226586Sdim 125226586Sdim // Check if the pointer to the argument needs to be passed: 126226586Sdim // (type -> type *) or (type & -> type *). 127226586Sdim if (isa<PointerType>(ToQTy)) { 128226586Sdim bool CanConvert = false; 129226586Sdim OverloadFixItKind FixKind = OFIK_TakeAddress; 130226586Sdim 131226586Sdim // Only suggest taking address of L-values. 132226586Sdim if (!Expr->isLValue() || Expr->getObjectKind() != OK_Ordinary) 133226586Sdim return false; 134226586Sdim 135226586Sdim CanConvert = CompareTypes(S.Context.getPointerType(FromQTy), ToQTy, 136226586Sdim S, Begin, VK_RValue); 137226586Sdim if (CanConvert) { 138226586Sdim 139226586Sdim if (const UnaryOperator *UO = dyn_cast<UnaryOperator>(Expr)) { 140226586Sdim if (UO->getOpcode() == UO_Deref) { 141226586Sdim FixKind = OFIK_RemoveDereference; 142226586Sdim Hints.push_back(FixItHint::CreateRemoval( 143226586Sdim CharSourceRange::getTokenRange(Begin, Begin))); 144226586Sdim } 145226586Sdim } else if (NeedParen) { 146226586Sdim Hints.push_back(FixItHint::CreateInsertion(Begin, "&(")); 147226586Sdim Hints.push_back(FixItHint::CreateInsertion(End, ")")); 148226586Sdim } else { 149226586Sdim Hints.push_back(FixItHint::CreateInsertion(Begin, "&")); 150226586Sdim } 151226586Sdim 152226586Sdim NumConversionsFixed++; 153226586Sdim if (NumConversionsFixed == 1) 154226586Sdim Kind = FixKind; 155226586Sdim return true; 156226586Sdim } 157226586Sdim } 158226586Sdim 159226586Sdim return false; 160226586Sdim} 161234353Sdim 162261991Sdimstatic bool isMacroDefined(const Sema &S, SourceLocation Loc, StringRef Name) { 163288943Sdim return (bool)S.PP.getMacroDefinitionAtLoc(&S.getASTContext().Idents.get(Name), 164288943Sdim Loc); 165234353Sdim} 166234353Sdim 167261991Sdimstatic std::string getScalarZeroExpressionForType( 168261991Sdim const Type &T, SourceLocation Loc, const Sema &S) { 169239462Sdim assert(T.isScalarType() && "use scalar types only"); 170239462Sdim // Suggest "0" for non-enumeration scalar types, unless we can find a 171239462Sdim // better initializer. 172239462Sdim if (T.isEnumeralType()) 173239462Sdim return std::string(); 174239462Sdim if ((T.isObjCObjectPointerType() || T.isBlockPointerType()) && 175261991Sdim isMacroDefined(S, Loc, "nil")) 176239462Sdim return "nil"; 177239462Sdim if (T.isRealFloatingType()) 178239462Sdim return "0.0"; 179261991Sdim if (T.isBooleanType() && 180261991Sdim (S.LangOpts.CPlusPlus || isMacroDefined(S, Loc, "false"))) 181239462Sdim return "false"; 182239462Sdim if (T.isPointerType() || T.isMemberPointerType()) { 183249423Sdim if (S.LangOpts.CPlusPlus11) 184239462Sdim return "nullptr"; 185261991Sdim if (isMacroDefined(S, Loc, "NULL")) 186239462Sdim return "NULL"; 187239462Sdim } 188239462Sdim if (T.isCharType()) 189239462Sdim return "'\\0'"; 190239462Sdim if (T.isWideCharType()) 191239462Sdim return "L'\\0'"; 192239462Sdim if (T.isChar16Type()) 193239462Sdim return "u'\\0'"; 194239462Sdim if (T.isChar32Type()) 195239462Sdim return "U'\\0'"; 196239462Sdim return "0"; 197239462Sdim} 198239462Sdim 199261991Sdimstd::string 200261991SdimSema::getFixItZeroInitializerForType(QualType T, SourceLocation Loc) const { 201234353Sdim if (T->isScalarType()) { 202261991Sdim std::string s = getScalarZeroExpressionForType(*T, Loc, *this); 203239462Sdim if (!s.empty()) 204239462Sdim s = " = " + s; 205239462Sdim return s; 206234353Sdim } 207234353Sdim 208234353Sdim const CXXRecordDecl *RD = T->getAsCXXRecordDecl(); 209234353Sdim if (!RD || !RD->hasDefinition()) 210239462Sdim return std::string(); 211249423Sdim if (LangOpts.CPlusPlus11 && !RD->hasUserProvidedDefaultConstructor()) 212234353Sdim return "{}"; 213234353Sdim if (RD->isAggregate()) 214234353Sdim return " = {}"; 215239462Sdim return std::string(); 216234353Sdim} 217239462Sdim 218261991Sdimstd::string 219261991SdimSema::getFixItZeroLiteralForType(QualType T, SourceLocation Loc) const { 220261991Sdim return getScalarZeroExpressionForType(*T, Loc, *this); 221239462Sdim} 222