clang 19.0.0git
SemaFixItUtils.cpp
Go to the documentation of this file.
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
14#include "clang/AST/ExprCXX.h"
15#include "clang/AST/ExprObjC.h"
17#include "clang/Sema/Sema.h"
19
20using namespace clang;
21
23 CanQualType To,
24 Sema &S,
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)) {
36 (cast<PointerType>(From))->getPointeeType());
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)) ) &&
46 return true;
47 return false;
48}
49
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);
61 .getEnd());
62
63 // Strip the implicit casts - those are implied by the compiler, not the
64 // 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)) {
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;
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
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;
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,
141 if (CanConvert) {
142
143 if (const UnaryOperator *UO = dyn_cast<UnaryOperator>(Expr)) {
144 if (UO->getOpcode() == UO_Deref) {
145 FixKind = OFIK_RemoveDereference;
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
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
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 a
175 // better initializer.
176 if (T.isEnumeralType())
177 return std::string();
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";
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::string
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::string
224 return getScalarZeroExpressionForType(*T, Loc, *this);
225}
Defines the clang::ASTContext interface.
Defines the clang::Expr interface and subclasses for C++ expressions.
Defines the clang::Preprocessor interface.
static std::string getScalarZeroExpressionForType(const Type &T, SourceLocation Loc, const Sema &S)
static bool isMacroDefined(const Sema &S, SourceLocation Loc, StringRef Name)
SourceLocation Begin
__device__ __2f16 float __ockl_bool s
CanQualType getCanonicalType(QualType T) const
Return the canonical (structural) type corresponding to the specified potentially non-canonical type ...
Definition: ASTContext.h:2563
QualType getPointerType(QualType T) const
Return the uniqued reference to the type for a pointer to the specified type.
IdentifierTable & Idents
Definition: ASTContext.h:644
Represents a C++ struct/union/class.
Definition: DeclCXX.h:258
bool isAggregate() const
Determine whether this class is an aggregate (C++ [dcl.init.aggr]), which is a class with no user-dec...
Definition: DeclCXX.h:1146
bool hasUserProvidedDefaultConstructor() const
Whether this class has a user-provided default constructor per C++11.
Definition: DeclCXX.h:796
bool hasDefinition() const
Definition: DeclCXX.h:571
CanQual< Type > getNonReferenceType() const
If the canonical type is a reference type, returns the type that it refers to; otherwise,...
CanQual< T > getUnqualifiedType() const
Retrieve the unqualified form of this type.
bool isAtLeastAsQualifiedAs(CanQual< T > Other) const
Determines whether this canonical type is at least as qualified as the Other canonical type.
static CharSourceRange getTokenRange(SourceRange R)
This represents one expression.
Definition: Expr.h:110
Expr * IgnoreParenCasts() LLVM_READONLY
Skip past any parentheses and casts which might surround this expression until reaching a fixed point...
Definition: Expr.cpp:3064
bool isLValue() const
isLValue - True if this expression is an "l-value" according to the rules of the current language.
Definition: Expr.h:277
@ NPC_ValueDependentIsNotNull
Specifies that a value-dependent expression should be considered to never be a null pointer constant.
Definition: Expr.h:825
ExprObjectKind getObjectKind() const
getObjectKind - The object kind that this expression produces.
Definition: Expr.h:444
Expr * IgnoreImpCasts() LLVM_READONLY
Skip past any implicit casts which might surround this expression until reaching a fixed point.
Definition: Expr.cpp:3039
static FixItHint CreateRemoval(CharSourceRange RemoveRange)
Create a code modification hint that removes the given source range.
Definition: Diagnostic.h:123
static FixItHint CreateInsertion(SourceLocation InsertionLoc, StringRef Code, bool BeforePreviousInsertions=false)
Create a code modification hint that inserts the given code string at a specific location.
Definition: Diagnostic.h:97
FullExpr - Represents a "full-expression" node.
Definition: Expr.h:1039
IdentifierInfo & get(StringRef Name)
Return the identifier token info for the specified named identifier.
PointerType - C99 6.7.5.1 - Pointer Declarators.
Definition: Type.h:2929
MacroDefinition getMacroDefinitionAtLoc(const IdentifierInfo *II, SourceLocation Loc)
A (possibly-)qualified type.
Definition: Type.h:738
Sema - This implements semantic analysis and AST building for C.
Definition: Sema.h:457
ASTContext & Context
Definition: Sema.h:858
std::string getFixItZeroLiteralForType(QualType T, SourceLocation Loc) const
ASTContext & getASTContext() const
Definition: Sema.h:527
std::string getFixItZeroInitializerForType(QualType T, SourceLocation Loc) const
Get a string to suggest for zero-initialization of a type.
SourceLocation getLocForEndOfToken(SourceLocation Loc, unsigned Offset=0)
Calls Lexer::getLocForEndOfToken()
Definition: Sema.cpp:63
Preprocessor & PP
Definition: Sema.h:857
const LangOptions & LangOpts
Definition: Sema.h:856
bool IsDerivedFrom(SourceLocation Loc, QualType Derived, QualType Base)
Determine whether the type Derived is a C++ class that is derived from the type Base.
Encodes a location in the source.
SourceLocation getEnd() const
SourceLocation getBegin() const
SourceRange getSourceRange() const LLVM_READONLY
SourceLocation tokens are not useful in isolation - they are low level value objects created/interpre...
Definition: Stmt.cpp:326
The base class of the type hierarchy.
Definition: Type.h:1607
CXXRecordDecl * getAsCXXRecordDecl() const
Retrieves the CXXRecordDecl that this type refers to, either because the type is a RecordType or beca...
Definition: Type.cpp:1870
bool isBlockPointerType() const
Definition: Type.h:7410
bool isBooleanType() const
Definition: Type.h:7823
bool isCharType() const
Definition: Type.cpp:2077
bool isPointerType() const
Definition: Type.h:7402
bool isEnumeralType() const
Definition: Type.h:7500
bool isScalarType() const
Definition: Type.h:7794
bool isChar16Type() const
Definition: Type.cpp:2099
bool isMemberPointerType() const
Definition: Type.h:7450
bool isChar32Type() const
Definition: Type.cpp:2105
bool isObjCObjectPointerType() const
Definition: Type.h:7534
bool isRealFloatingType() const
Floating point categories.
Definition: Type.cpp:2254
bool isWideCharType() const
Definition: Type.cpp:2086
UnaryOperator - This represents the unary-expression's (except sizeof and alignof),...
Definition: Expr.h:2183
The JSON file list parser is used to communicate input to InstallAPI.
@ OK_Ordinary
An ordinary object is located at an address in memory.
Definition: Specifiers.h:148
OverloadFixItKind
@ OFIK_Dereference
@ OFIK_TakeAddress
@ OFIK_RemoveDereference
@ OFIK_RemoveTakeAddress
ExprValueKind
The categorization of expression values, currently following the C++11 scheme.
Definition: Specifiers.h:129
@ VK_PRValue
A pr-value expression (in the C++11 taxonomy) produces a temporary value.
Definition: Specifiers.h:132
@ VK_LValue
An l-value expression is a reference to an object with independent storage.
Definition: Specifiers.h:136
const FunctionProtoType * T
OverloadFixItKind Kind
The type of fix applied.
unsigned NumConversionsFixed
The number of Conversions fixed.
TypeComparisonFuncTy CompareTypes
The type comparison function used to decide if expression FromExpr of type FromTy can be converted to...
bool tryToFixConversion(const Expr *FromExpr, const QualType FromQTy, const QualType ToQTy, Sema &S)
If possible, generates and stores a fix for the given conversion.
static bool compareTypesSimple(CanQualType From, CanQualType To, Sema &S, SourceLocation Loc, ExprValueKind FromVK)
Performs a simple check to see if From type can be converted to To type.
std::vector< FixItHint > Hints
The list of Hints generated so far.