11 #include "clang/Frontend/CompilerInstance.h" 12 #include "clang/Lex/Lexer.h" 13 #include "clang/Lex/Preprocessor.h" 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";
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);
67 Compiler.getSourceManager(), Compiler.getLangOpts(), IncludeStyle));
68 Compiler.getPreprocessor().addPPCallbacks(Inserter->CreatePPCallbacks());
78 auto CanCallCtor = unless(has(ignoringImpCasts(
79 cxxConstructExpr(hasDeclaration(decl(unless(isPublic())))))));
82 cxxBindTemporaryExpr(has(ignoringParenImpCasts(
86 cxxNewExpr(hasType(pointsTo(qualType(hasCanonicalType(
90 unless(isInTemplateInstantiation()))
97 callee(cxxMethodDecl(hasName(
"reset"))),
99 unless(isInTemplateInstantiation()))
109 SourceManager &SM = *Result.SourceManager;
110 const auto *Construct =
112 const auto *Reset = Result.Nodes.getNodeAs<CXXMemberCallExpr>(
ResetCall);
113 const auto *Type = Result.Nodes.getNodeAs<QualType>(
PointerType);
114 const auto *New = Result.Nodes.getNodeAs<CXXNewExpr>(
NewExpression);
116 if (New->getNumPlacementArgs() != 0)
120 checkConstruct(SM, Construct, Type, New);
122 checkReset(SM, Reset, New);
125 void MakeSmartPtrCheck::checkConstruct(SourceManager &SM,
126 const CXXConstructExpr *Construct,
127 const QualType *Type,
128 const CXXNewExpr *New) {
129 SourceLocation ConstructCallStart = Construct->getExprLoc();
130 bool InMacro = ConstructCallStart.isMacroID();
132 if (InMacro && IgnoreMacros) {
136 bool Invalid =
false;
137 StringRef ExprStr = Lexer::getSourceText(
138 CharSourceRange::getCharRange(
139 ConstructCallStart, Construct->getParenOrBraceRange().getBegin()),
144 auto Diag =
diag(ConstructCallStart,
"use %0 instead")
145 << MakeSmartPtrFunctionName;
152 if (!replaceNew(Diag, New, SM)) {
157 size_t LAngle = ExprStr.find(
"<");
158 SourceLocation ConstructCallEnd;
159 if (LAngle == StringRef::npos) {
162 ConstructCallEnd = ConstructCallStart.getLocWithOffset(ExprStr.size());
163 Diag << FixItHint::CreateInsertion(
165 "<" + GetNewExprName(New, SM,
getLangOpts()) +
">");
167 ConstructCallEnd = ConstructCallStart.getLocWithOffset(LAngle);
170 Diag << FixItHint::CreateReplacement(
171 CharSourceRange::getCharRange(ConstructCallStart, ConstructCallEnd),
172 MakeSmartPtrFunctionName);
176 if (Construct->isListInitialization()) {
177 SourceRange BraceRange = Construct->getParenOrBraceRange();
178 Diag << FixItHint::CreateReplacement(
179 CharSourceRange::getCharRange(
180 BraceRange.getBegin(), BraceRange.getBegin().getLocWithOffset(1)),
182 Diag << FixItHint::CreateReplacement(
183 CharSourceRange::getCharRange(BraceRange.getEnd(),
184 BraceRange.getEnd().getLocWithOffset(1)),
188 insertHeader(Diag, SM.getFileID(ConstructCallStart));
191 void MakeSmartPtrCheck::checkReset(SourceManager &SM,
192 const CXXMemberCallExpr *Reset,
193 const CXXNewExpr *New) {
194 const auto *Expr = cast<MemberExpr>(Reset->getCallee());
195 SourceLocation OperatorLoc = Expr->getOperatorLoc();
196 SourceLocation ResetCallStart = Reset->getExprLoc();
197 SourceLocation ExprStart = Expr->getLocStart();
198 SourceLocation ExprEnd =
199 Lexer::getLocForEndOfToken(Expr->getLocEnd(), 0, SM,
getLangOpts());
201 bool InMacro = ExprStart.isMacroID();
203 if (InMacro && IgnoreMacros) {
210 if (OperatorLoc.isInvalid()) {
214 auto Diag =
diag(ResetCallStart,
"use %0 instead")
215 << MakeSmartPtrFunctionName;
222 if (!replaceNew(Diag, New, SM)) {
226 Diag << FixItHint::CreateReplacement(
227 CharSourceRange::getCharRange(OperatorLoc, ExprEnd),
228 (llvm::Twine(
" = ") + MakeSmartPtrFunctionName +
"<" +
233 Diag << FixItHint::CreateInsertion(ExprStart,
"*");
235 insertHeader(Diag, SM.getFileID(OperatorLoc));
238 bool MakeSmartPtrCheck::replaceNew(DiagnosticBuilder &Diag,
239 const CXXNewExpr *New,
241 SourceLocation NewStart = New->getSourceRange().getBegin();
242 SourceLocation NewEnd = New->getSourceRange().getEnd();
244 std::string ArraySizeExpr;
245 if (
const auto* ArraySize = New->getArraySize()) {
246 ArraySizeExpr = Lexer::getSourceText(CharSourceRange::getTokenRange(
247 ArraySize->getSourceRange()),
252 switch (New->getInitializationStyle()) {
253 case CXXNewExpr::NoInit: {
254 if (ArraySizeExpr.empty()) {
255 Diag << FixItHint::CreateRemoval(SourceRange(NewStart, NewEnd));
259 Diag << FixItHint::CreateReplacement(SourceRange(NewStart, NewEnd),
264 case CXXNewExpr::CallInit: {
279 if (
const auto *CE = New->getConstructExpr()) {
280 for (
const auto *Arg : CE->arguments()) {
281 if (isa<CXXStdInitializerListExpr>(Arg)) {
286 if (
const auto *ImplicitCE = dyn_cast<CXXConstructExpr>(Arg)) {
287 if (ImplicitCE->isStdInitListInitialization()) {
293 if (ArraySizeExpr.empty()) {
294 SourceRange InitRange = New->getDirectInitRange();
295 Diag << FixItHint::CreateRemoval(
296 SourceRange(NewStart, InitRange.getBegin()));
297 Diag << FixItHint::CreateRemoval(SourceRange(InitRange.getEnd(), NewEnd));
303 Diag << FixItHint::CreateReplacement(SourceRange(NewStart, NewEnd),
308 case CXXNewExpr::ListInit: {
310 SourceRange InitRange;
311 if (
const auto *NewConstruct = New->getConstructExpr()) {
312 if (NewConstruct->isStdInitListInitialization()) {
332 InitRange = SourceRange(
333 NewConstruct->getParenOrBraceRange().getBegin().getLocWithOffset(1),
334 NewConstruct->getParenOrBraceRange().getEnd().getLocWithOffset(-1));
341 InitRange = SourceRange(
342 New->getAllocatedTypeSourceInfo()->getTypeLoc().getLocStart(),
343 New->getInitializer()->getSourceRange().getEnd());
345 Diag << FixItHint::CreateRemoval(
346 CharSourceRange::getCharRange(NewStart, InitRange.getBegin()));
347 Diag << FixItHint::CreateRemoval(
348 SourceRange(InitRange.getEnd().getLocWithOffset(1), NewEnd));
355 void MakeSmartPtrCheck::insertHeader(DiagnosticBuilder &Diag, FileID FD) {
356 if (MakeSmartPtrFunctionHeader.empty()) {
359 if (
auto IncludeFixit = Inserter->CreateIncludeInsertion(
360 FD, MakeSmartPtrFunctionHeader,
361 MakeSmartPtrFunctionHeader == StdMemoryHeader)) {
362 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.
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.
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.
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.