LanguageTool: don't crash if REST protocol isn't set
[LibreOffice.git] / compilerplugins / clang / staticdynamic.cxx
blob7f3d2bd49aed495a2a1f3c09c20738f763d567ef
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 */
9 #ifndef LO_CLANG_SHARED_PLUGINS
11 #include <cassert>
12 #include <string>
13 #include <iostream>
14 #include <fstream>
15 #include <map>
16 #include <vector>
18 #include "compat.hxx"
19 #include "check.hxx"
20 #include "plugin.hxx"
22 namespace
24 class StaticDynamic : public loplugin::FilteringPlugin<StaticDynamic>
26 public:
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
36 if (preRun())
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*);
46 private:
47 // the key is the pair of VarDecl and the type being cast to.
48 struct BlockState
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));
62 return true;
65 bool StaticDynamic::PostTraverseCompoundStmt(CompoundStmt*, bool)
67 blockState = std::move(blockStack.back());
68 blockStack.pop_back();
69 return true;
72 bool StaticDynamic::TraverseCompoundStmt(CompoundStmt* compoundStmt)
74 bool ret = true;
75 if (PreTraverseCompoundStmt(compoundStmt))
77 ret = FilteringPlugin::TraverseCompoundStmt(compoundStmt);
78 PostTraverseCompoundStmt(compoundStmt, ret);
80 return 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>()
90 ->getPointeeType()
91 ->getUnqualifiedDesugaredType();
92 return varType;
95 bool StaticDynamic::VisitCXXStaticCastExpr(CXXStaticCastExpr const* staticCastExpr)
97 if (ignoreLocation(staticCastExpr))
98 return true;
99 auto subExprDecl = dyn_cast<DeclRefExpr>(staticCastExpr->getSubExpr()->IgnoreParenImpCasts());
100 if (!subExprDecl)
101 return true;
102 auto varDecl = dyn_cast_or_null<VarDecl>(subExprDecl->getDecl());
103 if (!varDecl)
104 return true;
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)));
111 // loop
112 if (loplugin::isSamePathname(fn, SRCDIR "/basctl/source/basicide/basobj3.cxx"))
113 return true;
114 if (loplugin::isSamePathname(fn, SRCDIR "/sw/source/core/doc/swserv.cxx"))
115 return true;
116 if (loplugin::isSamePathname(fn, SRCDIR "/sw/source/core/text/txtfly.cxx"))
117 return true;
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);
123 return true;
125 blockState.staticCastVars.insert({ { varDecl, varType }, compat::getBeginLoc(staticCastExpr) });
126 return true;
129 bool StaticDynamic::VisitCXXDynamicCastExpr(CXXDynamicCastExpr const* dynamicCastExpr)
131 if (ignoreLocation(dynamicCastExpr))
132 return true;
134 auto subExprDecl = dyn_cast<DeclRefExpr>(dynamicCastExpr->getSubExpr()->IgnoreParenImpCasts());
135 if (!subExprDecl)
136 return true;
137 auto varDecl = dyn_cast_or_null<VarDecl>(subExprDecl->getDecl());
138 if (!varDecl)
139 return true;
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);
148 return true;
150 auto loc = compat::getBeginLoc(dynamicCastExpr);
151 if (compiler.getSourceManager().isMacroArgExpansion(loc)
152 && (Lexer::getImmediateMacroNameForDiagnostics(loc, compiler.getSourceManager(),
153 compiler.getLangOpts())
154 == "assert"))
156 return true;
158 blockState.dynamicCastVars.insert(
159 { { varDecl, varType }, compat::getBeginLoc(dynamicCastExpr) });
160 return true;
163 loplugin::Plugin::Registration<StaticDynamic> staticdynamic("staticdynamic");
166 #endif // LO_CLANG_SHARED_PLUGINS
168 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */