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);
65 const LangOptions &LangOpts)
const {
66 return LangOpts.CPlusPlus11;
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(
95 unless(isInTemplateInstantiation()))
102 callee(cxxMethodDecl(hasName(
"reset"))),
104 unless(isInTemplateInstantiation()))
114 SourceManager &SM = *Result.SourceManager;
115 const auto *Construct =
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)
125 checkConstruct(SM, Construct, Type, New);
127 checkReset(SM, Reset, New);
130 void MakeSmartPtrCheck::checkConstruct(SourceManager &SM,
131 const CXXConstructExpr *Construct,
132 const QualType *Type,
133 const CXXNewExpr *New) {
134 SourceLocation ConstructCallStart = Construct->getExprLoc();
135 bool InMacro = ConstructCallStart.isMacroID();
137 if (InMacro && IgnoreMacros) {
141 bool Invalid =
false;
142 StringRef ExprStr = Lexer::getSourceText(
143 CharSourceRange::getCharRange(
144 ConstructCallStart, Construct->getParenOrBraceRange().getBegin()),
149 auto Diag =
diag(ConstructCallStart,
"use %0 instead")
150 << MakeSmartPtrFunctionName;
157 if (!replaceNew(Diag, New, SM)) {
162 size_t LAngle = ExprStr.find(
"<");
163 SourceLocation ConstructCallEnd;
164 if (LAngle == StringRef::npos) {
167 ConstructCallEnd = ConstructCallStart.getLocWithOffset(ExprStr.size());
168 Diag << FixItHint::CreateInsertion(
170 "<" + GetNewExprName(New, SM,
getLangOpts()) +
">");
172 ConstructCallEnd = ConstructCallStart.getLocWithOffset(LAngle);
175 Diag << FixItHint::CreateReplacement(
176 CharSourceRange::getCharRange(ConstructCallStart, ConstructCallEnd),
177 MakeSmartPtrFunctionName);
181 if (Construct->isListInitialization()) {
182 SourceRange BraceRange = Construct->getParenOrBraceRange();
183 Diag << FixItHint::CreateReplacement(
184 CharSourceRange::getCharRange(
185 BraceRange.getBegin(), BraceRange.getBegin().getLocWithOffset(1)),
187 Diag << FixItHint::CreateReplacement(
188 CharSourceRange::getCharRange(BraceRange.getEnd(),
189 BraceRange.getEnd().getLocWithOffset(1)),
193 insertHeader(Diag, SM.getFileID(ConstructCallStart));
196 void MakeSmartPtrCheck::checkReset(SourceManager &SM,
197 const CXXMemberCallExpr *Reset,
198 const CXXNewExpr *New) {
199 const auto *Expr = cast<MemberExpr>(Reset->getCallee());
200 SourceLocation OperatorLoc = Expr->getOperatorLoc();
201 SourceLocation ResetCallStart = Reset->getExprLoc();
202 SourceLocation ExprStart = Expr->getLocStart();
203 SourceLocation ExprEnd =
204 Lexer::getLocForEndOfToken(Expr->getLocEnd(), 0, SM,
getLangOpts());
206 bool InMacro = ExprStart.isMacroID();
208 if (InMacro && IgnoreMacros) {
215 if (OperatorLoc.isInvalid()) {
219 auto Diag =
diag(ResetCallStart,
"use %0 instead")
220 << MakeSmartPtrFunctionName;
227 if (!replaceNew(Diag, New, SM)) {
231 Diag << FixItHint::CreateReplacement(
232 CharSourceRange::getCharRange(OperatorLoc, ExprEnd),
233 (llvm::Twine(
" = ") + MakeSmartPtrFunctionName +
"<" +
238 Diag << FixItHint::CreateInsertion(ExprStart,
"*");
240 insertHeader(Diag, SM.getFileID(OperatorLoc));
243 bool MakeSmartPtrCheck::replaceNew(DiagnosticBuilder &Diag,
244 const CXXNewExpr *New,
246 SourceLocation NewStart = New->getSourceRange().getBegin();
247 SourceLocation NewEnd = New->getSourceRange().getEnd();
250 if (NewStart.isInvalid() || NewEnd.isInvalid())
253 std::string ArraySizeExpr;
254 if (
const auto* ArraySize = New->getArraySize()) {
255 ArraySizeExpr = Lexer::getSourceText(CharSourceRange::getTokenRange(
256 ArraySize->getSourceRange()),
261 switch (New->getInitializationStyle()) {
262 case CXXNewExpr::NoInit: {
263 if (ArraySizeExpr.empty()) {
264 Diag << FixItHint::CreateRemoval(SourceRange(NewStart, NewEnd));
268 Diag << FixItHint::CreateReplacement(SourceRange(NewStart, NewEnd),
273 case CXXNewExpr::CallInit: {
288 if (
const auto *CE = New->getConstructExpr()) {
289 for (
const auto *Arg : CE->arguments()) {
290 if (isa<CXXStdInitializerListExpr>(Arg)) {
295 auto IsStdInitListInitConstructExpr = [](
const Expr* E) {
297 if (
const auto *ImplicitCE = dyn_cast<CXXConstructExpr>(E)) {
298 if (ImplicitCE->isStdInitListInitialization())
303 if (IsStdInitListInitConstructExpr(Arg->IgnoreImplicit()))
307 if (ArraySizeExpr.empty()) {
308 SourceRange InitRange = New->getDirectInitRange();
309 Diag << FixItHint::CreateRemoval(
310 SourceRange(NewStart, InitRange.getBegin()));
311 Diag << FixItHint::CreateRemoval(SourceRange(InitRange.getEnd(), NewEnd));
317 Diag << FixItHint::CreateReplacement(SourceRange(NewStart, NewEnd),
322 case CXXNewExpr::ListInit: {
324 SourceRange InitRange;
325 if (
const auto *NewConstruct = New->getConstructExpr()) {
326 if (NewConstruct->isStdInitListInitialization()) {
346 InitRange = SourceRange(
347 NewConstruct->getParenOrBraceRange().getBegin().getLocWithOffset(1),
348 NewConstruct->getParenOrBraceRange().getEnd().getLocWithOffset(-1));
355 InitRange = SourceRange(
356 New->getAllocatedTypeSourceInfo()->getTypeLoc().getLocStart(),
357 New->getInitializer()->getSourceRange().getEnd());
359 Diag << FixItHint::CreateRemoval(
360 CharSourceRange::getCharRange(NewStart, InitRange.getBegin()));
361 Diag << FixItHint::CreateRemoval(
362 SourceRange(InitRange.getEnd().getLocWithOffset(1), NewEnd));
369 void MakeSmartPtrCheck::insertHeader(DiagnosticBuilder &Diag, FileID FD) {
370 if (MakeSmartPtrFunctionHeader.empty()) {
373 if (
auto IncludeFixit = Inserter->CreateIncludeInsertion(
374 FD, MakeSmartPtrFunctionHeader,
375 MakeSmartPtrFunctionHeader == StdMemoryHeader)) {
376 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.
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[]
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...
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.