SemaFixItUtils.cpp revision 239462
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 163234353Sdimstatic bool isMacroDefined(const Sema &S, StringRef Name) { 164234353Sdim return S.PP.getMacroInfo(&S.getASTContext().Idents.get(Name)); 165234353Sdim} 166234353Sdim 167239462Sdimstatic std::string getScalarZeroExpressionForType(const Type& T, const Sema& S) { 168239462Sdim assert(T.isScalarType() && "use scalar types only"); 169239462Sdim // Suggest "0" for non-enumeration scalar types, unless we can find a 170239462Sdim // better initializer. 171239462Sdim if (T.isEnumeralType()) 172239462Sdim return std::string(); 173239462Sdim if ((T.isObjCObjectPointerType() || T.isBlockPointerType()) && 174239462Sdim isMacroDefined(S, "nil")) 175239462Sdim return "nil"; 176239462Sdim if (T.isRealFloatingType()) 177239462Sdim return "0.0"; 178239462Sdim if (T.isBooleanType() && S.LangOpts.CPlusPlus) 179239462Sdim return "false"; 180239462Sdim if (T.isPointerType() || T.isMemberPointerType()) { 181239462Sdim if (S.LangOpts.CPlusPlus0x) 182239462Sdim return "nullptr"; 183239462Sdim if (isMacroDefined(S, "NULL")) 184239462Sdim return "NULL"; 185239462Sdim } 186239462Sdim if (T.isCharType()) 187239462Sdim return "'\\0'"; 188239462Sdim if (T.isWideCharType()) 189239462Sdim return "L'\\0'"; 190239462Sdim if (T.isChar16Type()) 191239462Sdim return "u'\\0'"; 192239462Sdim if (T.isChar32Type()) 193239462Sdim return "U'\\0'"; 194239462Sdim return "0"; 195239462Sdim} 196239462Sdim 197239462Sdimstd::string Sema::getFixItZeroInitializerForType(QualType T) const { 198234353Sdim if (T->isScalarType()) { 199239462Sdim std::string s = getScalarZeroExpressionForType(*T, *this); 200239462Sdim if (!s.empty()) 201239462Sdim s = " = " + s; 202239462Sdim return s; 203234353Sdim } 204234353Sdim 205234353Sdim const CXXRecordDecl *RD = T->getAsCXXRecordDecl(); 206234353Sdim if (!RD || !RD->hasDefinition()) 207239462Sdim return std::string(); 208234353Sdim if (LangOpts.CPlusPlus0x && !RD->hasUserProvidedDefaultConstructor()) 209234353Sdim return "{}"; 210234353Sdim if (RD->isAggregate()) 211234353Sdim return " = {}"; 212239462Sdim return std::string(); 213234353Sdim} 214239462Sdim 215239462Sdimstd::string Sema::getFixItZeroLiteralForType(QualType T) const { 216239462Sdim return getScalarZeroExpressionForType(*T, *this); 217239462Sdim} 218