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