xref: /aosp_15_r20/external/clang/lib/StaticAnalyzer/Checkers/CheckObjCInstMethSignature.cpp (revision 67e74705e28f6214e480b399dd47ea732279e315)
1*67e74705SXin Li //=- CheckObjCInstMethodRetTy.cpp - Check ObjC method signatures -*- C++ -*-==//
2*67e74705SXin Li //
3*67e74705SXin Li //                     The LLVM Compiler Infrastructure
4*67e74705SXin Li //
5*67e74705SXin Li // This file is distributed under the University of Illinois Open Source
6*67e74705SXin Li // License. See LICENSE.TXT for details.
7*67e74705SXin Li //
8*67e74705SXin Li //===----------------------------------------------------------------------===//
9*67e74705SXin Li //
10*67e74705SXin Li //  This file defines a CheckObjCInstMethSignature, a flow-insenstive check
11*67e74705SXin Li //  that determines if an Objective-C class interface incorrectly redefines
12*67e74705SXin Li //  the method signature in a subclass.
13*67e74705SXin Li //
14*67e74705SXin Li //===----------------------------------------------------------------------===//
15*67e74705SXin Li 
16*67e74705SXin Li #include "ClangSACheckers.h"
17*67e74705SXin Li #include "clang/AST/ASTContext.h"
18*67e74705SXin Li #include "clang/AST/DeclObjC.h"
19*67e74705SXin Li #include "clang/AST/Type.h"
20*67e74705SXin Li #include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
21*67e74705SXin Li #include "clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h"
22*67e74705SXin Li #include "clang/StaticAnalyzer/Core/Checker.h"
23*67e74705SXin Li #include "llvm/ADT/DenseMap.h"
24*67e74705SXin Li #include "llvm/Support/raw_ostream.h"
25*67e74705SXin Li 
26*67e74705SXin Li using namespace clang;
27*67e74705SXin Li using namespace ento;
28*67e74705SXin Li 
AreTypesCompatible(QualType Derived,QualType Ancestor,ASTContext & C)29*67e74705SXin Li static bool AreTypesCompatible(QualType Derived, QualType Ancestor,
30*67e74705SXin Li                                ASTContext &C) {
31*67e74705SXin Li 
32*67e74705SXin Li   // Right now don't compare the compatibility of pointers.  That involves
33*67e74705SXin Li   // looking at subtyping relationships.  FIXME: Future patch.
34*67e74705SXin Li   if (Derived->isAnyPointerType() &&  Ancestor->isAnyPointerType())
35*67e74705SXin Li     return true;
36*67e74705SXin Li 
37*67e74705SXin Li   return C.typesAreCompatible(Derived, Ancestor);
38*67e74705SXin Li }
39*67e74705SXin Li 
CompareReturnTypes(const ObjCMethodDecl * MethDerived,const ObjCMethodDecl * MethAncestor,BugReporter & BR,ASTContext & Ctx,const ObjCImplementationDecl * ID,const CheckerBase * Checker)40*67e74705SXin Li static void CompareReturnTypes(const ObjCMethodDecl *MethDerived,
41*67e74705SXin Li                                const ObjCMethodDecl *MethAncestor,
42*67e74705SXin Li                                BugReporter &BR, ASTContext &Ctx,
43*67e74705SXin Li                                const ObjCImplementationDecl *ID,
44*67e74705SXin Li                                const CheckerBase *Checker) {
45*67e74705SXin Li 
46*67e74705SXin Li   QualType ResDerived = MethDerived->getReturnType();
47*67e74705SXin Li   QualType ResAncestor = MethAncestor->getReturnType();
48*67e74705SXin Li 
49*67e74705SXin Li   if (!AreTypesCompatible(ResDerived, ResAncestor, Ctx)) {
50*67e74705SXin Li     std::string sbuf;
51*67e74705SXin Li     llvm::raw_string_ostream os(sbuf);
52*67e74705SXin Li 
53*67e74705SXin Li     os << "The Objective-C class '"
54*67e74705SXin Li        << *MethDerived->getClassInterface()
55*67e74705SXin Li        << "', which is derived from class '"
56*67e74705SXin Li        << *MethAncestor->getClassInterface()
57*67e74705SXin Li        << "', defines the instance method '";
58*67e74705SXin Li     MethDerived->getSelector().print(os);
59*67e74705SXin Li     os << "' whose return type is '"
60*67e74705SXin Li        << ResDerived.getAsString()
61*67e74705SXin Li        << "'.  A method with the same name (same selector) is also defined in "
62*67e74705SXin Li           "class '"
63*67e74705SXin Li        << *MethAncestor->getClassInterface()
64*67e74705SXin Li        << "' and has a return type of '"
65*67e74705SXin Li        << ResAncestor.getAsString()
66*67e74705SXin Li        << "'.  These two types are incompatible, and may result in undefined "
67*67e74705SXin Li           "behavior for clients of these classes.";
68*67e74705SXin Li 
69*67e74705SXin Li     PathDiagnosticLocation MethDLoc =
70*67e74705SXin Li       PathDiagnosticLocation::createBegin(MethDerived,
71*67e74705SXin Li                                           BR.getSourceManager());
72*67e74705SXin Li 
73*67e74705SXin Li     BR.EmitBasicReport(
74*67e74705SXin Li         MethDerived, Checker, "Incompatible instance method return type",
75*67e74705SXin Li         categories::CoreFoundationObjectiveC, os.str(), MethDLoc);
76*67e74705SXin Li   }
77*67e74705SXin Li }
78*67e74705SXin Li 
CheckObjCInstMethSignature(const ObjCImplementationDecl * ID,BugReporter & BR,const CheckerBase * Checker)79*67e74705SXin Li static void CheckObjCInstMethSignature(const ObjCImplementationDecl *ID,
80*67e74705SXin Li                                        BugReporter &BR,
81*67e74705SXin Li                                        const CheckerBase *Checker) {
82*67e74705SXin Li 
83*67e74705SXin Li   const ObjCInterfaceDecl *D = ID->getClassInterface();
84*67e74705SXin Li   const ObjCInterfaceDecl *C = D->getSuperClass();
85*67e74705SXin Li 
86*67e74705SXin Li   if (!C)
87*67e74705SXin Li     return;
88*67e74705SXin Li 
89*67e74705SXin Li   ASTContext &Ctx = BR.getContext();
90*67e74705SXin Li 
91*67e74705SXin Li   // Build a DenseMap of the methods for quick querying.
92*67e74705SXin Li   typedef llvm::DenseMap<Selector,ObjCMethodDecl*> MapTy;
93*67e74705SXin Li   MapTy IMeths;
94*67e74705SXin Li   unsigned NumMethods = 0;
95*67e74705SXin Li 
96*67e74705SXin Li   for (auto *M : ID->instance_methods()) {
97*67e74705SXin Li     IMeths[M->getSelector()] = M;
98*67e74705SXin Li     ++NumMethods;
99*67e74705SXin Li   }
100*67e74705SXin Li 
101*67e74705SXin Li   // Now recurse the class hierarchy chain looking for methods with the
102*67e74705SXin Li   // same signatures.
103*67e74705SXin Li   while (C && NumMethods) {
104*67e74705SXin Li     for (const auto *M : C->instance_methods()) {
105*67e74705SXin Li       Selector S = M->getSelector();
106*67e74705SXin Li 
107*67e74705SXin Li       MapTy::iterator MI = IMeths.find(S);
108*67e74705SXin Li 
109*67e74705SXin Li       if (MI == IMeths.end() || MI->second == nullptr)
110*67e74705SXin Li         continue;
111*67e74705SXin Li 
112*67e74705SXin Li       --NumMethods;
113*67e74705SXin Li       ObjCMethodDecl *MethDerived = MI->second;
114*67e74705SXin Li       MI->second = nullptr;
115*67e74705SXin Li 
116*67e74705SXin Li       CompareReturnTypes(MethDerived, M, BR, Ctx, ID, Checker);
117*67e74705SXin Li     }
118*67e74705SXin Li 
119*67e74705SXin Li     C = C->getSuperClass();
120*67e74705SXin Li   }
121*67e74705SXin Li }
122*67e74705SXin Li 
123*67e74705SXin Li //===----------------------------------------------------------------------===//
124*67e74705SXin Li // ObjCMethSigsChecker
125*67e74705SXin Li //===----------------------------------------------------------------------===//
126*67e74705SXin Li 
127*67e74705SXin Li namespace {
128*67e74705SXin Li class ObjCMethSigsChecker : public Checker<
129*67e74705SXin Li                                       check::ASTDecl<ObjCImplementationDecl> > {
130*67e74705SXin Li public:
checkASTDecl(const ObjCImplementationDecl * D,AnalysisManager & mgr,BugReporter & BR) const131*67e74705SXin Li   void checkASTDecl(const ObjCImplementationDecl *D, AnalysisManager& mgr,
132*67e74705SXin Li                     BugReporter &BR) const {
133*67e74705SXin Li     CheckObjCInstMethSignature(D, BR, this);
134*67e74705SXin Li   }
135*67e74705SXin Li };
136*67e74705SXin Li }
137*67e74705SXin Li 
registerObjCMethSigsChecker(CheckerManager & mgr)138*67e74705SXin Li void ento::registerObjCMethSigsChecker(CheckerManager &mgr) {
139*67e74705SXin Li   mgr.registerChecker<ObjCMethSigsChecker>();
140*67e74705SXin Li }
141