1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
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
14 #include "clang/AST/Comment.h"
19 // Remove dynamic exception specifications. See the mail thread starting at
20 // <https://lists.freedesktop.org/archives/libreoffice/2017-January/076665.html>
21 // "Dynamic Exception Specifications" for details.
25 bool isOverriding(FunctionDecl
const * decl
) {
26 if (decl
->hasAttr
<OverrideAttr
>()) {
29 auto m
= dyn_cast
<CXXMethodDecl
>(decl
);
31 && m
->begin_overridden_methods() != m
->end_overridden_methods();
34 bool isDtorOrDealloc(FunctionDecl
const * decl
) {
35 if (isa
<CXXDestructorDecl
>(decl
)) {
38 switch (decl
->getOverloadedOperator()) {
48 public loplugin::FilteringRewritePlugin
<DynExcSpec
>
51 explicit DynExcSpec(loplugin::InstantiationData
const & data
):
52 FilteringRewritePlugin(data
) {}
54 bool preRun() override
{
55 return compiler
.getLangOpts().CPlusPlus
;
60 TraverseDecl(compiler
.getASTContext().getTranslationUnitDecl());
64 bool VisitFunctionDecl(FunctionDecl
const * decl
) {
65 if (ignoreLocation(decl
)) {
68 auto proto
= decl
->getType()->getAs
<FunctionProtoType
>();
69 if (proto
== nullptr || proto
->getExceptionSpecType() != EST_Dynamic
) {
72 if (decl
->isCanonicalDecl() && !isOverriding(decl
)
73 && !anyRedeclHasThrowsDocumentation(decl
))
76 DiagnosticsEngine::Warning
,
77 ("function declaration has dynamic exception specification but"
78 " no corresponding documentation comment"),
80 << decl
->getSourceRange();
82 if (rewriter
!= nullptr) {
83 if (!(decl
->isDefined() || compat::isPureVirtual(decl
))) {
86 if (auto m
= dyn_cast
<CXXMethodDecl
>(decl
)) {
87 for (auto i
= m
->begin_overridden_methods();
88 i
!= m
->end_overridden_methods(); ++i
)
90 auto proto2
= (*i
)->getType()->getAs
<FunctionProtoType
>();
91 assert(proto2
!= nullptr);
92 if (proto2
->getExceptionSpecType() == EST_Dynamic
) {
98 bool dtorOrDealloc
= isDtorOrDealloc(decl
);
99 auto const source
= decl
->getExceptionSpecSourceRange();
100 if (rewriter
!= nullptr && source
.isValid()) {
102 if (replaceText(source
, "noexcept(false)")) {
106 auto beg
= source
.getBegin();
107 if (beg
.isFileID()) {
109 auto prev
= Lexer::GetBeginningOfToken(
110 beg
.getLocWithOffset(-1),
111 compiler
.getSourceManager(),
112 compiler
.getLangOpts());
113 auto n
= Lexer::MeasureTokenLength(
114 prev
, compiler
.getSourceManager(),
115 compiler
.getLangOpts());
117 compiler
.getSourceManager().getCharacterData(prev
),
119 while (compat::starts_with(s
, "\\\n")) {
122 && (s
.front() == ' ' || s
.front() == '\t'
123 || s
.front() == '\n' || s
.front() == '\v'
124 || s
.front() == '\f'))
129 if (!s
.empty() && s
!= "\\") {
130 if (compat::starts_with(s
, "//")) {
131 beg
= source
.getBegin();
138 if (removeText(SourceRange(beg
, source
.getEnd()))) {
144 DiagnosticsEngine::Warning
,
146 ? "replace dynamic exception specification with 'noexcept(false)'"
147 : "remove dynamic exception specification"),
148 source
.isValid() ? source
.getBegin() : decl
->getLocation())
149 << (source
.isValid() ? source
: decl
->getSourceRange());
154 bool hasThrowsDocumentation(FunctionDecl
const * decl
) {
155 if (auto cmt
= compiler
.getASTContext().getCommentForDecl(
156 decl
, &compiler
.getPreprocessor()))
158 for (auto i
= cmt
->child_begin(); i
!= cmt
->child_end(); ++i
) {
159 if (auto bcc
= dyn_cast
<comments::BlockCommandComment
>(*i
)) {
160 if (compiler
.getASTContext().getCommentCommandTraits()
161 .getCommandInfo(bcc
->getCommandID())->IsThrowsCommand
)
171 bool anyRedeclHasThrowsDocumentation(FunctionDecl
const * decl
) {
173 decl
->redecls_begin(), decl
->redecls_end(),
174 [this](FunctionDecl
* d
) { return hasThrowsDocumentation(d
); });
176 // &DynExcSpec::hasThrowsDocumentation, this,
177 // std::placeholders::_1));
181 loplugin::Plugin::Registration
<DynExcSpec
> dynexcspec("dynexcspec");
185 #endif // LO_CLANG_SHARED_PLUGINS
187 /* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */