bump product version to 5.0.4.1
[LibreOffice.git] / compilerplugins / clang / store / stdexception.cxx
blob3f93b27927f83099a582115b21c79536c709d022
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 RecursiveASTVisitor<StdException>, public loplugin::RewritePlugin
28 public:
29 explicit StdException(InstantiationData const & data): RewritePlugin(data)
32 virtual void run() override
33 { TraverseDecl(compiler.getASTContext().getTranslationUnitDecl()); }
35 bool VisitCXXMethodDecl(CXXMethodDecl const * decl);
37 private:
38 bool isInMainFile(SourceLocation spellingLocation) const;
41 bool StdException::VisitCXXMethodDecl(CXXMethodDecl const * decl) {
42 if (ignoreLocation(decl)
43 || decl->begin_overridden_methods() == decl->end_overridden_methods())
45 return true;
47 CXXMethodDecl const * over = nullptr;
48 for (auto i = decl->begin_overridden_methods();
49 i != decl->end_overridden_methods(); ++i)
51 FunctionProtoType const * t
52 = (*i)->getType()->getAs<FunctionProtoType>();
53 switch (t->getExceptionSpecType()) {
54 case EST_None:
55 continue;
56 case EST_DynamicNone:
57 case EST_BasicNoexcept:
58 return true;
59 case EST_Dynamic:
61 unsigned n = t->getNumExceptions();
62 for (unsigned j = 0; j != n; ++j) {
63 if (isStdException(t->getExceptionType(j))) {
64 over = *i;
65 goto found;
68 return true;
70 case EST_ComputedNoexcept:
71 switch (t->getNoexceptSpec(compiler.getASTContext())) {
72 case FunctionProtoType::NR_NoNoexcept:
73 case FunctionProtoType::NR_BadNoexcept:
74 assert(false);
75 // fall through
76 case FunctionProtoType::NR_Dependent:
77 break;
78 case FunctionProtoType::NR_Throw:
79 continue;
80 case FunctionProtoType::NR_Nothrow:
81 return true;
83 case EST_MSAny:
84 case EST_Unevaluated:
85 case EST_Uninstantiated:
86 continue; //TODO???
89 return true;
90 found:
91 FunctionProtoType const * t = decl->getType()->getAs<FunctionProtoType>();
92 if (!t->hasDynamicExceptionSpec()) {
93 report(
94 DiagnosticsEngine::Warning,
95 "override does not have dynamic exception specification",
96 decl->getLocStart())
97 << decl->getSourceRange();
98 report(
99 DiagnosticsEngine::Note,
100 ("overridden declaration with dynamic exception specification"
101 " including std::exception is here"),
102 over->getLocStart());
103 return true;
105 unsigned n = t->getNumExceptions();
106 for (unsigned i = 0; i != n; ++i) {
107 if (isStdException(t->getExceptionType(i))) {
108 return true;
111 SourceRange r { decl->getSourceRange() };
112 SourceLocation l {
113 compiler.getSourceManager().getExpansionLoc(r.getBegin()) };
114 SourceLocation end {
115 compiler.getSourceManager().getExpansionLoc(r.getEnd()) };
116 assert(
117 l == end
118 || compiler.getSourceManager().isBeforeInTranslationUnit(l, end));
119 bool seenThrow = false;
120 unsigned parens = 0;
121 SourceLocation openParen;
122 SourceLocation loc;
123 for (;;) {
124 unsigned n = Lexer::MeasureTokenLength(
125 l, compiler.getSourceManager(), compiler.getLangOpts());
126 std::string s { compiler.getSourceManager().getCharacterData(l), n };
127 if (s == "{" || s == ";") {
128 break;
130 if (!seenThrow) {
131 if (s == "throw") {
132 seenThrow = true;
134 } else if (s == "(") {
135 assert(parens < std::numeric_limits<unsigned>::max());
136 ++parens;
137 if (parens == 1) {
138 openParen = l;
140 loc = l;
141 } else if (s == ")") {
142 assert(parens != 0);
143 --parens;
144 if (parens == 0) {
145 assert(loc.isValid());
146 // Only rewrite declarations in include files if a definition is
147 // also seen, to avoid compilation of a definition (in a main
148 // file only processed later) to fail with a "mismatch" error
149 // before the rewriter had a chance to act upon the definition
150 // (but use the heuristic of assuming pure virtual functions do
151 // not have definitions):
152 if (rewriter != nullptr
153 && (isInMainFile(
154 compiler.getSourceManager().getSpellingLoc(loc))
155 || decl->isDefined() || decl->isPure())
156 && insertTextAfterToken(
157 loc,
158 (loc == openParen
159 ? "std::exception" : ", std::exception")))
161 return true;
163 break;
165 loc = l;
166 } else if (!s.empty() && s.compare(0, 2, "/*") != 0
167 && s.compare(0, 2, "//") != 0)
169 loc = l;
171 if (l == end) {
172 break;
174 l = l.getLocWithOffset(std::max<unsigned>(n, 1));
176 report(
177 DiagnosticsEngine::Warning,
178 "override dropped std::exception from dynamic exception specification",
179 openParen.isValid() ? openParen : decl->getLocStart())
180 << decl->getSourceRange();
181 report(
182 DiagnosticsEngine::Note, "overridden declaration is here",
183 over->getLocStart());
184 return true;
187 bool StdException::isInMainFile(SourceLocation spellingLocation) const {
188 #if (__clang_major__ == 3 && __clang_minor__ >= 4) || __clang_major__ > 3
189 return compiler.getSourceManager().isInMainFile(spellingLocation);
190 #else
191 return compiler.getSourceManager().isFromMainFile(spellingLocation);
192 #endif
195 loplugin::Plugin::Registration<StdException> X("stdexception", true);
199 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */