clang API Documentation
00001 //===--- SemaFixItUtils.cpp - Sema FixIts ---------------------------------===// 00002 // 00003 // The LLVM Compiler Infrastructure 00004 // 00005 // This file is distributed under the University of Illinois Open Source 00006 // License. See LICENSE.TXT for details. 00007 // 00008 //===----------------------------------------------------------------------===// 00009 // 00010 // This file defines helper classes for generation of Sema FixItHints. 00011 // 00012 //===----------------------------------------------------------------------===// 00013 00014 #include "clang/AST/ExprCXX.h" 00015 #include "clang/AST/ExprObjC.h" 00016 #include "clang/Lex/Preprocessor.h" 00017 #include "clang/Sema/Sema.h" 00018 #include "clang/Sema/SemaFixItUtils.h" 00019 00020 using namespace clang; 00021 00022 bool ConversionFixItGenerator::compareTypesSimple(CanQualType From, 00023 CanQualType To, 00024 Sema &S, 00025 SourceLocation Loc, 00026 ExprValueKind FromVK) { 00027 if (!To.isAtLeastAsQualifiedAs(From)) 00028 return false; 00029 00030 From = From.getNonReferenceType(); 00031 To = To.getNonReferenceType(); 00032 00033 // If both are pointer types, work with the pointee types. 00034 if (isa<PointerType>(From) && isa<PointerType>(To)) { 00035 From = S.Context.getCanonicalType( 00036 (cast<PointerType>(From))->getPointeeType()); 00037 To = S.Context.getCanonicalType( 00038 (cast<PointerType>(To))->getPointeeType()); 00039 } 00040 00041 const CanQualType FromUnq = From.getUnqualifiedType(); 00042 const CanQualType ToUnq = To.getUnqualifiedType(); 00043 00044 if ((FromUnq == ToUnq || (S.IsDerivedFrom(FromUnq, ToUnq)) ) && 00045 To.isAtLeastAsQualifiedAs(From)) 00046 return true; 00047 return false; 00048 } 00049 00050 bool ConversionFixItGenerator::tryToFixConversion(const Expr *FullExpr, 00051 const QualType FromTy, 00052 const QualType ToTy, 00053 Sema &S) { 00054 if (!FullExpr) 00055 return false; 00056 00057 const CanQualType FromQTy = S.Context.getCanonicalType(FromTy); 00058 const CanQualType ToQTy = S.Context.getCanonicalType(ToTy); 00059 const SourceLocation Begin = FullExpr->getSourceRange().getBegin(); 00060 const SourceLocation End = S.PP.getLocForEndOfToken(FullExpr->getSourceRange() 00061 .getEnd()); 00062 00063 // Strip the implicit casts - those are implied by the compiler, not the 00064 // original source code. 00065 const Expr* Expr = FullExpr->IgnoreImpCasts(); 00066 00067 bool NeedParen = true; 00068 if (isa<ArraySubscriptExpr>(Expr) || 00069 isa<CallExpr>(Expr) || 00070 isa<DeclRefExpr>(Expr) || 00071 isa<CastExpr>(Expr) || 00072 isa<CXXNewExpr>(Expr) || 00073 isa<CXXConstructExpr>(Expr) || 00074 isa<CXXDeleteExpr>(Expr) || 00075 isa<CXXNoexceptExpr>(Expr) || 00076 isa<CXXPseudoDestructorExpr>(Expr) || 00077 isa<CXXScalarValueInitExpr>(Expr) || 00078 isa<CXXThisExpr>(Expr) || 00079 isa<CXXTypeidExpr>(Expr) || 00080 isa<CXXUnresolvedConstructExpr>(Expr) || 00081 isa<ObjCMessageExpr>(Expr) || 00082 isa<ObjCPropertyRefExpr>(Expr) || 00083 isa<ObjCProtocolExpr>(Expr) || 00084 isa<MemberExpr>(Expr) || 00085 isa<ParenExpr>(FullExpr) || 00086 isa<ParenListExpr>(Expr) || 00087 isa<SizeOfPackExpr>(Expr) || 00088 isa<UnaryOperator>(Expr)) 00089 NeedParen = false; 00090 00091 // Check if the argument needs to be dereferenced: 00092 // (type * -> type) or (type * -> type &). 00093 if (const PointerType *FromPtrTy = dyn_cast<PointerType>(FromQTy)) { 00094 OverloadFixItKind FixKind = OFIK_Dereference; 00095 00096 bool CanConvert = CompareTypes( 00097 S.Context.getCanonicalType(FromPtrTy->getPointeeType()), ToQTy, 00098 S, Begin, VK_LValue); 00099 if (CanConvert) { 00100 // Do not suggest dereferencing a Null pointer. 00101 if (Expr->IgnoreParenCasts()-> 00102 isNullPointerConstant(S.Context, Expr::NPC_ValueDependentIsNotNull)) 00103 return false; 00104 00105 if (const UnaryOperator *UO = dyn_cast<UnaryOperator>(Expr)) { 00106 if (UO->getOpcode() == UO_AddrOf) { 00107 FixKind = OFIK_RemoveTakeAddress; 00108 Hints.push_back(FixItHint::CreateRemoval( 00109 CharSourceRange::getTokenRange(Begin, Begin))); 00110 } 00111 } else if (NeedParen) { 00112 Hints.push_back(FixItHint::CreateInsertion(Begin, "*(")); 00113 Hints.push_back(FixItHint::CreateInsertion(End, ")")); 00114 } else { 00115 Hints.push_back(FixItHint::CreateInsertion(Begin, "*")); 00116 } 00117 00118 NumConversionsFixed++; 00119 if (NumConversionsFixed == 1) 00120 Kind = FixKind; 00121 return true; 00122 } 00123 } 00124 00125 // Check if the pointer to the argument needs to be passed: 00126 // (type -> type *) or (type & -> type *). 00127 if (isa<PointerType>(ToQTy)) { 00128 bool CanConvert = false; 00129 OverloadFixItKind FixKind = OFIK_TakeAddress; 00130 00131 // Only suggest taking address of L-values. 00132 if (!Expr->isLValue() || Expr->getObjectKind() != OK_Ordinary) 00133 return false; 00134 00135 CanConvert = CompareTypes(S.Context.getPointerType(FromQTy), ToQTy, 00136 S, Begin, VK_RValue); 00137 if (CanConvert) { 00138 00139 if (const UnaryOperator *UO = dyn_cast<UnaryOperator>(Expr)) { 00140 if (UO->getOpcode() == UO_Deref) { 00141 FixKind = OFIK_RemoveDereference; 00142 Hints.push_back(FixItHint::CreateRemoval( 00143 CharSourceRange::getTokenRange(Begin, Begin))); 00144 } 00145 } else if (NeedParen) { 00146 Hints.push_back(FixItHint::CreateInsertion(Begin, "&(")); 00147 Hints.push_back(FixItHint::CreateInsertion(End, ")")); 00148 } else { 00149 Hints.push_back(FixItHint::CreateInsertion(Begin, "&")); 00150 } 00151 00152 NumConversionsFixed++; 00153 if (NumConversionsFixed == 1) 00154 Kind = FixKind; 00155 return true; 00156 } 00157 } 00158 00159 return false; 00160 } 00161 00162 static bool isMacroDefined(const Sema &S, StringRef Name) { 00163 return S.PP.getMacroInfo(&S.getASTContext().Idents.get(Name)); 00164 } 00165 00166 static std::string getScalarZeroExpressionForType(const Type& T, const Sema& S) { 00167 assert(T.isScalarType() && "use scalar types only"); 00168 // Suggest "0" for non-enumeration scalar types, unless we can find a 00169 // better initializer. 00170 if (T.isEnumeralType()) 00171 return std::string(); 00172 if ((T.isObjCObjectPointerType() || T.isBlockPointerType()) && 00173 isMacroDefined(S, "nil")) 00174 return "nil"; 00175 if (T.isRealFloatingType()) 00176 return "0.0"; 00177 if (T.isBooleanType() && S.LangOpts.CPlusPlus) 00178 return "false"; 00179 if (T.isPointerType() || T.isMemberPointerType()) { 00180 if (S.LangOpts.CPlusPlus0x) 00181 return "nullptr"; 00182 if (isMacroDefined(S, "NULL")) 00183 return "NULL"; 00184 } 00185 if (T.isCharType()) 00186 return "'\\0'"; 00187 if (T.isWideCharType()) 00188 return "L'\\0'"; 00189 if (T.isChar16Type()) 00190 return "u'\\0'"; 00191 if (T.isChar32Type()) 00192 return "U'\\0'"; 00193 return "0"; 00194 } 00195 00196 std::string Sema::getFixItZeroInitializerForType(QualType T) const { 00197 if (T->isScalarType()) { 00198 std::string s = getScalarZeroExpressionForType(*T, *this); 00199 if (!s.empty()) 00200 s = " = " + s; 00201 return s; 00202 } 00203 00204 const CXXRecordDecl *RD = T->getAsCXXRecordDecl(); 00205 if (!RD || !RD->hasDefinition()) 00206 return std::string(); 00207 if (LangOpts.CPlusPlus0x && !RD->hasUserProvidedDefaultConstructor()) 00208 return "{}"; 00209 if (RD->isAggregate()) 00210 return " = {}"; 00211 return std::string(); 00212 } 00213 00214 std::string Sema::getFixItZeroLiteralForType(QualType T) const { 00215 return getScalarZeroExpressionForType(*T, *this); 00216 }