clang-tools 20.0.0git
IncorrectEnableSharedFromThisCheck.cpp
Go to the documentation of this file.
1//===--- IncorrectEnableSharedFromThisCheck.cpp - clang-tidy --------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
10#include "clang/AST/ASTContext.h"
11#include "clang/AST/DeclCXX.h"
12#include "clang/ASTMatchers/ASTMatchFinder.h"
13
14using namespace clang::ast_matchers;
15
16namespace clang::tidy::bugprone {
17
19 const auto EnableSharedFromThis =
20 cxxRecordDecl(hasName("enable_shared_from_this"), isInStdNamespace());
21 const auto QType = hasCanonicalType(hasDeclaration(
22 cxxRecordDecl(
23 anyOf(EnableSharedFromThis.bind("enable_rec"),
24 cxxRecordDecl(hasAnyBase(cxxBaseSpecifier(
25 isPublic(), hasType(hasCanonicalType(
26 hasDeclaration(EnableSharedFromThis))))))))
27 .bind("base_rec")));
28 Finder->addMatcher(
29 cxxRecordDecl(
30 unless(isExpansionInSystemHeader()),
31 hasDirectBase(cxxBaseSpecifier(unless(isPublic()), hasType(QType))
32 .bind("base")))
33 .bind("derived"),
34 this);
35}
36
38 const MatchFinder::MatchResult &Result) {
39 const auto *BaseSpec = Result.Nodes.getNodeAs<CXXBaseSpecifier>("base");
40 const auto *Base = Result.Nodes.getNodeAs<CXXRecordDecl>("base_rec");
41 const auto *Derived = Result.Nodes.getNodeAs<CXXRecordDecl>("derived");
42 const bool IsEnableSharedFromThisDirectBase =
43 Result.Nodes.getNodeAs<CXXRecordDecl>("enable_rec") == Base;
44 const bool HasWrittenAccessSpecifier =
45 BaseSpec->getAccessSpecifierAsWritten() != AS_none;
46 const auto ReplacementRange = CharSourceRange(
47 SourceRange(BaseSpec->getBeginLoc()), HasWrittenAccessSpecifier);
48 const llvm::StringRef Replacement =
49 HasWrittenAccessSpecifier ? "public" : "public ";
50 const FixItHint Hint =
51 IsEnableSharedFromThisDirectBase
52 ? FixItHint::CreateReplacement(ReplacementRange, Replacement)
53 : FixItHint();
54 diag(Derived->getLocation(),
55 "%2 is not publicly inheriting from "
56 "%select{%1 which inherits from |}0'std::enable_shared_"
57 "from_this', "
58 "which will cause unintended behaviour "
59 "when using 'shared_from_this'; make the inheritance "
60 "public",
61 DiagnosticIDs::Warning)
62 << IsEnableSharedFromThisDirectBase << Base << Derived << Hint;
63}
64
65} // namespace clang::tidy::bugprone
DiagnosticBuilder diag(SourceLocation Loc, StringRef Description, DiagnosticIDs::Level Level=DiagnosticIDs::Warning)
Add a diagnostic with the check's name.
void registerMatchers(ast_matchers::MatchFinder *Finder) override
Override this to register AST matchers with Finder.
void check(const ast_matchers::MatchFinder::MatchResult &Result) override
ClangTidyChecks that register ASTMatchers should do the actual work in here.