clang API Documentation

SemaFixItUtils.cpp
Go to the documentation of this file.
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 }