null-deref seen in testing
[LibreOffice.git] / compilerplugins / clang / datamembershadow.cxx
blob93f65de6672642cacabf045c8caa90cefe96f58b
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 #ifndef LO_CLANG_SHARED_PLUGINS
12 #include <string>
13 #include <iostream>
14 #include <map>
15 #include <set>
17 #include "plugin.hxx"
18 #include "config_clang.h"
19 #include "clang/AST/CXXInheritance.h"
21 /**
22 * Check for data member being shadowed.
24 * @TODO check for any members in superclass hierarchy with duplicate names,
25 * regardless of their visibility,
26 * more specific names will make the code easier to read
28 namespace
31 class DataMemberShadow:
32 public loplugin::FilteringPlugin<DataMemberShadow>
34 public:
35 explicit DataMemberShadow(loplugin::InstantiationData const & data):
36 FilteringPlugin(data) {}
38 virtual void run() override {
39 TraverseDecl(compiler.getASTContext().getTranslationUnitDecl());
42 bool VisitFieldDecl(FieldDecl const *);
45 bool DataMemberShadow::VisitFieldDecl(FieldDecl const * fieldDecl)
47 if (ignoreLocation(fieldDecl)) {
48 return true;
50 StringRef aFileName = getFilenameOfLocation(
51 compiler.getSourceManager().getSpellingLoc(fieldDecl->getBeginLoc()));
53 // FIXME complex stuff to fix later
55 if (loplugin::hasPathnamePrefix(aFileName, SRCDIR "/chart2/source/"))
56 return true;
57 if (loplugin::isSamePathname(aFileName, SRCDIR "/include/sfx2/recentdocsview.hxx"))
58 return true;
59 if (loplugin::isSamePathname(aFileName, SRCDIR "/include/sfx2/templatelocalview.hxx"))
60 return true;
61 if (loplugin::isSamePathname(aFileName, SRCDIR "/store/source/stortree.hxx")
62 || loplugin::isSamePathname(aFileName, SRCDIR "/store/source/stordata.hxx"))
63 return true;
64 if (loplugin::isSamePathname(aFileName, SRCDIR "/sw/source/uibase/inc/dbtree.hxx"))
65 return true;
67 const CXXRecordDecl* parentCXXRecordDecl = dyn_cast<CXXRecordDecl>(fieldDecl->getDeclContext());
68 if (!parentCXXRecordDecl) {
69 return true;
72 fieldDecl = fieldDecl->getCanonicalDecl();
74 auto BaseMatchesCallback = [&](const CXXBaseSpecifier *cxxBaseSpecifier, CXXBasePath& Paths)
76 if (!cxxBaseSpecifier->getType().getTypePtr())
77 return false;
78 const CXXRecordDecl* baseCXXRecordDecl = cxxBaseSpecifier->getType()->getAsCXXRecordDecl();
79 if (!baseCXXRecordDecl)
80 return false;
81 if (baseCXXRecordDecl->isInvalidDecl())
82 return false;
83 for (const FieldDecl* baseFieldDecl : baseCXXRecordDecl->fields())
85 // TODO look for overlaps even with private fields
87 if (baseFieldDecl->getAccess() == AS_private
88 || !baseFieldDecl->getDeclName().isIdentifier()
89 || fieldDecl->getName() != baseFieldDecl->getName()) {
90 continue;
92 std::string sPath;
93 for (CXXBasePathElement const & pathElement : Paths) {
94 if (!sPath.empty()) {
95 sPath += "->";
97 sPath += pathElement.Class->getNameAsString();
99 sPath += "->";
100 sPath += baseCXXRecordDecl->getNameAsString();
101 report(DiagnosticsEngine::Warning,
102 "data member %0 is shadowing member in superclass, through inheritance path %1",
103 fieldDecl->getBeginLoc())
104 << fieldDecl->getName()
105 << sPath
106 << fieldDecl->getSourceRange();
107 report(DiagnosticsEngine::Note,
108 "superclass member here",
109 baseFieldDecl->getBeginLoc())
110 << baseFieldDecl->getSourceRange();
112 return false;
115 CXXBasePaths aPaths;
116 parentCXXRecordDecl->lookupInBases(BaseMatchesCallback, aPaths);
117 return true;
120 loplugin::Plugin::Registration< DataMemberShadow > datamembershadow("datamembershadow", true);
124 #endif // LO_CLANG_SHARED_PLUGINS
126 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */