brintos

brintos / llvm-project-archived public Read only

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