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/.
9 #ifndef LO_CLANG_SHARED_PLUGINS
24 class StaticDynamic
: public loplugin::FilteringPlugin
<StaticDynamic
>
27 explicit StaticDynamic(loplugin::InstantiationData
const& data
)
28 : FilteringPlugin(data
)
32 bool preRun() override
{ return compiler
.getLangOpts().CPlusPlus
; }
33 void postRun() override
{}
34 virtual void run() override
37 TraverseDecl(compiler
.getASTContext().getTranslationUnitDecl());
40 bool VisitCXXDynamicCastExpr(CXXDynamicCastExpr
const*);
41 bool VisitCXXStaticCastExpr(CXXStaticCastExpr
const*);
42 bool PreTraverseCompoundStmt(CompoundStmt
*);
43 bool PostTraverseCompoundStmt(CompoundStmt
*, bool);
44 bool TraverseCompoundStmt(CompoundStmt
*);
47 // the key is the pair of VarDecl and the type being cast to.
50 std::map
<std::pair
<VarDecl
const*, clang::Type
const*>, SourceLocation
> staticCastVars
;
51 std::map
<std::pair
<VarDecl
const*, clang::Type
const*>, SourceLocation
> dynamicCastVars
;
53 // only maintain state inside a single basic block, we're not trying to analyse
54 // cross-block interactions.
55 std::vector
<BlockState
> blockStack
;
56 BlockState blockState
;
59 bool StaticDynamic::PreTraverseCompoundStmt(CompoundStmt
*)
61 blockStack
.push_back(std::move(blockState
));
65 bool StaticDynamic::PostTraverseCompoundStmt(CompoundStmt
*, bool)
67 blockState
= std::move(blockStack
.back());
68 blockStack
.pop_back();
72 bool StaticDynamic::TraverseCompoundStmt(CompoundStmt
* compoundStmt
)
75 if (PreTraverseCompoundStmt(compoundStmt
))
77 ret
= FilteringPlugin::TraverseCompoundStmt(compoundStmt
);
78 PostTraverseCompoundStmt(compoundStmt
, ret
);
83 const clang::Type
* strip(QualType qt
)
85 const clang::Type
* varType
= qt
->getUnqualifiedDesugaredType();
86 if (varType
->isPointerType())
87 varType
= varType
->getPointeeType()->getUnqualifiedDesugaredType();
88 if (varType
->isReferenceType())
89 varType
= varType
->getAs
<clang::ReferenceType
>()
91 ->getUnqualifiedDesugaredType();
95 bool StaticDynamic::VisitCXXStaticCastExpr(CXXStaticCastExpr
const* staticCastExpr
)
97 if (ignoreLocation(staticCastExpr
))
99 auto subExprDecl
= dyn_cast
<DeclRefExpr
>(staticCastExpr
->getSubExpr()->IgnoreParenImpCasts());
102 auto varDecl
= dyn_cast_or_null
<VarDecl
>(subExprDecl
->getDecl());
105 auto varType
= strip(staticCastExpr
->getType());
106 auto it
= blockState
.dynamicCastVars
.find({ varDecl
, varType
});
107 if (it
!= blockState
.dynamicCastVars
.end())
109 StringRef fn
= getFilenameOfLocation(
110 compiler
.getSourceManager().getSpellingLoc(compat::getBeginLoc(staticCastExpr
)));
112 if (loplugin::isSamePathname(fn
, SRCDIR
"/basctl/source/basicide/basobj3.cxx"))
114 if (loplugin::isSamePathname(fn
, SRCDIR
"/sw/source/core/doc/swserv.cxx"))
116 if (loplugin::isSamePathname(fn
, SRCDIR
"/sw/source/core/text/txtfly.cxx"))
119 report(DiagnosticsEngine::Warning
, "static_cast after dynamic_cast",
120 compat::getBeginLoc(staticCastExpr
))
121 << staticCastExpr
->getSourceRange();
122 report(DiagnosticsEngine::Note
, "dynamic_cast here", it
->second
);
125 blockState
.staticCastVars
.insert({ { varDecl
, varType
}, compat::getBeginLoc(staticCastExpr
) });
129 bool StaticDynamic::VisitCXXDynamicCastExpr(CXXDynamicCastExpr
const* dynamicCastExpr
)
131 if (ignoreLocation(dynamicCastExpr
))
134 auto subExprDecl
= dyn_cast
<DeclRefExpr
>(dynamicCastExpr
->getSubExpr()->IgnoreParenImpCasts());
137 auto varDecl
= dyn_cast_or_null
<VarDecl
>(subExprDecl
->getDecl());
140 auto varType
= strip(dynamicCastExpr
->getTypeAsWritten());
141 auto it
= blockState
.staticCastVars
.find({ varDecl
, varType
});
142 if (it
!= blockState
.staticCastVars
.end())
144 report(DiagnosticsEngine::Warning
, "dynamic_cast after static_cast",
145 compat::getBeginLoc(dynamicCastExpr
))
146 << dynamicCastExpr
->getSourceRange();
147 report(DiagnosticsEngine::Note
, "static_cast here", it
->second
);
150 auto loc
= compat::getBeginLoc(dynamicCastExpr
);
151 if (compiler
.getSourceManager().isMacroArgExpansion(loc
)
152 && (Lexer::getImmediateMacroNameForDiagnostics(loc
, compiler
.getSourceManager(),
153 compiler
.getLangOpts())
158 blockState
.dynamicCastVars
.insert(
159 { { varDecl
, varType
}, compat::getBeginLoc(dynamicCastExpr
) });
163 loplugin::Plugin::Registration
<StaticDynamic
> staticdynamic("staticdynamic");
166 #endif // LO_CLANG_SHARED_PLUGINS
168 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */