11 #include "clang/AST/ASTContext.h" 12 #include "clang/AST/CXXInheritance.h" 13 #include "clang/ASTMatchers/ASTMatchFinder.h" 14 #include "clang/Lex/Lexer.h" 23 AST_MATCHER(CXXMethodDecl, isStatic) {
return Node.isStatic(); }
26 return Node.isOverloadedOperator();
32 return MD->size_overridden_methods() > 0 || MD->hasAttr<OverrideAttr>();
41 const CXXMethodDecl *BaseMD,
42 const CXXMethodDecl *DerivedMD) {
43 QualType BaseReturnTy = BaseMD->getType()
44 ->getAs<FunctionType>()
47 QualType DerivedReturnTy = DerivedMD->getType()
48 ->getAs<FunctionType>()
52 if (DerivedReturnTy->isDependentType() || BaseReturnTy->isDependentType())
56 if (Context->hasSameType(DerivedReturnTy, BaseReturnTy))
62 if (!(BaseReturnTy->isPointerType() && DerivedReturnTy->isPointerType()) &&
63 !(BaseReturnTy->isReferenceType() && DerivedReturnTy->isReferenceType()))
69 QualType DTy = DerivedReturnTy->getPointeeType().getCanonicalType();
70 QualType BTy = BaseReturnTy->getPointeeType().getCanonicalType();
72 const CXXRecordDecl *DRD = DTy->getAsCXXRecordDecl();
73 const CXXRecordDecl *BRD = BTy->getAsCXXRecordDecl();
74 if (DRD ==
nullptr || BRD ==
nullptr)
77 if (!DRD->hasDefinition() || !BRD->hasDefinition())
83 if (!Context->hasSameUnqualifiedType(DTy, BTy)) {
85 CXXBasePaths Paths(
true,
true,
89 if (!DRD->isDerivedFrom(BRD, Paths))
93 if (Paths.isAmbiguous(Context->getCanonicalType(BTy).getUnqualifiedType()))
100 DRD->getCanonicalDecl() == DerivedMD->getParent()->getCanonicalDecl();
101 bool HasPublicAccess =
false;
102 for (
const auto &
Path : Paths) {
103 if (
Path.Access == AS_public)
104 HasPublicAccess =
true;
106 if (!HasPublicAccess && !IsItself)
112 if (DerivedReturnTy.getLocalCVRQualifiers() !=
113 BaseReturnTy.getLocalCVRQualifiers())
118 if (DTy.isMoreQualifiedThan(BTy))
126 if (
const auto *Decayed = Type->getAs<DecayedType>())
127 return Decayed->getDecayedType();
133 const CXXMethodDecl *DerivedMD) {
134 unsigned NumParamA = BaseMD->getNumParams();
135 unsigned NumParamB = DerivedMD->getNumParams();
136 if (NumParamA != NumParamB)
139 for (
unsigned I = 0; I < NumParamA; I++) {
140 if (
getDecayedType(BaseMD->getParamDecl(I)->getType().getCanonicalType()) !=
142 DerivedMD->getParamDecl(I)->getType().getCanonicalType()))
151 const CXXMethodDecl *BaseMD,
152 const CXXMethodDecl *DerivedMD) {
153 if (BaseMD->isStatic() != DerivedMD->isStatic())
156 if (BaseMD->getType() == DerivedMD->getType())
171 const CXXMethodDecl *DerivedMD) {
172 for (CXXMethodDecl::method_iterator I = DerivedMD->begin_overridden_methods(),
173 E = DerivedMD->end_overridden_methods();
175 const CXXMethodDecl *OverriddenMD = *I;
176 if (BaseMD->getCanonicalDecl() == OverriddenMD->getCanonicalDecl())
183 bool VirtualNearMissCheck::isPossibleToBeOverridden(
184 const CXXMethodDecl *BaseMD) {
185 auto Iter = PossibleMap.find(BaseMD);
186 if (Iter != PossibleMap.end())
189 bool IsPossible = !BaseMD->isImplicit() && !isa<CXXConstructorDecl>(BaseMD) &&
190 !isa<CXXDestructorDecl>(BaseMD) && BaseMD->isVirtual() &&
191 !BaseMD->isOverloadedOperator() &&
192 !isa<CXXConversionDecl>(BaseMD);
193 PossibleMap[BaseMD] = IsPossible;
197 bool VirtualNearMissCheck::isOverriddenByDerivedClass(
198 const CXXMethodDecl *BaseMD,
const CXXRecordDecl *DerivedRD) {
199 auto Key = std::make_pair(BaseMD, DerivedRD);
200 auto Iter = OverriddenMap.find(Key);
201 if (Iter != OverriddenMap.end())
204 bool IsOverridden =
false;
205 for (
const CXXMethodDecl *DerivedMD : DerivedRD->methods()) {
214 OverriddenMap[Key] = IsOverridden;
218 void VirtualNearMissCheck::registerMatchers(MatchFinder *Finder) {
219 if (!getLangOpts().CPlusPlus)
224 unless(anyOf(isOverride(), isImplicit(), cxxConstructorDecl(),
225 cxxDestructorDecl(), cxxConversionDecl(), isStatic(),
226 isOverloadedOperator())))
231 void VirtualNearMissCheck::check(
const MatchFinder::MatchResult &Result) {
232 const auto *DerivedMD = Result.Nodes.getNodeAs<CXXMethodDecl>(
"method");
235 const ASTContext *Context = Result.Context;
237 const auto *DerivedRD = DerivedMD->getParent()->getDefinition();
240 for (
const auto &BaseSpec : DerivedRD->bases()) {
241 if (
const auto *BaseRD = BaseSpec.getType()->getAsCXXRecordDecl()) {
242 for (
const auto *BaseMD : BaseRD->methods()) {
243 if (!isPossibleToBeOverridden(BaseMD))
246 if (isOverriddenByDerivedClass(BaseMD, DerivedRD))
249 unsigned EditDistance = BaseMD->getName().edit_distance(
250 DerivedMD->getName(), EditDistanceThreshold);
251 if (EditDistance > 0 && EditDistance <= EditDistanceThreshold) {
254 auto Range = CharSourceRange::getTokenRange(
255 SourceRange(DerivedMD->getLocation()));
257 bool ApplyFix = !BaseMD->isTemplateInstantiation() &&
258 !DerivedMD->isTemplateInstantiation();
260 diag(DerivedMD->getLocStart(),
261 "method '%0' has a similar name and the same signature as " 262 "virtual method '%1'; did you mean to override it?")
263 << DerivedMD->getQualifiedNameAsString()
264 << BaseMD->getQualifiedNameAsString();
266 Diag << FixItHint::CreateReplacement(
Range, BaseMD->getName());
AST_MATCHER(BinaryOperator, isAssignmentOperator)
static bool isOverrideMethod(const CXXMethodDecl *MD)
Finds out if the given method overrides some method.
static bool checkOverrideWithoutName(const ASTContext *Context, const CXXMethodDecl *BaseMD, const CXXMethodDecl *DerivedMD)
static QualType getDecayedType(QualType Type)
std::vector< HeaderHandle > Path
std::string getReturnType(const CodeCompletionString &CCS)
Gets detail to be used as the detail field in an LSP completion item.
static bool checkParamTypes(const CXXMethodDecl *BaseMD, const CXXMethodDecl *DerivedMD)
static bool checkOverridingFunctionReturnType(const ASTContext *Context, const CXXMethodDecl *BaseMD, const CXXMethodDecl *DerivedMD)
Checks whether the return types are covariant, according to C++[class.virtual]p7. ...
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
CharSourceRange Range
SourceRange for the file name.
static bool checkOverrideByDerivedMethod(const CXXMethodDecl *BaseMD, const CXXMethodDecl *DerivedMD)
Check whether BaseMD overrides DerivedMD.