1226586Sdim//===--- SemaFixItUtils.cpp - Sema FixIts ---------------------------------===// 2226586Sdim// 3226586Sdim// The LLVM Compiler Infrastructure 4226586Sdim// 5226586Sdim// This file is distributed under the University of Illinois Open Source 6226586Sdim// License. See LICENSE.TXT for details. 7226586Sdim// 8226586Sdim//===----------------------------------------------------------------------===// 9226586Sdim// 10226586Sdim// This file defines helper classes for generation of Sema FixItHints. 11226586Sdim// 12226586Sdim//===----------------------------------------------------------------------===// 13226586Sdim 14239462Sdim#include "clang/AST/ASTContext.h" 15226586Sdim#include "clang/AST/ExprCXX.h" 16226586Sdim#include "clang/AST/ExprObjC.h" 17226586Sdim#include "clang/Lex/Preprocessor.h" 18226586Sdim#include "clang/Sema/Sema.h" 19226586Sdim#include "clang/Sema/SemaFixItUtils.h" 20226586Sdim 21226586Sdimusing namespace clang; 22226586Sdim 23226586Sdimbool ConversionFixItGenerator::compareTypesSimple(CanQualType From, 24226586Sdim CanQualType To, 25226586Sdim Sema &S, 26226586Sdim SourceLocation Loc, 27226586Sdim ExprValueKind FromVK) { 28226586Sdim if (!To.isAtLeastAsQualifiedAs(From)) 29226586Sdim return false; 30226586Sdim 31226586Sdim From = From.getNonReferenceType(); 32226586Sdim To = To.getNonReferenceType(); 33226586Sdim 34226586Sdim // If both are pointer types, work with the pointee types. 35226586Sdim if (isa<PointerType>(From) && isa<PointerType>(To)) { 36226586Sdim From = S.Context.getCanonicalType( 37226586Sdim (cast<PointerType>(From))->getPointeeType()); 38226586Sdim To = S.Context.getCanonicalType( 39226586Sdim (cast<PointerType>(To))->getPointeeType()); 40226586Sdim } 41226586Sdim 42226586Sdim const CanQualType FromUnq = From.getUnqualifiedType(); 43226586Sdim const CanQualType ToUnq = To.getUnqualifiedType(); 44226586Sdim 45226586Sdim if ((FromUnq == ToUnq || (S.IsDerivedFrom(FromUnq, ToUnq)) ) && 46226586Sdim To.isAtLeastAsQualifiedAs(From)) 47226586Sdim return true; 48226586Sdim return false; 49226586Sdim} 50226586Sdim 51226586Sdimbool ConversionFixItGenerator::tryToFixConversion(const Expr *FullExpr, 52226586Sdim const QualType FromTy, 53226586Sdim const QualType ToTy, 54226586Sdim Sema &S) { 55226586Sdim if (!FullExpr) 56226586Sdim return false; 57226586Sdim 58226586Sdim const CanQualType FromQTy = S.Context.getCanonicalType(FromTy); 59226586Sdim const CanQualType ToQTy = S.Context.getCanonicalType(ToTy); 60226586Sdim const SourceLocation Begin = FullExpr->getSourceRange().getBegin(); 61226586Sdim const SourceLocation End = S.PP.getLocForEndOfToken(FullExpr->getSourceRange() 62226586Sdim .getEnd()); 63226586Sdim 64226586Sdim // Strip the implicit casts - those are implied by the compiler, not the 65226586Sdim // original source code. 66226586Sdim const Expr* Expr = FullExpr->IgnoreImpCasts(); 67226586Sdim 68226586Sdim bool NeedParen = true; 69226586Sdim if (isa<ArraySubscriptExpr>(Expr) || 70226586Sdim isa<CallExpr>(Expr) || 71226586Sdim isa<DeclRefExpr>(Expr) || 72226586Sdim isa<CastExpr>(Expr) || 73226586Sdim isa<CXXNewExpr>(Expr) || 74226586Sdim isa<CXXConstructExpr>(Expr) || 75226586Sdim isa<CXXDeleteExpr>(Expr) || 76226586Sdim isa<CXXNoexceptExpr>(Expr) || 77226586Sdim isa<CXXPseudoDestructorExpr>(Expr) || 78226586Sdim isa<CXXScalarValueInitExpr>(Expr) || 79226586Sdim isa<CXXThisExpr>(Expr) || 80226586Sdim isa<CXXTypeidExpr>(Expr) || 81226586Sdim isa<CXXUnresolvedConstructExpr>(Expr) || 82226586Sdim isa<ObjCMessageExpr>(Expr) || 83226586Sdim isa<ObjCPropertyRefExpr>(Expr) || 84226586Sdim isa<ObjCProtocolExpr>(Expr) || 85226586Sdim isa<MemberExpr>(Expr) || 86226586Sdim isa<ParenExpr>(FullExpr) || 87226586Sdim isa<ParenListExpr>(Expr) || 88226586Sdim isa<SizeOfPackExpr>(Expr) || 89226586Sdim isa<UnaryOperator>(Expr)) 90226586Sdim NeedParen = false; 91226586Sdim 92226586Sdim // Check if the argument needs to be dereferenced: 93226586Sdim // (type * -> type) or (type * -> type &). 94226586Sdim if (const PointerType *FromPtrTy = dyn_cast<PointerType>(FromQTy)) { 95226586Sdim OverloadFixItKind FixKind = OFIK_Dereference; 96226586Sdim 97226586Sdim bool CanConvert = CompareTypes( 98226586Sdim S.Context.getCanonicalType(FromPtrTy->getPointeeType()), ToQTy, 99226586Sdim S, Begin, VK_LValue); 100226586Sdim if (CanConvert) { 101226586Sdim // Do not suggest dereferencing a Null pointer. 102226586Sdim if (Expr->IgnoreParenCasts()-> 103226586Sdim isNullPointerConstant(S.Context, Expr::NPC_ValueDependentIsNotNull)) 104226586Sdim return false; 105226586Sdim 106226586Sdim if (const UnaryOperator *UO = dyn_cast<UnaryOperator>(Expr)) { 107226586Sdim if (UO->getOpcode() == UO_AddrOf) { 108226586Sdim FixKind = OFIK_RemoveTakeAddress; 109226586Sdim Hints.push_back(FixItHint::CreateRemoval( 110226586Sdim CharSourceRange::getTokenRange(Begin, Begin))); 111226586Sdim } 112226586Sdim } else if (NeedParen) { 113226586Sdim Hints.push_back(FixItHint::CreateInsertion(Begin, "*(")); 114226586Sdim Hints.push_back(FixItHint::CreateInsertion(End, ")")); 115226586Sdim } else { 116226586Sdim Hints.push_back(FixItHint::CreateInsertion(Begin, "*")); 117226586Sdim } 118226586Sdim 119226586Sdim NumConversionsFixed++; 120226586Sdim if (NumConversionsFixed == 1) 121226586Sdim Kind = FixKind; 122226586Sdim return true; 123226586Sdim } 124226586Sdim } 125226586Sdim 126226586Sdim // Check if the pointer to the argument needs to be passed: 127226586Sdim // (type -> type *) or (type & -> type *). 128226586Sdim if (isa<PointerType>(ToQTy)) { 129226586Sdim bool CanConvert = false; 130226586Sdim OverloadFixItKind FixKind = OFIK_TakeAddress; 131226586Sdim 132226586Sdim // Only suggest taking address of L-values. 133226586Sdim if (!Expr->isLValue() || Expr->getObjectKind() != OK_Ordinary) 134226586Sdim return false; 135226586Sdim 136226586Sdim CanConvert = CompareTypes(S.Context.getPointerType(FromQTy), ToQTy, 137226586Sdim S, Begin, VK_RValue); 138226586Sdim if (CanConvert) { 139226586Sdim 140226586Sdim if (const UnaryOperator *UO = dyn_cast<UnaryOperator>(Expr)) { 141226586Sdim if (UO->getOpcode() == UO_Deref) { 142226586Sdim FixKind = OFIK_RemoveDereference; 143226586Sdim Hints.push_back(FixItHint::CreateRemoval( 144226586Sdim CharSourceRange::getTokenRange(Begin, Begin))); 145226586Sdim } 146226586Sdim } else if (NeedParen) { 147226586Sdim Hints.push_back(FixItHint::CreateInsertion(Begin, "&(")); 148226586Sdim Hints.push_back(FixItHint::CreateInsertion(End, ")")); 149226586Sdim } else { 150226586Sdim Hints.push_back(FixItHint::CreateInsertion(Begin, "&")); 151226586Sdim } 152226586Sdim 153226586Sdim NumConversionsFixed++; 154226586Sdim if (NumConversionsFixed == 1) 155226586Sdim Kind = FixKind; 156226586Sdim return true; 157226586Sdim } 158226586Sdim } 159226586Sdim 160226586Sdim return false; 161226586Sdim} 162234353Sdim 163263508Sdimstatic bool isMacroDefined(const Sema &S, SourceLocation Loc, StringRef Name) { 164263508Sdim const IdentifierInfo *II = &S.getASTContext().Idents.get(Name); 165263508Sdim if (!II->hadMacroDefinition()) return false; 166263508Sdim 167263508Sdim MacroDirective *Macro = S.PP.getMacroDirectiveHistory(II); 168263508Sdim return Macro && Macro->findDirectiveAtLoc(Loc, S.getSourceManager()); 169234353Sdim} 170234353Sdim 171263508Sdimstatic std::string getScalarZeroExpressionForType( 172263508Sdim const Type &T, SourceLocation Loc, const Sema &S) { 173239462Sdim assert(T.isScalarType() && "use scalar types only"); 174239462Sdim // Suggest "0" for non-enumeration scalar types, unless we can find a 175239462Sdim // better initializer. 176239462Sdim if (T.isEnumeralType()) 177239462Sdim return std::string(); 178239462Sdim if ((T.isObjCObjectPointerType() || T.isBlockPointerType()) && 179263508Sdim isMacroDefined(S, Loc, "nil")) 180239462Sdim return "nil"; 181239462Sdim if (T.isRealFloatingType()) 182239462Sdim return "0.0"; 183263508Sdim if (T.isBooleanType() && 184263508Sdim (S.LangOpts.CPlusPlus || isMacroDefined(S, Loc, "false"))) 185239462Sdim return "false"; 186239462Sdim if (T.isPointerType() || T.isMemberPointerType()) { 187249423Sdim if (S.LangOpts.CPlusPlus11) 188239462Sdim return "nullptr"; 189263508Sdim if (isMacroDefined(S, Loc, "NULL")) 190239462Sdim return "NULL"; 191239462Sdim } 192239462Sdim if (T.isCharType()) 193239462Sdim return "'\\0'"; 194239462Sdim if (T.isWideCharType()) 195239462Sdim return "L'\\0'"; 196239462Sdim if (T.isChar16Type()) 197239462Sdim return "u'\\0'"; 198239462Sdim if (T.isChar32Type()) 199239462Sdim return "U'\\0'"; 200239462Sdim return "0"; 201239462Sdim} 202239462Sdim 203263508Sdimstd::string 204263508SdimSema::getFixItZeroInitializerForType(QualType T, SourceLocation Loc) const { 205234353Sdim if (T->isScalarType()) { 206263508Sdim std::string s = getScalarZeroExpressionForType(*T, Loc, *this); 207239462Sdim if (!s.empty()) 208239462Sdim s = " = " + s; 209239462Sdim return s; 210234353Sdim } 211234353Sdim 212234353Sdim const CXXRecordDecl *RD = T->getAsCXXRecordDecl(); 213234353Sdim if (!RD || !RD->hasDefinition()) 214239462Sdim return std::string(); 215249423Sdim if (LangOpts.CPlusPlus11 && !RD->hasUserProvidedDefaultConstructor()) 216234353Sdim return "{}"; 217234353Sdim if (RD->isAggregate()) 218234353Sdim return " = {}"; 219239462Sdim return std::string(); 220234353Sdim} 221239462Sdim 222263508Sdimstd::string 223263508SdimSema::getFixItZeroLiteralForType(QualType T, SourceLocation Loc) const { 224263508Sdim return getScalarZeroExpressionForType(*T, Loc, *this); 225239462Sdim} 226