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/.
17 char const * kindName(Expr::NullPointerConstantKind kind
) {
19 case Expr::NPCK_NotNull
:
20 assert(false); // cannot happen
22 case Expr::NPCK_ZeroExpression
:
23 return "ZeroExpression";
24 case Expr::NPCK_ZeroLiteral
:
26 case Expr::NPCK_CXX11_nullptr
:
27 return "CXX11_nullptr";
28 case Expr::NPCK_GNUNull
:
34 public RecursiveASTVisitor
<Nullptr
>, public loplugin::RewritePlugin
37 explicit Nullptr(InstantiationData
const & data
): RewritePlugin(data
) {}
40 { TraverseDecl(compiler
.getASTContext().getTranslationUnitDecl()); }
42 bool VisitImplicitCastExpr(CastExpr
const * expr
);
45 bool isFromCIncludeFile(SourceLocation spellingLocation
) const;
47 bool isMacroBodyExpansion(SourceLocation location
) const;
50 Expr
const & expr
, char const * castKind
,
51 Expr::NullPointerConstantKind nullPointerkind
,
52 char const * replacement
);
55 bool Nullptr::VisitImplicitCastExpr(CastExpr
const * expr
) {
56 if (ignoreLocation(expr
)) {
59 switch (expr
->getCastKind()) {
60 case CK_NullToPointer
:
61 case CK_NullToMemberPointer
:
66 Expr::NullPointerConstantKind k
= expr
->isNullPointerConstant(
67 compiler
.getASTContext(), Expr::NPC_ValueDependentIsNotNull
);
69 case Expr::NPCK_NotNull
:
70 k
= expr
->isNullPointerConstant(
71 compiler
.getASTContext(), Expr::NPC_ValueDependentIsNull
);
73 case Expr::NPCK_NotNull
:
75 case Expr::NPCK_ZeroExpression
:
76 case Expr::NPCK_ZeroLiteral
:
78 DiagnosticsEngine::Warning
,
79 "suspicious ValueDependendIsNull %0", expr
->getLocStart())
80 << kindName(k
) << expr
->getSourceRange();
83 assert(false); // cannot happen
86 case Expr::NPCK_CXX11_nullptr
:
90 Expr
const * e
= expr
->getSubExpr();
93 e
= e
->IgnoreImpCasts();
94 loc
= e
->getLocStart();
95 while (compiler
.getSourceManager().isMacroArgExpansion(loc
)) {
96 loc
= compiler
.getSourceManager()
97 .getImmediateMacroCallerLoc(
100 if (isMacroBodyExpansion(loc
)) {
101 if (Lexer::getImmediateMacroName(
102 loc
, compiler
.getSourceManager(),
103 compiler
.getLangOpts())
106 if (!compiler
.getLangOpts().CPlusPlus
) {
109 loc
= compiler
.getSourceManager()
110 .getImmediateExpansionRange(loc
).first
;
111 if (isInUnoIncludeFile(
112 compiler
.getSourceManager().getSpellingLoc(loc
))
113 || isFromCIncludeFile(
114 compiler
.getSourceManager().getSpellingLoc(
119 } else if (ignoreLocation(
120 compiler
.getSourceManager().getSpellingLoc(
126 ParenExpr
const * pe
= dyn_cast
<ParenExpr
>(e
);
130 e
= pe
->getSubExpr();
133 *e
, expr
->getCastKindName(), k
,
134 ((!compiler
.getLangOpts().CPlusPlus
135 || isInUnoIncludeFile(
136 compiler
.getSourceManager().getSpellingLoc(loc
))
137 || isFromCIncludeFile(
138 compiler
.getSourceManager().getSpellingLoc(loc
)))
139 ? "NULL" : "nullptr"));
146 bool Nullptr::isFromCIncludeFile(SourceLocation spellingLocation
) const {
147 return !compat::isInMainFile(compiler
.getSourceManager(), spellingLocation
)
149 compiler
.getSourceManager().getPresumedLoc(spellingLocation
)
154 bool Nullptr::isMacroBodyExpansion(SourceLocation location
) const {
155 #if (__clang_major__ == 3 && __clang_minor__ >= 3) || __clang_major__ > 3
156 return compiler
.getSourceManager().isMacroBodyExpansion(location
);
158 return location
.isMacroID()
159 && !compiler
.getSourceManager().isMacroArgExpansion(location
);
163 void Nullptr::rewriteOrWarn(
164 Expr
const & expr
, char const * castKind
,
165 Expr::NullPointerConstantKind nullPointerKind
, char const * replacement
)
167 if (rewriter
!= nullptr) {
168 SourceLocation
locStart(expr
.getLocStart());
169 while (compiler
.getSourceManager().isMacroArgExpansion(locStart
)) {
170 locStart
= compiler
.getSourceManager()
171 .getImmediateMacroCallerLoc(locStart
);
173 if (compiler
.getLangOpts().CPlusPlus
&& isMacroBodyExpansion(locStart
)
174 && (Lexer::getImmediateMacroName(
175 locStart
, compiler
.getSourceManager(),
176 compiler
.getLangOpts())
179 locStart
= compiler
.getSourceManager().getImmediateExpansionRange(
182 SourceLocation
locEnd(expr
.getLocEnd());
183 while (compiler
.getSourceManager().isMacroArgExpansion(locEnd
)) {
184 locEnd
= compiler
.getSourceManager()
185 .getImmediateMacroCallerLoc(locEnd
);
187 if (compiler
.getLangOpts().CPlusPlus
&& isMacroBodyExpansion(locEnd
)
188 && (Lexer::getImmediateMacroName(
189 locEnd
, compiler
.getSourceManager(),
190 compiler
.getLangOpts())
193 locEnd
= compiler
.getSourceManager().getImmediateExpansionRange(
196 if (replaceText(SourceRange(compiler
.getSourceManager().getSpellingLoc(locStart
), compiler
.getSourceManager().getSpellingLoc(locEnd
)), replacement
)) {
201 DiagnosticsEngine::Warning
, "%0 ValueDependendIsNotNull %1 -> %2",
203 << castKind
<< kindName(nullPointerKind
) << replacement
204 << expr
.getSourceRange();
207 loplugin::Plugin::Registration
<Nullptr
> X("nullptr", true);
211 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */