11 #include "clang/Frontend/CompilerInstance.h" 12 #include "clang/Lex/Lexer.h" 13 #include "clang/Lex/Preprocessor.h" 23 constexpr
char StdMemoryHeader[] =
"memory";
24 constexpr
char ConstructorCall[] =
"constructorCall";
25 constexpr
char ResetCall[] =
"resetCall";
26 constexpr
char NewExpression[] =
"newExpression";
28 std::string GetNewExprName(
const CXXNewExpr *NewExpr,
29 const SourceManager &SM,
30 const LangOptions &Lang) {
31 StringRef WrittenName = Lexer::getSourceText(
32 CharSourceRange::getTokenRange(
33 NewExpr->getAllocatedTypeSourceInfo()->getTypeLoc().getSourceRange()),
35 if (NewExpr->isArray()) {
36 return (WrittenName +
"[]").str();
38 return WrittenName.str();
43 const char MakeSmartPtrCheck::PointerType[] =
"pointerType";
45 MakeSmartPtrCheck::MakeSmartPtrCheck(StringRef
Name,
47 StringRef MakeSmartPtrFunctionName)
49 IncludeStyle(utils::IncludeSorter::parseIncludeStyle(
50 Options.getLocalOrGlobal(
"IncludeStyle",
"llvm"))),
51 MakeSmartPtrFunctionHeader(
52 Options.get(
"MakeSmartPtrFunctionHeader", StdMemoryHeader)),
53 MakeSmartPtrFunctionName(
54 Options.get(
"MakeSmartPtrFunction", MakeSmartPtrFunctionName)),
55 IgnoreMacros(Options.getLocalOrGlobal(
"IgnoreMacros", true)) {}
59 Options.
store(Opts,
"MakeSmartPtrFunctionHeader", MakeSmartPtrFunctionHeader);
60 Options.
store(Opts,
"MakeSmartPtrFunction", MakeSmartPtrFunctionName);
65 const LangOptions &LangOpts)
const {
66 return LangOpts.CPlusPlus11;
71 Inserter = llvm::make_unique<utils::IncludeInserter>(
72 Compiler.getSourceManager(), Compiler.getLangOpts(), IncludeStyle);
73 Compiler.getPreprocessor().addPPCallbacks(Inserter->CreatePPCallbacks());
83 auto CanCallCtor = unless(has(ignoringImpCasts(
84 cxxConstructExpr(hasDeclaration(decl(unless(
isPublic())))))));
87 cxxBindTemporaryExpr(has(ignoringParenImpCasts(
91 cxxNewExpr(hasType(pointsTo(qualType(hasCanonicalType(
94 .bind(NewExpression)),
95 unless(isInTemplateInstantiation()))
96 .bind(ConstructorCall)))),
102 callee(cxxMethodDecl(hasName(
"reset"))),
103 hasArgument(0, cxxNewExpr(CanCallCtor).bind(NewExpression)),
104 unless(isInTemplateInstantiation()))
114 SourceManager &SM = *Result.SourceManager;
115 const auto *Construct =
116 Result.Nodes.getNodeAs<CXXConstructExpr>(ConstructorCall);
117 const auto *Reset = Result.Nodes.getNodeAs<CXXMemberCallExpr>(ResetCall);
118 const auto *Type = Result.Nodes.getNodeAs<QualType>(
PointerType);
119 const auto *New = Result.Nodes.getNodeAs<CXXNewExpr>(NewExpression);
121 if (New->getNumPlacementArgs() != 0)
124 if (New->getType()->getPointeeType()->getContainedAutoType())
134 if (New->isArray() && !New->hasInitializer())
137 checkConstruct(SM, Result.Context, Construct, Type, New);
139 checkReset(SM, Result.Context, Reset, New);
142 void MakeSmartPtrCheck::checkConstruct(SourceManager &SM, ASTContext *
Ctx,
143 const CXXConstructExpr *Construct,
144 const QualType *Type,
145 const CXXNewExpr *New) {
146 SourceLocation ConstructCallStart = Construct->getExprLoc();
147 bool InMacro = ConstructCallStart.isMacroID();
149 if (InMacro && IgnoreMacros) {
153 bool Invalid =
false;
154 StringRef ExprStr = Lexer::getSourceText(
155 CharSourceRange::getCharRange(
156 ConstructCallStart, Construct->getParenOrBraceRange().getBegin()),
161 auto Diag =
diag(ConstructCallStart,
"use %0 instead")
162 << MakeSmartPtrFunctionName;
169 if (!replaceNew(Diag, New, SM, Ctx)) {
174 size_t LAngle = ExprStr.find(
"<");
175 SourceLocation ConstructCallEnd;
176 if (LAngle == StringRef::npos) {
179 ConstructCallEnd = ConstructCallStart.getLocWithOffset(ExprStr.size());
180 Diag << FixItHint::CreateInsertion(
182 "<" + GetNewExprName(New, SM,
getLangOpts()) +
">");
184 ConstructCallEnd = ConstructCallStart.getLocWithOffset(LAngle);
187 Diag << FixItHint::CreateReplacement(
188 CharSourceRange::getCharRange(ConstructCallStart, ConstructCallEnd),
189 MakeSmartPtrFunctionName);
193 if (Construct->isListInitialization()) {
194 SourceRange BraceRange = Construct->getParenOrBraceRange();
195 Diag << FixItHint::CreateReplacement(
196 CharSourceRange::getCharRange(
197 BraceRange.getBegin(), BraceRange.getBegin().getLocWithOffset(1)),
199 Diag << FixItHint::CreateReplacement(
200 CharSourceRange::getCharRange(BraceRange.getEnd(),
201 BraceRange.getEnd().getLocWithOffset(1)),
205 insertHeader(Diag, SM.getFileID(ConstructCallStart));
208 void MakeSmartPtrCheck::checkReset(SourceManager &SM, ASTContext *Ctx,
209 const CXXMemberCallExpr *Reset,
210 const CXXNewExpr *New) {
211 const auto *Expr = cast<MemberExpr>(Reset->getCallee());
212 SourceLocation OperatorLoc = Expr->getOperatorLoc();
213 SourceLocation ResetCallStart = Reset->getExprLoc();
214 SourceLocation ExprStart = Expr->getBeginLoc();
215 SourceLocation ExprEnd =
216 Lexer::getLocForEndOfToken(Expr->getEndLoc(), 0, SM,
getLangOpts());
218 bool InMacro = ExprStart.isMacroID();
220 if (InMacro && IgnoreMacros) {
227 if (OperatorLoc.isInvalid()) {
231 auto Diag =
diag(ResetCallStart,
"use %0 instead")
232 << MakeSmartPtrFunctionName;
239 if (!replaceNew(Diag, New, SM, Ctx)) {
243 Diag << FixItHint::CreateReplacement(
244 CharSourceRange::getCharRange(OperatorLoc, ExprEnd),
245 (llvm::Twine(
" = ") + MakeSmartPtrFunctionName +
"<" +
250 Diag << FixItHint::CreateInsertion(ExprStart,
"*");
252 insertHeader(Diag, SM.getFileID(OperatorLoc));
255 bool MakeSmartPtrCheck::replaceNew(DiagnosticBuilder &Diag,
256 const CXXNewExpr *New, SourceManager &SM,
258 auto SkipParensParents = [&](
const Expr *E) {
259 for (
const Expr *OldE =
nullptr; E != OldE;) {
261 for (
const auto &Node : Ctx->getParents(*E)) {
262 if (
const Expr *Parent = Node.get<ParenExpr>()) {
271 SourceRange NewRange = SkipParensParents(New)->getSourceRange();
272 SourceLocation NewStart = NewRange.getBegin();
273 SourceLocation NewEnd = NewRange.getEnd();
276 if (NewStart.isInvalid() || NewEnd.isInvalid())
279 std::string ArraySizeExpr;
280 if (
const auto* ArraySize = New->getArraySize()) {
281 ArraySizeExpr = Lexer::getSourceText(CharSourceRange::getTokenRange(
282 ArraySize->getSourceRange()),
292 auto HasListIntializedArgument = [](
const CXXConstructExpr *CE) {
293 for (
const auto *Arg : CE->arguments()) {
294 if (isa<CXXStdInitializerListExpr>(Arg) || isa<InitListExpr>(Arg))
298 if (
const auto *ImplicitCE =
299 dyn_cast<CXXConstructExpr>(Arg->IgnoreImplicit())) {
300 if (ImplicitCE->isStdInitListInitialization())
307 switch (New->getInitializationStyle()) {
308 case CXXNewExpr::NoInit: {
309 if (ArraySizeExpr.empty()) {
310 Diag << FixItHint::CreateRemoval(SourceRange(NewStart, NewEnd));
314 Diag << FixItHint::CreateReplacement(SourceRange(NewStart, NewEnd),
319 case CXXNewExpr::CallInit: {
337 if (
const auto *CE = New->getConstructExpr()) {
338 if (HasListIntializedArgument(CE))
341 if (ArraySizeExpr.empty()) {
342 SourceRange InitRange = New->getDirectInitRange();
343 Diag << FixItHint::CreateRemoval(
344 SourceRange(NewStart, InitRange.getBegin()));
345 Diag << FixItHint::CreateRemoval(SourceRange(InitRange.getEnd(), NewEnd));
351 Diag << FixItHint::CreateReplacement(SourceRange(NewStart, NewEnd),
356 case CXXNewExpr::ListInit: {
358 SourceRange InitRange;
359 if (
const auto *NewConstruct = New->getConstructExpr()) {
360 if (NewConstruct->isStdInitListInitialization() ||
361 HasListIntializedArgument(NewConstruct)) {
384 InitRange = SourceRange(
385 NewConstruct->getParenOrBraceRange().getBegin().getLocWithOffset(1),
386 NewConstruct->getParenOrBraceRange().getEnd().getLocWithOffset(-1));
398 if (
const CXXRecordDecl *RD = New->getType()->getPointeeCXXRecordDecl()) {
399 if (llvm::find_if(RD->ctors(), [](
const CXXConstructorDecl *Ctor) {
400 return Ctor->isCopyOrMoveConstructor() &&
401 (Ctor->isDeleted() || Ctor->getAccess() == AS_private);
402 }) != RD->ctor_end()) {
406 InitRange = SourceRange(
407 New->getAllocatedTypeSourceInfo()->getTypeLoc().getBeginLoc(),
408 New->getInitializer()->getSourceRange().getEnd());
410 Diag << FixItHint::CreateRemoval(
411 CharSourceRange::getCharRange(NewStart, InitRange.getBegin()));
412 Diag << FixItHint::CreateRemoval(
413 SourceRange(InitRange.getEnd().getLocWithOffset(1), NewEnd));
420 void MakeSmartPtrCheck::insertHeader(DiagnosticBuilder &Diag, FileID FD) {
421 if (MakeSmartPtrFunctionHeader.empty()) {
424 if (
auto IncludeFixit = Inserter->CreateIncludeInsertion(
425 FD, MakeSmartPtrFunctionHeader,
426 MakeSmartPtrFunctionHeader == StdMemoryHeader)) {
427 Diag << *IncludeFixit;
void store(ClangTidyOptions::OptionMap &Options, StringRef LocalName, StringRef Value) const
Stores an option with the check-local name LocalName with string value Value to Options.
LangOptions getLangOpts() const
Returns the language options from the context.
virtual bool isLanguageVersionSupported(const LangOptions &LangOpts) const
Returns whether the C++ version is compatible with current check.
void registerMatchers(ast_matchers::MatchFinder *Finder) final
Override this to register AST matchers with Finder.
Base class for all clang-tidy checks.
void registerPPCallbacks(clang::CompilerInstance &Compiler) override
virtual SmartPtrTypeMatcher getSmartPointerTypeMatcher() const =0
Returns matcher that match with different smart pointer types.
void check(const ast_matchers::MatchFinder::MatchResult &Result) final
ClangTidyChecks that register ASTMatchers should do the actual work in here.
static constexpr llvm::StringLiteral Name
std::map< std::string, std::string > OptionMap
static const char PointerType[]
llvm::Optional< llvm::Expected< tooling::AtomicChanges > > Result
static bool isPublic(const clang::AccessSpecifier AS, const clang::Linkage Link)
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
void storeOptions(ClangTidyOptions::OptionMap &Opts) override
Should store all options supported by this check with their current values or default values for opti...
Every ClangTidyCheck reports errors through a DiagnosticsEngine provided by this context.
DiagnosticBuilder diag(SourceLocation Loc, StringRef Description, DiagnosticIDs::Level Level=DiagnosticIDs::Warning)
Add a diagnostic with the check's name.