1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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/.
15 #include "clang/AST/CXXInheritance.h"
17 // Check for calls to OutputDevice methods that are not passing through RenderContext
23 public loplugin::FilteringPlugin
<RenderContext
>
26 explicit RenderContext(loplugin::InstantiationData
const & data
):
27 FilteringPlugin(data
) {}
29 virtual void run() override
{
30 TraverseDecl(compiler
.getASTContext().getTranslationUnitDecl());
33 bool TraverseFunctionDecl(const FunctionDecl
* decl
);
35 bool VisitCXXMemberCallExpr(const CXXMemberCallExpr
*);
38 bool mbChecking
= false;
41 // We use Traverse to set a flag so we can easily ignore certain method calls
42 bool RenderContext::TraverseFunctionDecl(const FunctionDecl
* pFunctionDecl
)
44 if (ignoreLocation(pFunctionDecl
)) {
47 if (!pFunctionDecl
->hasBody()) {
50 if ( pFunctionDecl
!= pFunctionDecl
->getCanonicalDecl() ) {
53 // Ignore methods inside the OutputDevice class
54 const CXXMethodDecl
*pCXXMethodDecl
= dyn_cast
<CXXMethodDecl
>(pFunctionDecl
);
56 if (loplugin::TypeCheck(pCXXMethodDecl
->getParent()).Class("OutputDevice").GlobalNamespace())
59 // we are only currently interested in methods where the first parameter is RenderContext
60 if (pFunctionDecl
->getNumParams() == 0)
62 if ( loplugin::TypeCheck(pFunctionDecl
->getParamDecl( 0 )->getType()).Class("RenderContext").GlobalNamespace() ) {
66 TraverseStmt(pFunctionDecl
->getBody());
71 bool RenderContext::VisitCXXMemberCallExpr(const CXXMemberCallExpr
* pCXXMemberCallExpr
)
75 if (ignoreLocation(pCXXMemberCallExpr
)) {
78 const CXXRecordDecl
*pCXXRecordDecl
= pCXXMemberCallExpr
->getRecordDecl();
79 if (!loplugin::TypeCheck(pCXXRecordDecl
).Class("OutputDevice").GlobalNamespace()) {
82 // ignore a handful of methods. They will most probably still be present in Window for use during processing outside of the Paint()
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")
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")
103 // for calling through a reference
104 const DeclRefExpr
*pDeclRefExpr
= dyn_cast
<DeclRefExpr
>(pCXXMemberCallExpr
->getImplicitObjectArgument());
106 QualType aType
= pDeclRefExpr
->getType();
107 std::string t2
= aType
.getAsString();
108 if (t2
== "vcl::RenderContext" || t2
== "const vcl::RenderContext")
111 // for calling through a chain of methods
112 const CXXMemberCallExpr
*pMemberExpr
= dyn_cast
<CXXMemberCallExpr
>(pCXXMemberCallExpr
->getImplicitObjectArgument());
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")
122 DiagnosticsEngine::Warning
,
123 "Should be calling OutputDevice method through RenderContext.",
124 compat::getBeginLoc(pCXXMemberCallExpr
))
125 << pCXXMemberCallExpr
->getSourceRange();
129 loplugin::Plugin::Registration
< RenderContext
> X("rendercontext", false);
133 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */