Clang Project

clang_source_code/lib/Sema/SemaFixItUtils.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-exception
6//
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))
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(LocFromUnqToUnq)) ) &&
45      To.isAtLeastAsQualifiedAs(From))
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 the
64  // original source code.
65  const ExprExpr = 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                                 SBeginVK_LValue);
99    if (CanConvert) {
100      // Do not suggest dereferencing a Null pointer.
101      if (Expr->IgnoreParenCasts()->
102          isNullPointerConstant(S.ContextExpr::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(BeginBegin)));
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 (isa<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    CanConvert = CompareTypes(S.Context.getPointerType(FromQTy), ToQTy,
136                              SBeginVK_RValue);
137    if (CanConvert) {
138
139      if (const UnaryOperator *UO = dyn_cast<UnaryOperator>(Expr)) {
140        if (UO->getOpcode() == UO_Deref) {
141          FixKind = OFIK_RemoveDereference;
142          Hints.push_back(FixItHint::CreateRemoval(
143                            CharSourceRange::getTokenRange(BeginBegin)));
144        }
145      } else if (NeedParen) {
146        Hints.push_back(FixItHint::CreateInsertion(Begin"&("));
147        Hints.push_back(FixItHint::CreateInsertion(End")"));
148      } else {
149        Hints.push_back(FixItHint::CreateInsertion(Begin"&"));
150      }
151
152      NumConversionsFixed++;
153      if (NumConversionsFixed == 1)
154        Kind = FixKind;
155      return true;
156    }
157  }
158
159  return false;
160}
161
162static bool isMacroDefined(const Sema &SSourceLocation LocStringRef Name) {
163  return (bool)S.PP.getMacroDefinitionAtLoc(&S.getASTContext().Idents.get(Name),
164                                            Loc);
165}
166
167static std::string getScalarZeroExpressionForType(
168    const Type &TSourceLocation Locconst Sema &S) {
169   (0) . __assert_fail ("T.isScalarType() && \"use scalar types only\"", "/home/seafit/code_projects/clang_source/clang/lib/Sema/SemaFixItUtils.cpp", 169, __PRETTY_FUNCTION__))" file_link="../../../include/assert.h.html#88" macro="true">assert(T.isScalarType() && "use scalar types only");
170  // Suggest "0" for non-enumeration scalar types, unless we can find a
171  // better initializer.
172  if (T.isEnumeralType())
173    return std::string();
174  if ((T.isObjCObjectPointerType() || T.isBlockPointerType()) &&
175      isMacroDefined(SLoc"nil"))
176    return "nil";
177  if (T.isRealFloatingType())
178    return "0.0";
179  if (T.isBooleanType() &&
180      (S.LangOpts.CPlusPlus || isMacroDefined(SLoc"false")))
181    return "false";
182  if (T.isPointerType() || T.isMemberPointerType()) {
183    if (S.LangOpts.CPlusPlus11)
184      return "nullptr";
185    if (isMacroDefined(SLoc"NULL"))
186      return "NULL";
187  }
188  if (T.isCharType())
189    return "'\\0'";
190  if (T.isWideCharType())
191    return "L'\\0'";
192  if (T.isChar16Type())
193    return "u'\\0'";
194  if (T.isChar32Type())
195    return "U'\\0'";
196  return "0";
197}
198
199std::string
200Sema::getFixItZeroInitializerForType(QualType TSourceLocation Locconst {
201  if (T->isScalarType()) {
202    std::string s = getScalarZeroExpressionForType(*TLoc, *this);
203    if (!s.empty())
204      s = " = " + s;
205    return s;
206  }
207
208  const CXXRecordDecl *RD = T->getAsCXXRecordDecl();
209  if (!RD || !RD->hasDefinition())
210    return std::string();
211  if (LangOpts.CPlusPlus11 && !RD->hasUserProvidedDefaultConstructor())
212    return "{}";
213  if (RD->isAggregate())
214    return " = {}";
215  return std::string();
216}
217
218std::string
219Sema::getFixItZeroLiteralForType(QualType TSourceLocation Locconst {
220  return getScalarZeroExpressionForType(*TLoc, *this);
221}
222
clang::ConversionFixItGenerator::compareTypesSimple
clang::ConversionFixItGenerator::tryToFixConversion
clang::Sema::getFixItZeroInitializerForType
clang::Sema::getFixItZeroLiteralForType