12ce6352eSYafei Liu //===- AnnotateFunctions.cpp ----------------------------------------------===// 22ce6352eSYafei Liu // 32ce6352eSYafei Liu // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 42ce6352eSYafei Liu // See https://llvm.org/LICENSE.txt for license information. 52ce6352eSYafei Liu // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 62ce6352eSYafei Liu // 72ce6352eSYafei Liu //===----------------------------------------------------------------------===// 82ce6352eSYafei Liu // 92ce6352eSYafei Liu // Attribute plugin to mark a virtual method as ``call_super``, subclasses must 102ce6352eSYafei Liu // call it in the overridden method. 112ce6352eSYafei Liu // 122ce6352eSYafei Liu // This example shows that attribute plugins combined with ``PluginASTAction`` 132ce6352eSYafei Liu // in Clang can do some of the same things which Java Annotations do. 142ce6352eSYafei Liu // 152ce6352eSYafei Liu // Unlike the other attribute plugin examples, this one does not attach an 162ce6352eSYafei Liu // attribute AST node to the declaration AST node. Instead, it keeps a separate 172ce6352eSYafei Liu // list of attributed declarations, which may be faster than using 182ce6352eSYafei Liu // ``Decl::getAttr<T>()`` in some cases. The disadvantage of this approach is 192ce6352eSYafei Liu // that the attribute is not part of the AST, which means that dumping the AST 202ce6352eSYafei Liu // will lose the attribute information, pretty printing the AST won't write the 212ce6352eSYafei Liu // attribute back out to source, and AST matchers will not be able to match 222ce6352eSYafei Liu // against the attribute on the declaration. 232ce6352eSYafei Liu // 242ce6352eSYafei Liu //===----------------------------------------------------------------------===// 252ce6352eSYafei Liu 262ce6352eSYafei Liu #include "clang/AST/ASTContext.h" 272ce6352eSYafei Liu #include "clang/AST/Attr.h" 282ce6352eSYafei Liu #include "clang/AST/RecursiveASTVisitor.h" 292ce6352eSYafei Liu #include "clang/Frontend/FrontendPluginRegistry.h" 302ce6352eSYafei Liu #include "clang/Sema/ParsedAttr.h" 312ce6352eSYafei Liu #include "clang/Sema/Sema.h" 322ce6352eSYafei Liu #include "clang/Sema/SemaDiagnostic.h" 332ce6352eSYafei Liu #include "llvm/ADT/SmallPtrSet.h" 342ce6352eSYafei Liu using namespace clang; 352ce6352eSYafei Liu 362ce6352eSYafei Liu namespace { 372ce6352eSYafei Liu // Cached methods which are marked as 'call_super'. 382ce6352eSYafei Liu llvm::SmallPtrSet<const CXXMethodDecl *, 16> MarkedMethods; 392ce6352eSYafei Liu bool isMarkedAsCallSuper(const CXXMethodDecl *D) { 402ce6352eSYafei Liu // Uses this way to avoid add an annotation attr to the AST. 412ce6352eSYafei Liu return MarkedMethods.contains(D); 422ce6352eSYafei Liu } 432ce6352eSYafei Liu 442ce6352eSYafei Liu class MethodUsageVisitor : public RecursiveASTVisitor<MethodUsageVisitor> { 452ce6352eSYafei Liu public: 462ce6352eSYafei Liu bool IsOverriddenUsed = false; 472ce6352eSYafei Liu explicit MethodUsageVisitor( 482ce6352eSYafei Liu llvm::SmallPtrSet<const CXXMethodDecl *, 16> &MustCalledMethods) 492ce6352eSYafei Liu : MustCalledMethods(MustCalledMethods) {} 502ce6352eSYafei Liu bool VisitCallExpr(CallExpr *CallExpr) { 512ce6352eSYafei Liu const CXXMethodDecl *Callee = nullptr; 522ce6352eSYafei Liu for (const auto &MustCalled : MustCalledMethods) { 532ce6352eSYafei Liu if (CallExpr->getCalleeDecl() == MustCalled) { 542ce6352eSYafei Liu // Super is called. 552ce6352eSYafei Liu // Notice that we cannot do delete or insert in the iteration 562ce6352eSYafei Liu // when using SmallPtrSet. 572ce6352eSYafei Liu Callee = MustCalled; 582ce6352eSYafei Liu } 592ce6352eSYafei Liu } 602ce6352eSYafei Liu if (Callee) 612ce6352eSYafei Liu MustCalledMethods.erase(Callee); 622ce6352eSYafei Liu 632ce6352eSYafei Liu return true; 642ce6352eSYafei Liu } 652ce6352eSYafei Liu 662ce6352eSYafei Liu private: 672ce6352eSYafei Liu llvm::SmallPtrSet<const CXXMethodDecl *, 16> &MustCalledMethods; 682ce6352eSYafei Liu }; 692ce6352eSYafei Liu 702ce6352eSYafei Liu class CallSuperVisitor : public RecursiveASTVisitor<CallSuperVisitor> { 712ce6352eSYafei Liu public: 722ce6352eSYafei Liu CallSuperVisitor(DiagnosticsEngine &Diags) : Diags(Diags) { 732ce6352eSYafei Liu WarningSuperNotCalled = Diags.getCustomDiagID( 742ce6352eSYafei Liu DiagnosticsEngine::Warning, 752ce6352eSYafei Liu "virtual function %q0 is marked as 'call_super' but this overriding " 762ce6352eSYafei Liu "method does not call the base version"); 772ce6352eSYafei Liu NotePreviousCallSuperDeclaration = Diags.getCustomDiagID( 782ce6352eSYafei Liu DiagnosticsEngine::Note, "function marked 'call_super' here"); 792ce6352eSYafei Liu } 802ce6352eSYafei Liu bool VisitCXXMethodDecl(CXXMethodDecl *MethodDecl) { 812ce6352eSYafei Liu if (MethodDecl->isThisDeclarationADefinition() && MethodDecl->hasBody()) { 822ce6352eSYafei Liu // First find out which overridden methods are marked as 'call_super' 832ce6352eSYafei Liu llvm::SmallPtrSet<const CXXMethodDecl *, 16> OverriddenMarkedMethods; 842ce6352eSYafei Liu for (const auto *Overridden : MethodDecl->overridden_methods()) { 852ce6352eSYafei Liu if (isMarkedAsCallSuper(Overridden)) { 862ce6352eSYafei Liu OverriddenMarkedMethods.insert(Overridden); 872ce6352eSYafei Liu } 882ce6352eSYafei Liu } 892ce6352eSYafei Liu 902ce6352eSYafei Liu // Now find if the superclass method is called in `MethodDecl`. 912ce6352eSYafei Liu MethodUsageVisitor Visitor(OverriddenMarkedMethods); 922ce6352eSYafei Liu Visitor.TraverseDecl(MethodDecl); 932ce6352eSYafei Liu // After traversing, all methods left in `OverriddenMarkedMethods` 942ce6352eSYafei Liu // are not called, warn about these. 952ce6352eSYafei Liu for (const auto &LeftOverriddens : OverriddenMarkedMethods) { 962ce6352eSYafei Liu Diags.Report(MethodDecl->getLocation(), WarningSuperNotCalled) 972ce6352eSYafei Liu << LeftOverriddens << MethodDecl; 982ce6352eSYafei Liu Diags.Report(LeftOverriddens->getLocation(), 992ce6352eSYafei Liu NotePreviousCallSuperDeclaration); 1002ce6352eSYafei Liu } 1012ce6352eSYafei Liu } 1022ce6352eSYafei Liu return true; 1032ce6352eSYafei Liu } 1042ce6352eSYafei Liu 1052ce6352eSYafei Liu private: 1062ce6352eSYafei Liu DiagnosticsEngine &Diags; 1072ce6352eSYafei Liu unsigned WarningSuperNotCalled; 1082ce6352eSYafei Liu unsigned NotePreviousCallSuperDeclaration; 1092ce6352eSYafei Liu }; 1102ce6352eSYafei Liu 1112ce6352eSYafei Liu class CallSuperConsumer : public ASTConsumer { 1122ce6352eSYafei Liu public: 1132ce6352eSYafei Liu void HandleTranslationUnit(ASTContext &Context) override { 1142ce6352eSYafei Liu auto &Diags = Context.getDiagnostics(); 1152ce6352eSYafei Liu for (const auto *Method : MarkedMethods) { 1162ce6352eSYafei Liu lateDiagAppertainsToDecl(Diags, Method); 1172ce6352eSYafei Liu } 1182ce6352eSYafei Liu 1192ce6352eSYafei Liu CallSuperVisitor Visitor(Context.getDiagnostics()); 1202ce6352eSYafei Liu Visitor.TraverseDecl(Context.getTranslationUnitDecl()); 1212ce6352eSYafei Liu } 1222ce6352eSYafei Liu 1232ce6352eSYafei Liu private: 1242ce6352eSYafei Liu // This function does checks which cannot be done in `diagAppertainsToDecl()`, 1252ce6352eSYafei Liu // typical example is checking Attributes (such as `FinalAttr`), on the time 1262ce6352eSYafei Liu // when `diagAppertainsToDecl()` is called, `FinalAttr` is not added into 1272ce6352eSYafei Liu // the AST yet. 1282ce6352eSYafei Liu void lateDiagAppertainsToDecl(DiagnosticsEngine &Diags, 1292ce6352eSYafei Liu const CXXMethodDecl *MethodDecl) { 1302ce6352eSYafei Liu if (MethodDecl->hasAttr<FinalAttr>()) { 1312ce6352eSYafei Liu unsigned ID = Diags.getCustomDiagID( 1322ce6352eSYafei Liu DiagnosticsEngine::Warning, 1332ce6352eSYafei Liu "'call_super' attribute marked on a final method"); 1342ce6352eSYafei Liu Diags.Report(MethodDecl->getLocation(), ID); 1352ce6352eSYafei Liu } 1362ce6352eSYafei Liu } 1372ce6352eSYafei Liu }; 1382ce6352eSYafei Liu 1392ce6352eSYafei Liu class CallSuperAction : public PluginASTAction { 1402ce6352eSYafei Liu public: 1412ce6352eSYafei Liu std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI, 1422ce6352eSYafei Liu llvm::StringRef) override { 1432ce6352eSYafei Liu return std::make_unique<CallSuperConsumer>(); 1442ce6352eSYafei Liu } 1452ce6352eSYafei Liu 1462ce6352eSYafei Liu bool ParseArgs(const CompilerInstance &CI, 1472ce6352eSYafei Liu const std::vector<std::string> &args) override { 1483e67cf21STimm Bäder if (!args.empty() && args[0] == "help") 1493e67cf21STimm Bäder llvm::errs() << "Help for the CallSuperAttr plugin goes here\n"; 1502ce6352eSYafei Liu return true; 1512ce6352eSYafei Liu } 1522ce6352eSYafei Liu 1532ce6352eSYafei Liu PluginASTAction::ActionType getActionType() override { 1542ce6352eSYafei Liu return AddBeforeMainAction; 1552ce6352eSYafei Liu } 1562ce6352eSYafei Liu }; 1572ce6352eSYafei Liu 1582ce6352eSYafei Liu struct CallSuperAttrInfo : public ParsedAttrInfo { 1592ce6352eSYafei Liu CallSuperAttrInfo() { 1602ce6352eSYafei Liu OptArgs = 0; 1612ce6352eSYafei Liu static constexpr Spelling S[] = { 1622ce6352eSYafei Liu {ParsedAttr::AS_GNU, "call_super"}, 1632ce6352eSYafei Liu {ParsedAttr::AS_CXX11, "clang::call_super"}}; 1642ce6352eSYafei Liu Spellings = S; 1652ce6352eSYafei Liu } 1662ce6352eSYafei Liu 1672ce6352eSYafei Liu bool diagAppertainsToDecl(Sema &S, const ParsedAttr &Attr, 1682ce6352eSYafei Liu const Decl *D) const override { 1692ce6352eSYafei Liu const auto *TheMethod = dyn_cast_or_null<CXXMethodDecl>(D); 1702ce6352eSYafei Liu if (!TheMethod || !TheMethod->isVirtual()) { 171*41a94de7SMaksim Ivanov S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) 172*41a94de7SMaksim Ivanov << Attr << Attr.isRegularKeywordAttribute() 173*41a94de7SMaksim Ivanov << ExpectedVirtualFunction; 1742ce6352eSYafei Liu return false; 1752ce6352eSYafei Liu } 1762ce6352eSYafei Liu MarkedMethods.insert(TheMethod); 1772ce6352eSYafei Liu return true; 1782ce6352eSYafei Liu } 1792ce6352eSYafei Liu AttrHandling handleDeclAttribute(Sema &S, Decl *D, 1802ce6352eSYafei Liu const ParsedAttr &Attr) const override { 1812ce6352eSYafei Liu // No need to add an attr object (usually an `AnnotateAttr` is added). 1822ce6352eSYafei Liu // Save the address of the Decl in a set, it maybe faster than compare to 1832ce6352eSYafei Liu // strings. 1842ce6352eSYafei Liu return AttributeNotApplied; 1852ce6352eSYafei Liu } 1862ce6352eSYafei Liu }; 1872ce6352eSYafei Liu 1882ce6352eSYafei Liu } // namespace 1892ce6352eSYafei Liu static FrontendPluginRegistry::Add<CallSuperAction> 1902ce6352eSYafei Liu X("call_super_plugin", "clang plugin, checks every overridden virtual " 1912ce6352eSYafei Liu "function whether called this function or not."); 1922ce6352eSYafei Liu static ParsedAttrInfoRegistry::Add<CallSuperAttrInfo> 1932ce6352eSYafei Liu Y("call_super_attr", "Attr plugin to define 'call_super' attribute"); 194