cid#1607171 Data race condition
[LibreOffice.git] / compilerplugins / clang / store / stdexception.cxx
blob47a7d579118a30b3d817781e9e227312ff690492
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 #include <algorithm>
11 #include <cassert>
12 #include <limits>
13 #include <string>
15 #include "plugin.hxx"
17 namespace {
19 bool isStdException(QualType type) {
20 //TODO:
21 std::string name { type.getAsString() };
22 return name == "std::exception" || name == "::std::exception";
25 class StdException:
26 public loplugin::FilteringRewritePlugin<StdException>
28 public:
29 explicit StdException(InstantiationData const & data): FilteringRewritePlugin(data)
32 virtual void run() override
33 { TraverseDecl(compiler.getASTContext().getTranslationUnitDecl()); }
35 bool VisitCXXMethodDecl(CXXMethodDecl const * decl);
38 bool StdException::VisitCXXMethodDecl(CXXMethodDecl const * decl) {
39 if (ignoreLocation(decl)
40 || decl->begin_overridden_methods() == decl->end_overridden_methods())
42 return true;
44 CXXMethodDecl const * over = nullptr;
45 for (auto i = decl->begin_overridden_methods();
46 i != decl->end_overridden_methods(); ++i)
48 FunctionProtoType const * t
49 = (*i)->getType()->getAs<FunctionProtoType>();
50 switch (t->getExceptionSpecType()) {
51 case EST_None:
52 continue;
53 case EST_DynamicNone:
54 case EST_BasicNoexcept:
55 return true;
56 case EST_Dynamic:
58 unsigned n = t->getNumExceptions();
59 for (unsigned j = 0; j != n; ++j) {
60 if (isStdException(t->getExceptionType(j))) {
61 over = *i;
62 goto found;
65 return true;
67 case EST_ComputedNoexcept:
68 switch (t->getNoexceptSpec(compiler.getASTContext())) {
69 case FunctionProtoType::NR_NoNoexcept:
70 case FunctionProtoType::NR_BadNoexcept:
71 assert(false);
72 // fall through
73 case FunctionProtoType::NR_Dependent:
74 break;
75 case FunctionProtoType::NR_Throw:
76 continue;
77 case FunctionProtoType::NR_Nothrow:
78 return true;
80 case EST_MSAny:
81 case EST_Unevaluated:
82 case EST_Uninstantiated:
83 continue; //TODO???
86 return true;
87 found:
88 FunctionProtoType const * t = decl->getType()->getAs<FunctionProtoType>();
89 if (!t->hasDynamicExceptionSpec()) {
90 report(
91 DiagnosticsEngine::Warning,
92 "override does not have dynamic exception specification",
93 decl->getLocStart())
94 << decl->getSourceRange();
95 report(
96 DiagnosticsEngine::Note,
97 ("overridden declaration with dynamic exception specification"
98 " including std::exception is here"),
99 over->getLocStart());
100 return true;
102 unsigned n = t->getNumExceptions();
103 for (unsigned i = 0; i != n; ++i) {
104 if (isStdException(t->getExceptionType(i))) {
105 return true;
108 SourceRange r { decl->getSourceRange() };
109 SourceLocation l {
110 compiler.getSourceManager().getExpansionLoc(r.getBegin()) };
111 SourceLocation end {
112 compiler.getSourceManager().getExpansionLoc(r.getEnd()) };
113 assert(
114 l == end
115 || compiler.getSourceManager().isBeforeInTranslationUnit(l, end));
116 bool seenThrow = false;
117 unsigned parens = 0;
118 SourceLocation openParen;
119 SourceLocation loc;
120 for (;;) {
121 unsigned n = Lexer::MeasureTokenLength(
122 l, compiler.getSourceManager(), compiler.getLangOpts());
123 std::string s { compiler.getSourceManager().getCharacterData(l), n };
124 if (s == "{" || s == ";") {
125 break;
127 if (!seenThrow) {
128 if (s == "throw") {
129 seenThrow = true;
131 } else if (s == "(") {
132 assert(parens < std::numeric_limits<unsigned>::max());
133 ++parens;
134 if (parens == 1) {
135 openParen = l;
137 loc = l;
138 } else if (s == ")") {
139 assert(parens != 0);
140 --parens;
141 if (parens == 0) {
142 assert(loc.isValid());
143 // Only rewrite declarations in include files if a definition is
144 // also seen, to avoid compilation of a definition (in a main
145 // file only processed later) to fail with a "mismatch" error
146 // before the rewriter had a chance to act upon the definition
147 // (but use the heuristic of assuming pure virtual functions do
148 // not have definitions):
149 if (rewriter != nullptr
150 && (compiler.getSourceManager().isInMainFile(
151 compiler.getSourceManager().getSpellingLoc(loc))
152 || decl->isDefined() || decl->isPure())
153 && insertTextAfterToken(
154 loc,
155 (loc == openParen
156 ? "std::exception" : ", std::exception")))
158 return true;
160 break;
162 loc = l;
163 } else if (!s.empty() && s.compare(0, 2, "/*") != 0
164 && s.compare(0, 2, "//") != 0)
166 loc = l;
168 if (l == end) {
169 break;
171 l = l.getLocWithOffset(std::max<unsigned>(n, 1));
173 report(
174 DiagnosticsEngine::Warning,
175 "override dropped std::exception from dynamic exception specification",
176 openParen.isValid() ? openParen : decl->getLocStart())
177 << decl->getSourceRange();
178 report(
179 DiagnosticsEngine::Note, "overridden declaration is here",
180 over->getLocStart());
181 return true;
184 loplugin::Plugin::Registration<StdException> X("stdexception", true);
188 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */