cURL: follow redirects
[LibreOffice.git] / compilerplugins / clang / rendercontext.cxx
blobe3d1da40ae1ebb76e9583352f4a6ef3112eea479
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 */
10 #include <string>
11 #include <iostream>
13 #include "plugin.hxx"
14 #include "clang/AST/CXXInheritance.h"
16 // Check for calls to OutputDevice methods that are not passing through RenderContext
18 namespace
21 class RenderContext:
22 public RecursiveASTVisitor<RenderContext>, public loplugin::Plugin
24 public:
25 explicit RenderContext(InstantiationData const & data): Plugin(data) {}
27 virtual void run() override {
28 TraverseDecl(compiler.getASTContext().getTranslationUnitDecl());
31 bool TraverseFunctionDecl(const FunctionDecl * decl);
33 bool VisitCXXMemberCallExpr(const CXXMemberCallExpr *);
35 private:
36 bool mbChecking = false;
39 // We use Traverse to set a flag so we can easily ignore certain method calls
40 bool RenderContext::TraverseFunctionDecl(const FunctionDecl * pFunctionDecl)
42 if (ignoreLocation(pFunctionDecl)) {
43 return true;
45 if (!pFunctionDecl->hasBody()) {
46 return true;
48 if ( pFunctionDecl != pFunctionDecl->getCanonicalDecl() ) {
49 return true;
51 // Ignore methods inside the OutputDevice class
52 const CXXMethodDecl *pCXXMethodDecl = dyn_cast<CXXMethodDecl>(pFunctionDecl);
53 if (pCXXMethodDecl) {
54 std::string aParentName = pCXXMethodDecl->getParent()->getQualifiedNameAsString();
55 if (aParentName == "OutputDevice")
56 return true;
58 // we are only currently interested in methods where the first parameter is RenderContext
59 if (pFunctionDecl->getNumParams() == 0)
60 return true;
61 string arg0 = pFunctionDecl->getParamDecl( 0 )->getType().getAsString();
62 if ( arg0.find("RenderContext") != std::string::npos ) {
63 return true;
65 mbChecking = true;
66 TraverseStmt(pFunctionDecl->getBody());
67 mbChecking = false;
68 return true;
71 bool RenderContext::VisitCXXMemberCallExpr(const CXXMemberCallExpr* pCXXMemberCallExpr)
73 if (!mbChecking)
74 return true;
75 if (ignoreLocation(pCXXMemberCallExpr)) {
76 return true;
78 const CXXRecordDecl *pCXXRecordDecl = pCXXMemberCallExpr->getRecordDecl();
79 if (pCXXRecordDecl->getQualifiedNameAsString() != "OutputDevice") {
80 return true;
82 // ignore a handful of methods. They will most probably still be present in Window for use during processing outside of the Paint()
83 // method lifecycle
84 const CXXMethodDecl *pCXXMethodDecl = pCXXMemberCallExpr->getMethodDecl();
85 if (pCXXMethodDecl->isInstance()) {
86 StringRef name = pCXXMethodDecl->getName();
87 if (name == "LogicToPixel" || name == "GetMapMode" || name == "GetFontMetric" || name == "LogicToLogic"
88 || name == "PixelToLogic" || name == "SetDigitLanguage")
90 return true;
93 // for calling through a pointer
94 const ImplicitCastExpr *pImplicitCastExpr = dyn_cast<ImplicitCastExpr>(pCXXMemberCallExpr->getImplicitObjectArgument());
95 if (pImplicitCastExpr) {
96 QualType aType = pImplicitCastExpr->getSubExpr()->getType();
97 if (aType->isPointerType())
98 aType = aType->getPointeeType();
99 std::string t2 = aType.getAsString();
100 if (t2 == "vcl::RenderContext" || t2 == "const vcl::RenderContext")
101 return true;
103 // for calling through a reference
104 const DeclRefExpr *pDeclRefExpr = dyn_cast<DeclRefExpr>(pCXXMemberCallExpr->getImplicitObjectArgument());
105 if (pDeclRefExpr) {
106 QualType aType = pDeclRefExpr->getType();
107 std::string t2 = aType.getAsString();
108 if (t2 == "vcl::RenderContext" || t2 == "const vcl::RenderContext")
109 return true;
111 // for calling through a chain of methods
112 const CXXMemberCallExpr *pMemberExpr = dyn_cast<CXXMemberCallExpr>(pCXXMemberCallExpr->getImplicitObjectArgument());
113 if (pMemberExpr) {
114 QualType aType = pMemberExpr->getType();
115 if (aType->isPointerType())
116 aType = aType->getPointeeType();
117 std::string t2 = aType.getAsString();
118 if (t2 == "vcl::RenderContext" || t2 == "const vcl::RenderContext")
119 return true;
121 report(
122 DiagnosticsEngine::Warning,
123 "Should be calling OutputDevice method through RenderContext.",
124 pCXXMemberCallExpr->getLocStart())
125 << pCXXMemberCallExpr->getSourceRange();
126 return true;
129 loplugin::Plugin::Registration< RenderContext > X("rendercontext", false);
133 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */