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/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 }