Home | History | Annotate | Download | only in Sema
      1 //===--- SemaFixItUtils.cpp - Sema FixIts ---------------------------------===//
      2 //
      3 //                     The LLVM Compiler Infrastructure
      4 //
      5 // This file is distributed under the University of Illinois Open Source
      6 // License. See LICENSE.TXT for details.
      7 //
      8 //===----------------------------------------------------------------------===//
      9 //
     10 //  This file defines helper classes for generation of Sema FixItHints.
     11 //
     12 //===----------------------------------------------------------------------===//
     13 
     14 #include "clang/AST/ASTContext.h"
     15 #include "clang/AST/ExprCXX.h"
     16 #include "clang/AST/ExprObjC.h"
     17 #include "clang/Lex/Preprocessor.h"
     18 #include "clang/Sema/Sema.h"
     19 #include "clang/Sema/SemaFixItUtils.h"
     20 
     21 using namespace clang;
     22 
     23 bool ConversionFixItGenerator::compareTypesSimple(CanQualType From,
     24                                                   CanQualType To,
     25                                                   Sema &S,
     26                                                   SourceLocation Loc,
     27                                                   ExprValueKind FromVK) {
     28   if (!To.isAtLeastAsQualifiedAs(From))
     29     return false;
     30 
     31   From = From.getNonReferenceType();
     32   To = To.getNonReferenceType();
     33 
     34   // If both are pointer types, work with the pointee types.
     35   if (isa<PointerType>(From) && isa<PointerType>(To)) {
     36     From = S.Context.getCanonicalType(
     37         (cast<PointerType>(From))->getPointeeType());
     38     To = S.Context.getCanonicalType(
     39         (cast<PointerType>(To))->getPointeeType());
     40   }
     41 
     42   const CanQualType FromUnq = From.getUnqualifiedType();
     43   const CanQualType ToUnq = To.getUnqualifiedType();
     44 
     45   if ((FromUnq == ToUnq || (S.IsDerivedFrom(Loc, FromUnq, ToUnq)) ) &&
     46       To.isAtLeastAsQualifiedAs(From))
     47     return true;
     48   return false;
     49 }
     50 
     51 bool ConversionFixItGenerator::tryToFixConversion(const Expr *FullExpr,
     52                                                   const QualType FromTy,
     53                                                   const QualType ToTy,
     54                                                   Sema &S) {
     55   if (!FullExpr)
     56     return false;
     57 
     58   const CanQualType FromQTy = S.Context.getCanonicalType(FromTy);
     59   const CanQualType ToQTy = S.Context.getCanonicalType(ToTy);
     60   const SourceLocation Begin = FullExpr->getSourceRange().getBegin();
     61   const SourceLocation End = S.getLocForEndOfToken(FullExpr->getSourceRange()
     62                                                    .getEnd());
     63 
     64   // Strip the implicit casts - those are implied by the compiler, not the
     65   // original source code.
     66   const Expr* Expr = FullExpr->IgnoreImpCasts();
     67 
     68   bool NeedParen = true;
     69   if (isa<ArraySubscriptExpr>(Expr) ||
     70       isa<CallExpr>(Expr) ||
     71       isa<DeclRefExpr>(Expr) ||
     72       isa<CastExpr>(Expr) ||
     73       isa<CXXNewExpr>(Expr) ||
     74       isa<CXXConstructExpr>(Expr) ||
     75       isa<CXXDeleteExpr>(Expr) ||
     76       isa<CXXNoexceptExpr>(Expr) ||
     77       isa<CXXPseudoDestructorExpr>(Expr) ||
     78       isa<CXXScalarValueInitExpr>(Expr) ||
     79       isa<CXXThisExpr>(Expr) ||
     80       isa<CXXTypeidExpr>(Expr) ||
     81       isa<CXXUnresolvedConstructExpr>(Expr) ||
     82       isa<ObjCMessageExpr>(Expr) ||
     83       isa<ObjCPropertyRefExpr>(Expr) ||
     84       isa<ObjCProtocolExpr>(Expr) ||
     85       isa<MemberExpr>(Expr) ||
     86       isa<ParenExpr>(FullExpr) ||
     87       isa<ParenListExpr>(Expr) ||
     88       isa<SizeOfPackExpr>(Expr) ||
     89       isa<UnaryOperator>(Expr))
     90     NeedParen = false;
     91 
     92   // Check if the argument needs to be dereferenced:
     93   //   (type * -> type) or (type * -> type &).
     94   if (const PointerType *FromPtrTy = dyn_cast<PointerType>(FromQTy)) {
     95     OverloadFixItKind FixKind = OFIK_Dereference;
     96 
     97     bool CanConvert = CompareTypes(
     98       S.Context.getCanonicalType(FromPtrTy->getPointeeType()), ToQTy,
     99                                  S, Begin, VK_LValue);
    100     if (CanConvert) {
    101       // Do not suggest dereferencing a Null pointer.
    102       if (Expr->IgnoreParenCasts()->
    103           isNullPointerConstant(S.Context, Expr::NPC_ValueDependentIsNotNull))
    104         return false;
    105 
    106       if (const UnaryOperator *UO = dyn_cast<UnaryOperator>(Expr)) {
    107         if (UO->getOpcode() == UO_AddrOf) {
    108           FixKind = OFIK_RemoveTakeAddress;
    109           Hints.push_back(FixItHint::CreateRemoval(
    110                             CharSourceRange::getTokenRange(Begin, Begin)));
    111         }
    112       } else if (NeedParen) {
    113         Hints.push_back(FixItHint::CreateInsertion(Begin, "*("));
    114         Hints.push_back(FixItHint::CreateInsertion(End, ")"));
    115       } else {
    116         Hints.push_back(FixItHint::CreateInsertion(Begin, "*"));
    117       }
    118 
    119       NumConversionsFixed++;
    120       if (NumConversionsFixed == 1)
    121         Kind = FixKind;
    122       return true;
    123     }
    124   }
    125 
    126   // Check if the pointer to the argument needs to be passed:
    127   //   (type -> type *) or (type & -> type *).
    128   if (isa<PointerType>(ToQTy)) {
    129     bool CanConvert = false;
    130     OverloadFixItKind FixKind = OFIK_TakeAddress;
    131 
    132     // Only suggest taking address of L-values.
    133     if (!Expr->isLValue() || Expr->getObjectKind() != OK_Ordinary)
    134       return false;
    135 
    136     CanConvert = CompareTypes(S.Context.getPointerType(FromQTy), ToQTy,
    137                               S, Begin, VK_RValue);
    138     if (CanConvert) {
    139 
    140       if (const UnaryOperator *UO = dyn_cast<UnaryOperator>(Expr)) {
    141         if (UO->getOpcode() == UO_Deref) {
    142           FixKind = OFIK_RemoveDereference;
    143           Hints.push_back(FixItHint::CreateRemoval(
    144                             CharSourceRange::getTokenRange(Begin, Begin)));
    145         }
    146       } else if (NeedParen) {
    147         Hints.push_back(FixItHint::CreateInsertion(Begin, "&("));
    148         Hints.push_back(FixItHint::CreateInsertion(End, ")"));
    149       } else {
    150         Hints.push_back(FixItHint::CreateInsertion(Begin, "&"));
    151       }
    152 
    153       NumConversionsFixed++;
    154       if (NumConversionsFixed == 1)
    155         Kind = FixKind;
    156       return true;
    157     }
    158   }
    159 
    160   return false;
    161 }
    162 
    163 static bool isMacroDefined(const Sema &S, SourceLocation Loc, StringRef Name) {
    164   return (bool)S.PP.getMacroDefinitionAtLoc(&S.getASTContext().Idents.get(Name),
    165                                             Loc);
    166 }
    167 
    168 static std::string getScalarZeroExpressionForType(
    169     const Type &T, SourceLocation Loc, const Sema &S) {
    170   assert(T.isScalarType() && "use scalar types only");
    171   // Suggest "0" for non-enumeration scalar types, unless we can find a
    172   // better initializer.
    173   if (T.isEnumeralType())
    174     return std::string();
    175   if ((T.isObjCObjectPointerType() || T.isBlockPointerType()) &&
    176       isMacroDefined(S, Loc, "nil"))
    177     return "nil";
    178   if (T.isRealFloatingType())
    179     return "0.0";
    180   if (T.isBooleanType() &&
    181       (S.LangOpts.CPlusPlus || isMacroDefined(S, Loc, "false")))
    182     return "false";
    183   if (T.isPointerType() || T.isMemberPointerType()) {
    184     if (S.LangOpts.CPlusPlus11)
    185       return "nullptr";
    186     if (isMacroDefined(S, Loc, "NULL"))
    187       return "NULL";
    188   }
    189   if (T.isCharType())
    190     return "'\\0'";
    191   if (T.isWideCharType())
    192     return "L'\\0'";
    193   if (T.isChar16Type())
    194     return "u'\\0'";
    195   if (T.isChar32Type())
    196     return "U'\\0'";
    197   return "0";
    198 }
    199 
    200 std::string
    201 Sema::getFixItZeroInitializerForType(QualType T, SourceLocation Loc) const {
    202   if (T->isScalarType()) {
    203     std::string s = getScalarZeroExpressionForType(*T, Loc, *this);
    204     if (!s.empty())
    205       s = " = " + s;
    206     return s;
    207   }
    208 
    209   const CXXRecordDecl *RD = T->getAsCXXRecordDecl();
    210   if (!RD || !RD->hasDefinition())
    211     return std::string();
    212   if (LangOpts.CPlusPlus11 && !RD->hasUserProvidedDefaultConstructor())
    213     return "{}";
    214   if (RD->isAggregate())
    215     return " = {}";
    216   return std::string();
    217 }
    218 
    219 std::string
    220 Sema::getFixItZeroLiteralForType(QualType T, SourceLocation Loc) const {
    221   return getScalarZeroExpressionForType(*T, Loc, *this);
    222 }
    223