bump product version to 5.0.4.1
[LibreOffice.git] / compilerplugins / clang / store / nullptr.cxx
blob528bb6aac9bc6a4dc963bb5eb843829e1f9dad4d
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 <cassert>
12 #include "compat.hxx"
13 #include "plugin.hxx"
15 namespace {
17 char const * kindName(Expr::NullPointerConstantKind kind) {
18 switch (kind) {
19 case Expr::NPCK_NotNull:
20 assert(false); // cannot happen
21 // fall through
22 case Expr::NPCK_ZeroExpression:
23 return "ZeroExpression";
24 case Expr::NPCK_ZeroLiteral:
25 return "ZeroLiteral";
26 case Expr::NPCK_CXX11_nullptr:
27 return "CXX11_nullptr";
28 case Expr::NPCK_GNUNull:
29 return "GNUNull";
33 class Nullptr:
34 public RecursiveASTVisitor<Nullptr>, public loplugin::RewritePlugin
36 public:
37 explicit Nullptr(InstantiationData const & data): RewritePlugin(data) {}
39 void run() override
40 { TraverseDecl(compiler.getASTContext().getTranslationUnitDecl()); }
42 bool VisitImplicitCastExpr(CastExpr const * expr);
44 private:
45 bool isFromCIncludeFile(SourceLocation spellingLocation) const;
47 bool isMacroBodyExpansion(SourceLocation location) const;
49 void rewriteOrWarn(
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)) {
57 return true;
59 switch (expr->getCastKind()) {
60 case CK_NullToPointer:
61 case CK_NullToMemberPointer:
62 break;
63 default:
64 return true;
66 Expr::NullPointerConstantKind k = expr->isNullPointerConstant(
67 compiler.getASTContext(), Expr::NPC_ValueDependentIsNotNull);
68 switch (k) {
69 case Expr::NPCK_NotNull:
70 k = expr->isNullPointerConstant(
71 compiler.getASTContext(), Expr::NPC_ValueDependentIsNull);
72 switch (k) {
73 case Expr::NPCK_NotNull:
74 break;
75 case Expr::NPCK_ZeroExpression:
76 case Expr::NPCK_ZeroLiteral:
77 report(
78 DiagnosticsEngine::Warning,
79 "suspicious ValueDependendIsNull %0", expr->getLocStart())
80 << kindName(k) << expr->getSourceRange();
81 break;
82 default:
83 assert(false); // cannot happen
85 break;
86 case Expr::NPCK_CXX11_nullptr:
87 break;
88 default:
90 Expr const * e = expr->getSubExpr();
91 SourceLocation loc;
92 for (;;) {
93 e = e->IgnoreImpCasts();
94 loc = e->getLocStart();
95 while (compiler.getSourceManager().isMacroArgExpansion(loc)) {
96 loc = compiler.getSourceManager()
97 .getImmediateMacroCallerLoc(
98 loc);
100 if (isMacroBodyExpansion(loc)) {
101 if (Lexer::getImmediateMacroName(
102 loc, compiler.getSourceManager(),
103 compiler.getLangOpts())
104 == "NULL")
106 if (!compiler.getLangOpts().CPlusPlus) {
107 return true;
109 loc = compiler.getSourceManager()
110 .getImmediateExpansionRange(loc).first;
111 if (isInUnoIncludeFile(
112 compiler.getSourceManager().getSpellingLoc(loc))
113 || isFromCIncludeFile(
114 compiler.getSourceManager().getSpellingLoc(
115 loc)))
117 return true;
119 } else if (ignoreLocation(
120 compiler.getSourceManager().getSpellingLoc(
121 loc)))
123 return true;
126 ParenExpr const * pe = dyn_cast<ParenExpr>(e);
127 if (pe == nullptr) {
128 break;
130 e = pe->getSubExpr();
132 rewriteOrWarn(
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"));
141 break;
143 return true;
146 bool Nullptr::isFromCIncludeFile(SourceLocation spellingLocation) const {
147 return !compat::isInMainFile(compiler.getSourceManager(), spellingLocation)
148 && (StringRef(
149 compiler.getSourceManager().getPresumedLoc(spellingLocation)
150 .getFilename())
151 .endswith(".h"));
154 bool Nullptr::isMacroBodyExpansion(SourceLocation location) const {
155 #if (__clang_major__ == 3 && __clang_minor__ >= 3) || __clang_major__ > 3
156 return compiler.getSourceManager().isMacroBodyExpansion(location);
157 #else
158 return location.isMacroID()
159 && !compiler.getSourceManager().isMacroArgExpansion(location);
160 #endif
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())
177 == "NULL"))
179 locStart = compiler.getSourceManager().getImmediateExpansionRange(
180 locStart).first;
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())
191 == "NULL"))
193 locEnd = compiler.getSourceManager().getImmediateExpansionRange(
194 locEnd).first;
196 if (replaceText(SourceRange(compiler.getSourceManager().getSpellingLoc(locStart), compiler.getSourceManager().getSpellingLoc(locEnd)), replacement)) {
197 return;
200 report(
201 DiagnosticsEngine::Warning, "%0 ValueDependendIsNotNull %1 -> %2",
202 expr.getLocStart())
203 << castKind << kindName(nullPointerKind) << replacement
204 << expr.getSourceRange();
207 loplugin::Plugin::Registration<Nullptr> X("nullptr", true);
211 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */