clang 22.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, 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)) {
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;
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;
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
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,
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;
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
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();
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::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
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)
static QualType getPointeeType(const MemRegion *R)
__device__ __2f16 float __ockl_bool s
CanQualType getCanonicalType(QualType T) const
Return the canonical (structural) type corresponding to the specified potentially non-canonical type ...
QualType getPointerType(QualType T) const
Return the uniqued reference to the type for a pointer to the specified type.
IdentifierTable & Idents
Definition ASTContext.h:737
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:1143
bool hasUserProvidedDefaultConstructor() const
Whether this class has a user-provided default constructor per C++11.
Definition DeclCXX.h:786
bool hasDefinition() const
Definition DeclCXX.h:561
CanQual< Type > getNonReferenceType() const
If the canonical type is a reference type, returns the type that it refers to; otherwise,...
bool isAtLeastAsQualifiedAs(CanQual< T > Other, const ASTContext &Ctx) const
Determines whether this canonical type is at least as qualified as the Other canonical type.
CanQual< T > getUnqualifiedType() const
Retrieve the unqualified form of this type.
static CharSourceRange getTokenRange(SourceRange R)
This represents one expression.
Definition Expr.h:112
Expr * IgnoreParenCasts() LLVM_READONLY
Skip past any parentheses and casts which might surround this expression until reaching a fixed point...
Definition Expr.cpp:3078
bool isLValue() const
isLValue - True if this expression is an "l-value" according to the rules of the current language.
Definition Expr.h:284
@ NPC_ValueDependentIsNotNull
Specifies that a value-dependent expression should be considered to never be a null pointer constant.
Definition Expr.h:837
ExprObjectKind getObjectKind() const
getObjectKind - The object kind that this expression produces.
Definition Expr.h:451
Expr * IgnoreImpCasts() LLVM_READONLY
Skip past any implicit casts which might surround this expression until reaching a fixed point.
Definition Expr.cpp:3053
static FixItHint CreateRemoval(CharSourceRange RemoveRange)
Create a code modification hint that removes the given source range.
Definition Diagnostic.h:128
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:102
FullExpr - Represents a "full-expression" node.
Definition Expr.h:1051
IdentifierInfo & get(StringRef Name)
Return the identifier token info for the specified named identifier.
PointerType - C99 6.7.5.1 - Pointer Declarators.
Definition TypeBase.h:3328
MacroDefinition getMacroDefinitionAtLoc(const IdentifierInfo *II, SourceLocation Loc)
A (possibly-)qualified type.
Definition TypeBase.h:937
Sema - This implements semantic analysis and AST building for C.
Definition Sema.h:854
ASTContext & Context
Definition Sema.h:1283
std::string getFixItZeroLiteralForType(QualType T, SourceLocation Loc) const
ASTContext & getASTContext() const
Definition Sema.h:925
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:83
Preprocessor & PP
Definition Sema.h:1282
const LangOptions & LangOpts
Definition Sema.h:1281
bool IsDerivedFrom(SourceLocation Loc, CXXRecordDecl *Derived, CXXRecordDecl *Base, CXXBasePaths &Paths)
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:334
The base class of the type hierarchy.
Definition TypeBase.h:1833
UnaryOperator - This represents the unary-expression's (except sizeof and alignof),...
Definition Expr.h:2246
The JSON file list parser is used to communicate input to InstallAPI.
CanQual< Type > CanQualType
Represents a canonical, potentially-qualified type.
bool isa(CodeGen::Address addr)
Definition Address.h:330
@ OK_Ordinary
An ordinary object is located at an address in memory.
Definition Specifiers.h:151
@ OFIK_Dereference
@ OFIK_TakeAddress
@ OFIK_RemoveDereference
@ OFIK_RemoveTakeAddress
const FunctionProtoType * T
ExprValueKind
The categorization of expression values, currently following the C++11 scheme.
Definition Specifiers.h:132
@ VK_PRValue
A pr-value expression (in the C++11 taxonomy) produces a temporary value.
Definition Specifiers.h:135
@ VK_LValue
An l-value expression is a reference to an object with independent storage.
Definition Specifiers.h:139
U cast(CodeGen::Address addr)
Definition Address.h:327
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.