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