11 #include "clang/Frontend/CompilerInstance.h"
12 #include "clang/Lex/Lexer.h"
13 #include "clang/Lex/Preprocessor.h"
15 using namespace clang::ast_matchers;
23 constexpr
char StdMemoryHeader[] =
"memory";
25 std::string GetNewExprName(
const CXXNewExpr *NewExpr,
26 const SourceManager &
SM,
27 const LangOptions &Lang) {
28 StringRef WrittenName = Lexer::getSourceText(
29 CharSourceRange::getTokenRange(
30 NewExpr->getAllocatedTypeSourceInfo()->getTypeLoc().getSourceRange()),
32 if (NewExpr->isArray()) {
33 return WrittenName.str() +
"[]";
35 return WrittenName.str();
40 const char MakeSmartPtrCheck::PointerType[] =
"pointerType";
41 const char MakeSmartPtrCheck::ConstructorCall[] =
"constructorCall";
42 const char MakeSmartPtrCheck::ResetCall[] =
"resetCall";
43 const char MakeSmartPtrCheck::NewExpression[] =
"newExpression";
46 StringRef MakeSmartPtrFunctionName)
48 IncludeStyle(utils::IncludeSorter::parseIncludeStyle(
49 Options.get(
"IncludeStyle",
"llvm"))),
50 MakeSmartPtrFunctionHeader(
51 Options.get(
"MakeSmartPtrFunctionHeader", StdMemoryHeader)),
52 MakeSmartPtrFunctionName(
53 Options.get(
"MakeSmartPtrFunction", MakeSmartPtrFunctionName)) {}
57 Options.
store(Opts,
"MakeSmartPtrFunctionHeader", MakeSmartPtrFunctionHeader);
58 Options.
store(Opts,
"MakeSmartPtrFunction", MakeSmartPtrFunctionName);
64 Compiler.getSourceManager(), Compiler.getLangOpts(), IncludeStyle));
65 Compiler.getPreprocessor().addPPCallbacks(Inserter->CreatePPCallbacks());
75 auto CanCallCtor = unless(has(ignoringImpCasts(
76 cxxConstructExpr(hasDeclaration(decl(unless(isPublic())))))));
79 cxxBindTemporaryExpr(has(ignoringParenImpCasts(
83 cxxNewExpr(hasType(pointsTo(qualType(hasCanonicalType(
93 callee(cxxMethodDecl(hasName(
"reset"))),
104 SourceManager &SM = *Result.SourceManager;
105 const auto *Construct =
107 const auto *Reset = Result.Nodes.getNodeAs<CXXMemberCallExpr>(
ResetCall);
108 const auto *Type = Result.Nodes.getNodeAs<QualType>(
PointerType);
109 const auto *New = Result.Nodes.getNodeAs<CXXNewExpr>(
NewExpression);
111 if (New->getNumPlacementArgs() != 0)
115 checkConstruct(SM, Construct, Type, New);
117 checkReset(SM, Reset, New);
120 void MakeSmartPtrCheck::checkConstruct(SourceManager &SM,
121 const CXXConstructExpr *Construct,
122 const QualType *Type,
123 const CXXNewExpr *New) {
124 SourceLocation ConstructCallStart = Construct->getExprLoc();
126 bool Invalid =
false;
127 StringRef ExprStr = Lexer::getSourceText(
128 CharSourceRange::getCharRange(
129 ConstructCallStart, Construct->getParenOrBraceRange().getBegin()),
134 auto Diag =
diag(ConstructCallStart,
"use %0 instead")
135 << MakeSmartPtrFunctionName;
138 size_t LAngle = ExprStr.find(
"<");
139 SourceLocation ConstructCallEnd;
140 if (LAngle == StringRef::npos) {
143 ConstructCallEnd = ConstructCallStart.getLocWithOffset(ExprStr.size());
144 Diag << FixItHint::CreateInsertion(
146 "<" + GetNewExprName(New, SM,
getLangOpts()) +
">");
148 ConstructCallEnd = ConstructCallStart.getLocWithOffset(LAngle);
151 Diag << FixItHint::CreateReplacement(
152 CharSourceRange::getCharRange(ConstructCallStart, ConstructCallEnd),
153 MakeSmartPtrFunctionName);
157 if (Construct->isListInitialization()) {
158 SourceRange BraceRange = Construct->getParenOrBraceRange();
159 Diag << FixItHint::CreateReplacement(
160 CharSourceRange::getCharRange(
161 BraceRange.getBegin(), BraceRange.getBegin().getLocWithOffset(1)),
163 Diag << FixItHint::CreateReplacement(
164 CharSourceRange::getCharRange(BraceRange.getEnd(),
165 BraceRange.getEnd().getLocWithOffset(1)),
169 replaceNew(Diag, New, SM);
170 insertHeader(Diag, SM.getFileID(ConstructCallStart));
173 void MakeSmartPtrCheck::checkReset(SourceManager &SM,
174 const CXXMemberCallExpr *Reset,
175 const CXXNewExpr *New) {
176 const auto *Expr = cast<MemberExpr>(Reset->getCallee());
177 SourceLocation OperatorLoc = Expr->getOperatorLoc();
178 SourceLocation ResetCallStart = Reset->getExprLoc();
179 SourceLocation ExprStart = Expr->getLocStart();
180 SourceLocation ExprEnd =
181 Lexer::getLocForEndOfToken(Expr->getLocEnd(), 0,
SM,
getLangOpts());
183 auto Diag =
diag(ResetCallStart,
"use %0 instead")
184 << MakeSmartPtrFunctionName;
186 Diag << FixItHint::CreateReplacement(
187 CharSourceRange::getCharRange(OperatorLoc, ExprEnd),
188 (llvm::Twine(
" = ") + MakeSmartPtrFunctionName +
"<" +
193 Diag << FixItHint::CreateInsertion(ExprStart,
"*");
195 replaceNew(Diag, New, SM);
196 insertHeader(Diag, SM.getFileID(OperatorLoc));
199 void MakeSmartPtrCheck::replaceNew(DiagnosticBuilder &Diag,
200 const CXXNewExpr *New,
202 SourceLocation NewStart = New->getSourceRange().getBegin();
203 SourceLocation NewEnd = New->getSourceRange().getEnd();
205 std::string ArraySizeExpr;
206 if (
const auto* ArraySize = New->getArraySize()) {
207 ArraySizeExpr = Lexer::getSourceText(CharSourceRange::getTokenRange(
208 ArraySize->getSourceRange()),
213 switch (New->getInitializationStyle()) {
214 case CXXNewExpr::NoInit: {
215 if (ArraySizeExpr.empty()) {
216 Diag << FixItHint::CreateRemoval(SourceRange(NewStart, NewEnd));
220 Diag << FixItHint::CreateReplacement(SourceRange(NewStart, NewEnd),
225 case CXXNewExpr::CallInit: {
226 if (ArraySizeExpr.empty()) {
227 SourceRange InitRange = New->getDirectInitRange();
228 Diag << FixItHint::CreateRemoval(
229 SourceRange(NewStart, InitRange.getBegin()));
230 Diag << FixItHint::CreateRemoval(SourceRange(InitRange.getEnd(), NewEnd));
236 Diag << FixItHint::CreateReplacement(SourceRange(NewStart, NewEnd),
241 case CXXNewExpr::ListInit: {
243 SourceRange InitRange;
244 if (
const auto *NewConstruct = New->getConstructExpr()) {
252 InitRange = SourceRange(
253 NewConstruct->getParenOrBraceRange().getBegin().getLocWithOffset(1),
254 NewConstruct->getParenOrBraceRange().getEnd().getLocWithOffset(-1));
260 InitRange = SourceRange(
261 New->getAllocatedTypeSourceInfo()->getTypeLoc().getLocStart(),
262 New->getInitializer()->getSourceRange().getEnd());
264 Diag << FixItHint::CreateRemoval(
265 CharSourceRange::getCharRange(NewStart, InitRange.getBegin()));
266 Diag << FixItHint::CreateRemoval(
267 SourceRange(InitRange.getEnd().getLocWithOffset(1), NewEnd));
273 void MakeSmartPtrCheck::insertHeader(DiagnosticBuilder &Diag, FileID FD) {
274 if (MakeSmartPtrFunctionHeader.empty()) {
277 if (
auto IncludeFixit = Inserter->CreateIncludeInsertion(
278 FD, MakeSmartPtrFunctionHeader,
279 MakeSmartPtrFunctionHeader == StdMemoryHeader)) {
280 Diag << *IncludeFixit;
LangOptions getLangOpts() const
Returns the language options from the context.
std::unique_ptr< ast_matchers::MatchFinder > Finder
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.
static const char ConstructorCall[]
void check(const ast_matchers::MatchFinder::MatchResult &Result) final
ClangTidyChecks that register ASTMatchers should do the actual work in here.
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.
std::map< std::string, std::string > OptionMap
static const char PointerType[]
void storeOptions(ClangTidyOptions::OptionMap &Opts) override
Should store all options supported by this check with their current values or default values for opti...
Produces fixes to insert specified includes to source files, if not yet present.
ClangTidyContext & Context
Every ClangTidyCheck reports errors through a DiagnosticsEngine provided by this context.
static const char NewExpression[]
static const char ResetCall[]
DiagnosticBuilder diag(SourceLocation Loc, StringRef Description, DiagnosticIDs::Level Level=DiagnosticIDs::Warning)
Add a diagnostic with the check's name.