11#include "clang/AST/ASTContext.h"
12#include "clang/AST/ExprCXX.h"
13#include "clang/AST/Type.h"
14#include "clang/Sema/DeclSpec.h"
15#include "clang/Tooling/FixIt.h"
21 SourceLocation AmpLocation = Var.getLocation();
23 AmpLocation, Context.getSourceManager(), Context.getLangOpts());
26 if (Token && Token->is(tok::ellipsis))
27 return FixItHint::CreateInsertion(Token->getLocation(),
"&");
30 AmpLocation = Lexer::getLocForEndOfToken(Token->getLocation(), 0,
31 Context.getSourceManager(),
32 Context.getLangOpts());
33 return FixItHint::CreateInsertion(AmpLocation,
"&");
37 return !(isa<PointerType>(T) || isa<ReferenceType>(T) || isa<ArrayType>(T) ||
38 isa<MemberPointerType>(T) || isa<ObjCObjectPointerType>(T));
42 return (QT->isPointerType() && QT->isFunctionPointerType()) ||
43 isa<MemberPointerType>(QT.getTypePtr());
47 return S.isInvalid() || S.isMacroID();
50static std::optional<SourceLocation>
55 auto PreviousTokenLParen = [&Start, &Context]() {
57 Start, Context.getSourceManager(), Context.getLangOpts());
58 return T && T->is(tok::l_paren);
61 while (Start.isValid() && PreviousTokenLParen())
63 Context.getLangOpts());
74 return FixItHint::CreateInsertion(Loc, Text);
80 bool WhitespaceBefore =
false) {
82 return (llvm::Twine(
' ') + Qualifiers::fromCVRMask(Qualifier).getAsString())
84 return (llvm::Twine(Qualifiers::fromCVRMask(Qualifier).getAsString()) +
" ")
88static std::optional<FixItHint>
changeValue(
const VarDecl &Var,
89 Qualifiers::TQ Qualifier,
92 const ASTContext &Context) {
98 std::optional<SourceLocation> IgnoredParens =
105 llvm_unreachable(
"Unknown QualifierPolicy enum");
109 Qualifiers::TQ Qualifier,
110 const ASTContext &Context) {
114 std::optional<SourceLocation> IgnoredParens =
121static std::optional<FixItHint>
124 const ASTContext &Context) {
143 Var.getLocation(), Context.getSourceManager(), Context.getLangOpts(),
148 std::optional<SourceLocation> IgnoredParens =
164 Var.getLocation(), Context.getSourceManager(), Context.getLangOpts(),
172static std::optional<FixItHint>
175 const ASTContext &Context) {
181 Var.getLocation(), Context.getSourceManager(), Context.getLangOpts(),
182 tok::amp, tok::ampamp);
183 std::optional<SourceLocation> IgnoredParens =
192 const ASTContext &Context,
193 Qualifiers::TQ Qualifier,
198 "Unexpected Insertion Policy");
201 "Unexpected Target");
203 const QualType ParenStrippedType = Var.getType().IgnoreParens();
205 return changeValue(Var, Qualifier, QualTarget, QualPolicy, Context);
207 if (ParenStrippedType->isReferenceType())
209 QualTarget, QualPolicy, Context);
214 if (ParenStrippedType->isPointerType())
216 ParenStrippedType->getPointeeType().getTypePtr(),
217 QualTarget, QualPolicy, Context);
219 if (ParenStrippedType->isArrayType()) {
220 const Type *AT = ParenStrippedType->getBaseElementTypeUnsafe();
221 assert(AT &&
"Did not retrieve array element type for an array.");
224 return changeValue(Var, Qualifier, QualTarget, QualPolicy, Context);
226 if (AT->isPointerType())
227 return changePointer(Var, Qualifier, AT->getPointeeType().getTypePtr(),
228 QualTarget, QualPolicy, Context);
235 if (isa<ParenExpr>(&Node))
238 if (isa<clang::BinaryOperator>(&Node) || isa<UnaryOperator>(&Node))
241 if (isa<clang::ConditionalOperator>(&Node) ||
242 isa<BinaryConditionalOperator>(&Node))
245 if (
const auto *Op = dyn_cast<CXXOperatorCallExpr>(&Node))
246 switch (Op->getOperator()) {
250 return Op->getNumArgs() != 2;
261 if (isa<CStyleCastExpr>(&Node))
271 if (isa<clang::BinaryOperator>(&ExprNode) ||
272 isa<clang::ConditionalOperator>(&ExprNode)) {
275 if (
const auto *Op = dyn_cast<CXXOperatorCallExpr>(&ExprNode)) {
276 return Op->getNumArgs() == 2 && Op->getOperator() != OO_PlusPlus &&
277 Op->getOperator() != OO_MinusMinus && Op->getOperator() != OO_Call &&
278 Op->getOperator() != OO_Subscript;
286 if (
const auto *Op = dyn_cast<clang::UnaryOperator>(&ExprNode)) {
287 if (Op->getOpcode() == UO_AddrOf) {
290 tooling::fixit::getText(*Op->getSubExpr()->IgnoreParens(), Context));
293 StringRef Text = tooling::fixit::getText(ExprNode, Context);
299 Text.consume_back(
"->");
303 return (llvm::Twine(
"*(") + Text +
")").str();
304 return (llvm::Twine(
"*") + Text).str();
static std::string buildQualifier(Qualifiers::TQ Qualifier, bool WhitespaceBefore=false)
bool areParensNeededForStatement(const Stmt &Node)
static std::optional< FixItHint > changePointer(const VarDecl &Var, Qualifiers::TQ Qualifier, const Type *Pointee, QualifierTarget QualTarget, QualifierPolicy QualPolicy, const ASTContext &Context)
static std::optional< FixItHint > changePointerItself(const VarDecl &Var, Qualifiers::TQ Qualifier, const ASTContext &Context)
static std::optional< FixItHint > fixIfNotDangerous(SourceLocation Loc, StringRef Text)
static std::optional< FixItHint > changeValue(const VarDecl &Var, Qualifiers::TQ Qualifier, QualifierTarget QualTarget, QualifierPolicy QualPolicy, const ASTContext &Context)
static bool isMemberOrFunctionPointer(QualType QT)
QualifierTarget
This enum defines which entity is the target for adding the qualifier. This makes only a difference f...
@ Value
Transforming a pointer attaches to the pointee and not the pointer itself. For references and normal ...
static std::optional< FixItHint > changeReferencee(const VarDecl &Var, Qualifiers::TQ Qualifier, QualType Pointee, QualifierTarget QualTarget, QualifierPolicy QualPolicy, const ASTContext &Context)
QualifierPolicy
This enum defines where the qualifier shall be preferably added.
FixItHint changeVarDeclToReference(const VarDecl &Var, ASTContext &Context)
Creates fix to make VarDecl a reference by adding &.
std::optional< FixItHint > addQualifierToVarDecl(const VarDecl &Var, const ASTContext &Context, Qualifiers::TQ Qualifier, QualifierTarget QualTarget, QualifierPolicy QualPolicy)
Creates fix to qualify VarDecl with the specified Qualifier. Requires that Var is isolated in written...
static std::optional< SourceLocation > skipLParensBackwards(SourceLocation Start, const ASTContext &Context)
static bool needParensAfterUnaryOperator(const Expr &ExprNode)
static bool locDangerous(SourceLocation S)
std::string formatDereference(const Expr &ExprNode, const ASTContext &Context)
static bool isValueType(const Type *T)
std::optional< Token > getPreviousToken(SourceLocation Location, const SourceManager &SM, const LangOptions &LangOpts, bool SkipComments)
Returns previous token or std::nullopt if not found.
SourceLocation findPreviousTokenStart(SourceLocation Start, const SourceManager &SM, const LangOptions &LangOpts)
SourceLocation findPreviousTokenKind(SourceLocation Start, const SourceManager &SM, const LangOptions &LangOpts, tok::TokenKind TK)
SourceLocation findPreviousAnyTokenKind(SourceLocation Start, const SourceManager &SM, const LangOptions &LangOpts, TokenKind TK, TokenKinds... TKs)