xref: /freebsd/contrib/llvm-project/clang/lib/Sema/SemaFixItUtils.cpp (revision bdd1243df58e60e85101c09001d9812a789b6bc4)
10b57cec5SDimitry Andric //===--- SemaFixItUtils.cpp - Sema FixIts ---------------------------------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric //
90b57cec5SDimitry Andric //  This file defines helper classes for generation of Sema FixItHints.
100b57cec5SDimitry Andric //
110b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
120b57cec5SDimitry Andric 
130b57cec5SDimitry Andric #include "clang/AST/ASTContext.h"
140b57cec5SDimitry Andric #include "clang/AST/ExprCXX.h"
150b57cec5SDimitry Andric #include "clang/AST/ExprObjC.h"
160b57cec5SDimitry Andric #include "clang/Lex/Preprocessor.h"
170b57cec5SDimitry Andric #include "clang/Sema/Sema.h"
180b57cec5SDimitry Andric #include "clang/Sema/SemaFixItUtils.h"
190b57cec5SDimitry Andric 
200b57cec5SDimitry Andric using namespace clang;
210b57cec5SDimitry Andric 
compareTypesSimple(CanQualType From,CanQualType To,Sema & S,SourceLocation Loc,ExprValueKind FromVK)220b57cec5SDimitry Andric bool ConversionFixItGenerator::compareTypesSimple(CanQualType From,
230b57cec5SDimitry Andric                                                   CanQualType To,
240b57cec5SDimitry Andric                                                   Sema &S,
250b57cec5SDimitry Andric                                                   SourceLocation Loc,
260b57cec5SDimitry Andric                                                   ExprValueKind FromVK) {
270b57cec5SDimitry Andric   if (!To.isAtLeastAsQualifiedAs(From))
280b57cec5SDimitry Andric     return false;
290b57cec5SDimitry Andric 
300b57cec5SDimitry Andric   From = From.getNonReferenceType();
310b57cec5SDimitry Andric   To = To.getNonReferenceType();
320b57cec5SDimitry Andric 
330b57cec5SDimitry Andric   // If both are pointer types, work with the pointee types.
340b57cec5SDimitry Andric   if (isa<PointerType>(From) && isa<PointerType>(To)) {
350b57cec5SDimitry Andric     From = S.Context.getCanonicalType(
360b57cec5SDimitry Andric         (cast<PointerType>(From))->getPointeeType());
370b57cec5SDimitry Andric     To = S.Context.getCanonicalType(
380b57cec5SDimitry Andric         (cast<PointerType>(To))->getPointeeType());
390b57cec5SDimitry Andric   }
400b57cec5SDimitry Andric 
410b57cec5SDimitry Andric   const CanQualType FromUnq = From.getUnqualifiedType();
420b57cec5SDimitry Andric   const CanQualType ToUnq = To.getUnqualifiedType();
430b57cec5SDimitry Andric 
440b57cec5SDimitry Andric   if ((FromUnq == ToUnq || (S.IsDerivedFrom(Loc, FromUnq, ToUnq)) ) &&
450b57cec5SDimitry Andric       To.isAtLeastAsQualifiedAs(From))
460b57cec5SDimitry Andric     return true;
470b57cec5SDimitry Andric   return false;
480b57cec5SDimitry Andric }
490b57cec5SDimitry Andric 
tryToFixConversion(const Expr * FullExpr,const QualType FromTy,const QualType ToTy,Sema & S)500b57cec5SDimitry Andric bool ConversionFixItGenerator::tryToFixConversion(const Expr *FullExpr,
510b57cec5SDimitry Andric                                                   const QualType FromTy,
520b57cec5SDimitry Andric                                                   const QualType ToTy,
530b57cec5SDimitry Andric                                                   Sema &S) {
540b57cec5SDimitry Andric   if (!FullExpr)
550b57cec5SDimitry Andric     return false;
560b57cec5SDimitry Andric 
570b57cec5SDimitry Andric   const CanQualType FromQTy = S.Context.getCanonicalType(FromTy);
580b57cec5SDimitry Andric   const CanQualType ToQTy = S.Context.getCanonicalType(ToTy);
590b57cec5SDimitry Andric   const SourceLocation Begin = FullExpr->getSourceRange().getBegin();
600b57cec5SDimitry Andric   const SourceLocation End = S.getLocForEndOfToken(FullExpr->getSourceRange()
610b57cec5SDimitry Andric                                                    .getEnd());
620b57cec5SDimitry Andric 
630b57cec5SDimitry Andric   // Strip the implicit casts - those are implied by the compiler, not the
640b57cec5SDimitry Andric   // original source code.
650b57cec5SDimitry Andric   const Expr* Expr = FullExpr->IgnoreImpCasts();
660b57cec5SDimitry Andric 
670b57cec5SDimitry Andric   bool NeedParen = true;
680b57cec5SDimitry Andric   if (isa<ArraySubscriptExpr>(Expr) ||
690b57cec5SDimitry Andric       isa<CallExpr>(Expr) ||
700b57cec5SDimitry Andric       isa<DeclRefExpr>(Expr) ||
710b57cec5SDimitry Andric       isa<CastExpr>(Expr) ||
720b57cec5SDimitry Andric       isa<CXXNewExpr>(Expr) ||
730b57cec5SDimitry Andric       isa<CXXConstructExpr>(Expr) ||
740b57cec5SDimitry Andric       isa<CXXDeleteExpr>(Expr) ||
750b57cec5SDimitry Andric       isa<CXXNoexceptExpr>(Expr) ||
760b57cec5SDimitry Andric       isa<CXXPseudoDestructorExpr>(Expr) ||
770b57cec5SDimitry Andric       isa<CXXScalarValueInitExpr>(Expr) ||
780b57cec5SDimitry Andric       isa<CXXThisExpr>(Expr) ||
790b57cec5SDimitry Andric       isa<CXXTypeidExpr>(Expr) ||
800b57cec5SDimitry Andric       isa<CXXUnresolvedConstructExpr>(Expr) ||
810b57cec5SDimitry Andric       isa<ObjCMessageExpr>(Expr) ||
820b57cec5SDimitry Andric       isa<ObjCPropertyRefExpr>(Expr) ||
830b57cec5SDimitry Andric       isa<ObjCProtocolExpr>(Expr) ||
840b57cec5SDimitry Andric       isa<MemberExpr>(Expr) ||
850b57cec5SDimitry Andric       isa<ParenExpr>(FullExpr) ||
860b57cec5SDimitry Andric       isa<ParenListExpr>(Expr) ||
870b57cec5SDimitry Andric       isa<SizeOfPackExpr>(Expr) ||
880b57cec5SDimitry Andric       isa<UnaryOperator>(Expr))
890b57cec5SDimitry Andric     NeedParen = false;
900b57cec5SDimitry Andric 
910b57cec5SDimitry Andric   // Check if the argument needs to be dereferenced:
920b57cec5SDimitry Andric   //   (type * -> type) or (type * -> type &).
930b57cec5SDimitry Andric   if (const PointerType *FromPtrTy = dyn_cast<PointerType>(FromQTy)) {
940b57cec5SDimitry Andric     OverloadFixItKind FixKind = OFIK_Dereference;
950b57cec5SDimitry Andric 
960b57cec5SDimitry Andric     bool CanConvert = CompareTypes(
970b57cec5SDimitry Andric       S.Context.getCanonicalType(FromPtrTy->getPointeeType()), ToQTy,
980b57cec5SDimitry Andric                                  S, Begin, VK_LValue);
990b57cec5SDimitry Andric     if (CanConvert) {
1000b57cec5SDimitry Andric       // Do not suggest dereferencing a Null pointer.
1010b57cec5SDimitry Andric       if (Expr->IgnoreParenCasts()->
1020b57cec5SDimitry Andric           isNullPointerConstant(S.Context, Expr::NPC_ValueDependentIsNotNull))
1030b57cec5SDimitry Andric         return false;
1040b57cec5SDimitry Andric 
1050b57cec5SDimitry Andric       if (const UnaryOperator *UO = dyn_cast<UnaryOperator>(Expr)) {
1060b57cec5SDimitry Andric         if (UO->getOpcode() == UO_AddrOf) {
1070b57cec5SDimitry Andric           FixKind = OFIK_RemoveTakeAddress;
1080b57cec5SDimitry Andric           Hints.push_back(FixItHint::CreateRemoval(
1090b57cec5SDimitry Andric                             CharSourceRange::getTokenRange(Begin, Begin)));
1100b57cec5SDimitry Andric         }
1110b57cec5SDimitry Andric       } else if (NeedParen) {
1120b57cec5SDimitry Andric         Hints.push_back(FixItHint::CreateInsertion(Begin, "*("));
1130b57cec5SDimitry Andric         Hints.push_back(FixItHint::CreateInsertion(End, ")"));
1140b57cec5SDimitry Andric       } else {
1150b57cec5SDimitry Andric         Hints.push_back(FixItHint::CreateInsertion(Begin, "*"));
1160b57cec5SDimitry Andric       }
1170b57cec5SDimitry Andric 
1180b57cec5SDimitry Andric       NumConversionsFixed++;
1190b57cec5SDimitry Andric       if (NumConversionsFixed == 1)
1200b57cec5SDimitry Andric         Kind = FixKind;
1210b57cec5SDimitry Andric       return true;
1220b57cec5SDimitry Andric     }
1230b57cec5SDimitry Andric   }
1240b57cec5SDimitry Andric 
1250b57cec5SDimitry Andric   // Check if the pointer to the argument needs to be passed:
1260b57cec5SDimitry Andric   //   (type -> type *) or (type & -> type *).
127*bdd1243dSDimitry Andric   if (const auto *ToPtrTy = dyn_cast<PointerType>(ToQTy)) {
1280b57cec5SDimitry Andric     bool CanConvert = false;
1290b57cec5SDimitry Andric     OverloadFixItKind FixKind = OFIK_TakeAddress;
1300b57cec5SDimitry Andric 
1310b57cec5SDimitry Andric     // Only suggest taking address of L-values.
1320b57cec5SDimitry Andric     if (!Expr->isLValue() || Expr->getObjectKind() != OK_Ordinary)
1330b57cec5SDimitry Andric       return false;
1340b57cec5SDimitry Andric 
135*bdd1243dSDimitry Andric     // Do no take address of const pointer to get void*
136*bdd1243dSDimitry Andric     if (isa<PointerType>(FromQTy) && ToPtrTy->isVoidPointerType())
137*bdd1243dSDimitry Andric       return false;
138*bdd1243dSDimitry Andric 
139fe6060f1SDimitry Andric     CanConvert = CompareTypes(S.Context.getPointerType(FromQTy), ToQTy, S,
140fe6060f1SDimitry Andric                               Begin, VK_PRValue);
1410b57cec5SDimitry Andric     if (CanConvert) {
1420b57cec5SDimitry Andric 
1430b57cec5SDimitry Andric       if (const UnaryOperator *UO = dyn_cast<UnaryOperator>(Expr)) {
1440b57cec5SDimitry Andric         if (UO->getOpcode() == UO_Deref) {
1450b57cec5SDimitry Andric           FixKind = OFIK_RemoveDereference;
1460b57cec5SDimitry Andric           Hints.push_back(FixItHint::CreateRemoval(
1470b57cec5SDimitry Andric                             CharSourceRange::getTokenRange(Begin, Begin)));
1480b57cec5SDimitry Andric         }
1490b57cec5SDimitry Andric       } else if (NeedParen) {
1500b57cec5SDimitry Andric         Hints.push_back(FixItHint::CreateInsertion(Begin, "&("));
1510b57cec5SDimitry Andric         Hints.push_back(FixItHint::CreateInsertion(End, ")"));
1520b57cec5SDimitry Andric       } else {
1530b57cec5SDimitry Andric         Hints.push_back(FixItHint::CreateInsertion(Begin, "&"));
1540b57cec5SDimitry Andric       }
1550b57cec5SDimitry Andric 
1560b57cec5SDimitry Andric       NumConversionsFixed++;
1570b57cec5SDimitry Andric       if (NumConversionsFixed == 1)
1580b57cec5SDimitry Andric         Kind = FixKind;
1590b57cec5SDimitry Andric       return true;
1600b57cec5SDimitry Andric     }
1610b57cec5SDimitry Andric   }
1620b57cec5SDimitry Andric 
1630b57cec5SDimitry Andric   return false;
1640b57cec5SDimitry Andric }
1650b57cec5SDimitry Andric 
isMacroDefined(const Sema & S,SourceLocation Loc,StringRef Name)1660b57cec5SDimitry Andric static bool isMacroDefined(const Sema &S, SourceLocation Loc, StringRef Name) {
1670b57cec5SDimitry Andric   return (bool)S.PP.getMacroDefinitionAtLoc(&S.getASTContext().Idents.get(Name),
1680b57cec5SDimitry Andric                                             Loc);
1690b57cec5SDimitry Andric }
1700b57cec5SDimitry Andric 
getScalarZeroExpressionForType(const Type & T,SourceLocation Loc,const Sema & S)1710b57cec5SDimitry Andric static std::string getScalarZeroExpressionForType(
1720b57cec5SDimitry Andric     const Type &T, SourceLocation Loc, const Sema &S) {
1730b57cec5SDimitry Andric   assert(T.isScalarType() && "use scalar types only");
1740b57cec5SDimitry Andric   // Suggest "0" for non-enumeration scalar types, unless we can find a
1750b57cec5SDimitry Andric   // better initializer.
1760b57cec5SDimitry Andric   if (T.isEnumeralType())
1770b57cec5SDimitry Andric     return std::string();
1780b57cec5SDimitry Andric   if ((T.isObjCObjectPointerType() || T.isBlockPointerType()) &&
1790b57cec5SDimitry Andric       isMacroDefined(S, Loc, "nil"))
1800b57cec5SDimitry Andric     return "nil";
1810b57cec5SDimitry Andric   if (T.isRealFloatingType())
1820b57cec5SDimitry Andric     return "0.0";
1830b57cec5SDimitry Andric   if (T.isBooleanType() &&
1840b57cec5SDimitry Andric       (S.LangOpts.CPlusPlus || isMacroDefined(S, Loc, "false")))
1850b57cec5SDimitry Andric     return "false";
1860b57cec5SDimitry Andric   if (T.isPointerType() || T.isMemberPointerType()) {
1870b57cec5SDimitry Andric     if (S.LangOpts.CPlusPlus11)
1880b57cec5SDimitry Andric       return "nullptr";
1890b57cec5SDimitry Andric     if (isMacroDefined(S, Loc, "NULL"))
1900b57cec5SDimitry Andric       return "NULL";
1910b57cec5SDimitry Andric   }
1920b57cec5SDimitry Andric   if (T.isCharType())
1930b57cec5SDimitry Andric     return "'\\0'";
1940b57cec5SDimitry Andric   if (T.isWideCharType())
1950b57cec5SDimitry Andric     return "L'\\0'";
1960b57cec5SDimitry Andric   if (T.isChar16Type())
1970b57cec5SDimitry Andric     return "u'\\0'";
1980b57cec5SDimitry Andric   if (T.isChar32Type())
1990b57cec5SDimitry Andric     return "U'\\0'";
2000b57cec5SDimitry Andric   return "0";
2010b57cec5SDimitry Andric }
2020b57cec5SDimitry Andric 
2030b57cec5SDimitry Andric std::string
getFixItZeroInitializerForType(QualType T,SourceLocation Loc) const2040b57cec5SDimitry Andric Sema::getFixItZeroInitializerForType(QualType T, SourceLocation Loc) const {
2050b57cec5SDimitry Andric   if (T->isScalarType()) {
2060b57cec5SDimitry Andric     std::string s = getScalarZeroExpressionForType(*T, Loc, *this);
2070b57cec5SDimitry Andric     if (!s.empty())
2080b57cec5SDimitry Andric       s = " = " + s;
2090b57cec5SDimitry Andric     return s;
2100b57cec5SDimitry Andric   }
2110b57cec5SDimitry Andric 
2120b57cec5SDimitry Andric   const CXXRecordDecl *RD = T->getAsCXXRecordDecl();
2130b57cec5SDimitry Andric   if (!RD || !RD->hasDefinition())
2140b57cec5SDimitry Andric     return std::string();
2150b57cec5SDimitry Andric   if (LangOpts.CPlusPlus11 && !RD->hasUserProvidedDefaultConstructor())
2160b57cec5SDimitry Andric     return "{}";
2170b57cec5SDimitry Andric   if (RD->isAggregate())
2180b57cec5SDimitry Andric     return " = {}";
2190b57cec5SDimitry Andric   return std::string();
2200b57cec5SDimitry Andric }
2210b57cec5SDimitry Andric 
2220b57cec5SDimitry Andric std::string
getFixItZeroLiteralForType(QualType T,SourceLocation Loc) const2230b57cec5SDimitry Andric Sema::getFixItZeroLiteralForType(QualType T, SourceLocation Loc) const {
2240b57cec5SDimitry Andric   return getScalarZeroExpressionForType(*T, Loc, *this);
2250b57cec5SDimitry Andric }
226