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