annotate clang/lib/Analysis/PathDiagnostic.cpp @ 176:de4ac79aef9d

...
author Shinji KONO <kono@ie.u-ryukyu.ac.jp>
date Mon, 25 May 2020 17:13:11 +0900
parents 0572611fdcc8
children 2e18cbf3894f
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
150
anatofuz
parents:
diff changeset
1 //===- PathDiagnostic.cpp - Path-Specific Diagnostic Handling -------------===//
anatofuz
parents:
diff changeset
2 //
anatofuz
parents:
diff changeset
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
anatofuz
parents:
diff changeset
4 // See https://llvm.org/LICENSE.txt for license information.
anatofuz
parents:
diff changeset
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
anatofuz
parents:
diff changeset
6 //
anatofuz
parents:
diff changeset
7 //===----------------------------------------------------------------------===//
anatofuz
parents:
diff changeset
8 //
anatofuz
parents:
diff changeset
9 // This file defines the PathDiagnostic-related interfaces.
anatofuz
parents:
diff changeset
10 //
anatofuz
parents:
diff changeset
11 //===----------------------------------------------------------------------===//
anatofuz
parents:
diff changeset
12
anatofuz
parents:
diff changeset
13 #include "clang/Analysis/PathDiagnostic.h"
anatofuz
parents:
diff changeset
14 #include "clang/AST/Decl.h"
anatofuz
parents:
diff changeset
15 #include "clang/AST/DeclBase.h"
anatofuz
parents:
diff changeset
16 #include "clang/AST/DeclCXX.h"
anatofuz
parents:
diff changeset
17 #include "clang/AST/DeclObjC.h"
anatofuz
parents:
diff changeset
18 #include "clang/AST/DeclTemplate.h"
anatofuz
parents:
diff changeset
19 #include "clang/AST/Expr.h"
anatofuz
parents:
diff changeset
20 #include "clang/AST/ExprCXX.h"
anatofuz
parents:
diff changeset
21 #include "clang/AST/OperationKinds.h"
anatofuz
parents:
diff changeset
22 #include "clang/AST/ParentMap.h"
173
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
23 #include "clang/AST/PrettyPrinter.h"
150
anatofuz
parents:
diff changeset
24 #include "clang/AST/Stmt.h"
anatofuz
parents:
diff changeset
25 #include "clang/AST/Type.h"
anatofuz
parents:
diff changeset
26 #include "clang/Analysis/AnalysisDeclContext.h"
anatofuz
parents:
diff changeset
27 #include "clang/Analysis/CFG.h"
anatofuz
parents:
diff changeset
28 #include "clang/Analysis/ProgramPoint.h"
anatofuz
parents:
diff changeset
29 #include "clang/Basic/FileManager.h"
anatofuz
parents:
diff changeset
30 #include "clang/Basic/LLVM.h"
anatofuz
parents:
diff changeset
31 #include "clang/Basic/SourceLocation.h"
anatofuz
parents:
diff changeset
32 #include "clang/Basic/SourceManager.h"
anatofuz
parents:
diff changeset
33 #include "llvm/ADT/ArrayRef.h"
anatofuz
parents:
diff changeset
34 #include "llvm/ADT/FoldingSet.h"
anatofuz
parents:
diff changeset
35 #include "llvm/ADT/None.h"
anatofuz
parents:
diff changeset
36 #include "llvm/ADT/Optional.h"
anatofuz
parents:
diff changeset
37 #include "llvm/ADT/STLExtras.h"
anatofuz
parents:
diff changeset
38 #include "llvm/ADT/SmallString.h"
anatofuz
parents:
diff changeset
39 #include "llvm/ADT/SmallVector.h"
anatofuz
parents:
diff changeset
40 #include "llvm/ADT/StringExtras.h"
anatofuz
parents:
diff changeset
41 #include "llvm/ADT/StringRef.h"
anatofuz
parents:
diff changeset
42 #include "llvm/Support/Casting.h"
anatofuz
parents:
diff changeset
43 #include "llvm/Support/ErrorHandling.h"
anatofuz
parents:
diff changeset
44 #include "llvm/Support/raw_ostream.h"
anatofuz
parents:
diff changeset
45 #include <cassert>
anatofuz
parents:
diff changeset
46 #include <cstring>
anatofuz
parents:
diff changeset
47 #include <memory>
anatofuz
parents:
diff changeset
48 #include <utility>
anatofuz
parents:
diff changeset
49 #include <vector>
anatofuz
parents:
diff changeset
50
anatofuz
parents:
diff changeset
51 using namespace clang;
anatofuz
parents:
diff changeset
52 using namespace ento;
anatofuz
parents:
diff changeset
53
anatofuz
parents:
diff changeset
54 static StringRef StripTrailingDots(StringRef s) {
anatofuz
parents:
diff changeset
55 for (StringRef::size_type i = s.size(); i != 0; --i)
anatofuz
parents:
diff changeset
56 if (s[i - 1] != '.')
anatofuz
parents:
diff changeset
57 return s.substr(0, i);
anatofuz
parents:
diff changeset
58 return {};
anatofuz
parents:
diff changeset
59 }
anatofuz
parents:
diff changeset
60
anatofuz
parents:
diff changeset
61 PathDiagnosticPiece::PathDiagnosticPiece(StringRef s,
anatofuz
parents:
diff changeset
62 Kind k, DisplayHint hint)
anatofuz
parents:
diff changeset
63 : str(StripTrailingDots(s)), kind(k), Hint(hint) {}
anatofuz
parents:
diff changeset
64
anatofuz
parents:
diff changeset
65 PathDiagnosticPiece::PathDiagnosticPiece(Kind k, DisplayHint hint)
anatofuz
parents:
diff changeset
66 : kind(k), Hint(hint) {}
anatofuz
parents:
diff changeset
67
anatofuz
parents:
diff changeset
68 PathDiagnosticPiece::~PathDiagnosticPiece() = default;
anatofuz
parents:
diff changeset
69
anatofuz
parents:
diff changeset
70 PathDiagnosticEventPiece::~PathDiagnosticEventPiece() = default;
anatofuz
parents:
diff changeset
71
anatofuz
parents:
diff changeset
72 PathDiagnosticCallPiece::~PathDiagnosticCallPiece() = default;
anatofuz
parents:
diff changeset
73
anatofuz
parents:
diff changeset
74 PathDiagnosticControlFlowPiece::~PathDiagnosticControlFlowPiece() = default;
anatofuz
parents:
diff changeset
75
anatofuz
parents:
diff changeset
76 PathDiagnosticMacroPiece::~PathDiagnosticMacroPiece() = default;
anatofuz
parents:
diff changeset
77
anatofuz
parents:
diff changeset
78 PathDiagnosticNotePiece::~PathDiagnosticNotePiece() = default;
anatofuz
parents:
diff changeset
79
anatofuz
parents:
diff changeset
80 PathDiagnosticPopUpPiece::~PathDiagnosticPopUpPiece() = default;
anatofuz
parents:
diff changeset
81
anatofuz
parents:
diff changeset
82 void PathPieces::flattenTo(PathPieces &Primary, PathPieces &Current,
anatofuz
parents:
diff changeset
83 bool ShouldFlattenMacros) const {
anatofuz
parents:
diff changeset
84 for (auto &Piece : *this) {
anatofuz
parents:
diff changeset
85 switch (Piece->getKind()) {
anatofuz
parents:
diff changeset
86 case PathDiagnosticPiece::Call: {
anatofuz
parents:
diff changeset
87 auto &Call = cast<PathDiagnosticCallPiece>(*Piece);
anatofuz
parents:
diff changeset
88 if (auto CallEnter = Call.getCallEnterEvent())
anatofuz
parents:
diff changeset
89 Current.push_back(std::move(CallEnter));
anatofuz
parents:
diff changeset
90 Call.path.flattenTo(Primary, Primary, ShouldFlattenMacros);
anatofuz
parents:
diff changeset
91 if (auto callExit = Call.getCallExitEvent())
anatofuz
parents:
diff changeset
92 Current.push_back(std::move(callExit));
anatofuz
parents:
diff changeset
93 break;
anatofuz
parents:
diff changeset
94 }
anatofuz
parents:
diff changeset
95 case PathDiagnosticPiece::Macro: {
anatofuz
parents:
diff changeset
96 auto &Macro = cast<PathDiagnosticMacroPiece>(*Piece);
anatofuz
parents:
diff changeset
97 if (ShouldFlattenMacros) {
anatofuz
parents:
diff changeset
98 Macro.subPieces.flattenTo(Primary, Primary, ShouldFlattenMacros);
anatofuz
parents:
diff changeset
99 } else {
anatofuz
parents:
diff changeset
100 Current.push_back(Piece);
anatofuz
parents:
diff changeset
101 PathPieces NewPath;
anatofuz
parents:
diff changeset
102 Macro.subPieces.flattenTo(Primary, NewPath, ShouldFlattenMacros);
anatofuz
parents:
diff changeset
103 // FIXME: This probably shouldn't mutate the original path piece.
anatofuz
parents:
diff changeset
104 Macro.subPieces = NewPath;
anatofuz
parents:
diff changeset
105 }
anatofuz
parents:
diff changeset
106 break;
anatofuz
parents:
diff changeset
107 }
anatofuz
parents:
diff changeset
108 case PathDiagnosticPiece::Event:
anatofuz
parents:
diff changeset
109 case PathDiagnosticPiece::ControlFlow:
anatofuz
parents:
diff changeset
110 case PathDiagnosticPiece::Note:
anatofuz
parents:
diff changeset
111 case PathDiagnosticPiece::PopUp:
anatofuz
parents:
diff changeset
112 Current.push_back(Piece);
anatofuz
parents:
diff changeset
113 break;
anatofuz
parents:
diff changeset
114 }
anatofuz
parents:
diff changeset
115 }
anatofuz
parents:
diff changeset
116 }
anatofuz
parents:
diff changeset
117
anatofuz
parents:
diff changeset
118 PathDiagnostic::~PathDiagnostic() = default;
anatofuz
parents:
diff changeset
119
anatofuz
parents:
diff changeset
120 PathDiagnostic::PathDiagnostic(
anatofuz
parents:
diff changeset
121 StringRef CheckerName, const Decl *declWithIssue, StringRef bugtype,
anatofuz
parents:
diff changeset
122 StringRef verboseDesc, StringRef shortDesc, StringRef category,
anatofuz
parents:
diff changeset
123 PathDiagnosticLocation LocationToUnique, const Decl *DeclToUnique,
anatofuz
parents:
diff changeset
124 std::unique_ptr<FilesToLineNumsMap> ExecutedLines)
anatofuz
parents:
diff changeset
125 : CheckerName(CheckerName), DeclWithIssue(declWithIssue),
anatofuz
parents:
diff changeset
126 BugType(StripTrailingDots(bugtype)),
anatofuz
parents:
diff changeset
127 VerboseDesc(StripTrailingDots(verboseDesc)),
anatofuz
parents:
diff changeset
128 ShortDesc(StripTrailingDots(shortDesc)),
anatofuz
parents:
diff changeset
129 Category(StripTrailingDots(category)), UniqueingLoc(LocationToUnique),
anatofuz
parents:
diff changeset
130 UniqueingDecl(DeclToUnique), ExecutedLines(std::move(ExecutedLines)),
anatofuz
parents:
diff changeset
131 path(pathImpl) {}
anatofuz
parents:
diff changeset
132
anatofuz
parents:
diff changeset
133 void PathDiagnosticConsumer::anchor() {}
anatofuz
parents:
diff changeset
134
anatofuz
parents:
diff changeset
135 PathDiagnosticConsumer::~PathDiagnosticConsumer() {
anatofuz
parents:
diff changeset
136 // Delete the contents of the FoldingSet if it isn't empty already.
anatofuz
parents:
diff changeset
137 for (auto &Diag : Diags)
anatofuz
parents:
diff changeset
138 delete &Diag;
anatofuz
parents:
diff changeset
139 }
anatofuz
parents:
diff changeset
140
anatofuz
parents:
diff changeset
141 void PathDiagnosticConsumer::HandlePathDiagnostic(
anatofuz
parents:
diff changeset
142 std::unique_ptr<PathDiagnostic> D) {
anatofuz
parents:
diff changeset
143 if (!D || D->path.empty())
anatofuz
parents:
diff changeset
144 return;
anatofuz
parents:
diff changeset
145
anatofuz
parents:
diff changeset
146 // We need to flatten the locations (convert Stmt* to locations) because
anatofuz
parents:
diff changeset
147 // the referenced statements may be freed by the time the diagnostics
anatofuz
parents:
diff changeset
148 // are emitted.
anatofuz
parents:
diff changeset
149 D->flattenLocations();
anatofuz
parents:
diff changeset
150
anatofuz
parents:
diff changeset
151 // If the PathDiagnosticConsumer does not support diagnostics that
anatofuz
parents:
diff changeset
152 // cross file boundaries, prune out such diagnostics now.
anatofuz
parents:
diff changeset
153 if (!supportsCrossFileDiagnostics()) {
anatofuz
parents:
diff changeset
154 // Verify that the entire path is from the same FileID.
anatofuz
parents:
diff changeset
155 FileID FID;
anatofuz
parents:
diff changeset
156 const SourceManager &SMgr = D->path.front()->getLocation().getManager();
anatofuz
parents:
diff changeset
157 SmallVector<const PathPieces *, 5> WorkList;
anatofuz
parents:
diff changeset
158 WorkList.push_back(&D->path);
anatofuz
parents:
diff changeset
159 SmallString<128> buf;
anatofuz
parents:
diff changeset
160 llvm::raw_svector_ostream warning(buf);
anatofuz
parents:
diff changeset
161 warning << "warning: Path diagnostic report is not generated. Current "
anatofuz
parents:
diff changeset
162 << "output format does not support diagnostics that cross file "
anatofuz
parents:
diff changeset
163 << "boundaries. Refer to --analyzer-output for valid output "
anatofuz
parents:
diff changeset
164 << "formats\n";
anatofuz
parents:
diff changeset
165
anatofuz
parents:
diff changeset
166 while (!WorkList.empty()) {
anatofuz
parents:
diff changeset
167 const PathPieces &path = *WorkList.pop_back_val();
anatofuz
parents:
diff changeset
168
anatofuz
parents:
diff changeset
169 for (const auto &I : path) {
anatofuz
parents:
diff changeset
170 const PathDiagnosticPiece *piece = I.get();
anatofuz
parents:
diff changeset
171 FullSourceLoc L = piece->getLocation().asLocation().getExpansionLoc();
anatofuz
parents:
diff changeset
172
anatofuz
parents:
diff changeset
173 if (FID.isInvalid()) {
anatofuz
parents:
diff changeset
174 FID = SMgr.getFileID(L);
anatofuz
parents:
diff changeset
175 } else if (SMgr.getFileID(L) != FID) {
anatofuz
parents:
diff changeset
176 llvm::errs() << warning.str();
anatofuz
parents:
diff changeset
177 return;
anatofuz
parents:
diff changeset
178 }
anatofuz
parents:
diff changeset
179
anatofuz
parents:
diff changeset
180 // Check the source ranges.
anatofuz
parents:
diff changeset
181 ArrayRef<SourceRange> Ranges = piece->getRanges();
anatofuz
parents:
diff changeset
182 for (const auto &I : Ranges) {
anatofuz
parents:
diff changeset
183 SourceLocation L = SMgr.getExpansionLoc(I.getBegin());
anatofuz
parents:
diff changeset
184 if (!L.isFileID() || SMgr.getFileID(L) != FID) {
anatofuz
parents:
diff changeset
185 llvm::errs() << warning.str();
anatofuz
parents:
diff changeset
186 return;
anatofuz
parents:
diff changeset
187 }
anatofuz
parents:
diff changeset
188 L = SMgr.getExpansionLoc(I.getEnd());
anatofuz
parents:
diff changeset
189 if (!L.isFileID() || SMgr.getFileID(L) != FID) {
anatofuz
parents:
diff changeset
190 llvm::errs() << warning.str();
anatofuz
parents:
diff changeset
191 return;
anatofuz
parents:
diff changeset
192 }
anatofuz
parents:
diff changeset
193 }
anatofuz
parents:
diff changeset
194
anatofuz
parents:
diff changeset
195 if (const auto *call = dyn_cast<PathDiagnosticCallPiece>(piece))
anatofuz
parents:
diff changeset
196 WorkList.push_back(&call->path);
anatofuz
parents:
diff changeset
197 else if (const auto *macro = dyn_cast<PathDiagnosticMacroPiece>(piece))
anatofuz
parents:
diff changeset
198 WorkList.push_back(&macro->subPieces);
anatofuz
parents:
diff changeset
199 }
anatofuz
parents:
diff changeset
200 }
anatofuz
parents:
diff changeset
201
anatofuz
parents:
diff changeset
202 if (FID.isInvalid())
anatofuz
parents:
diff changeset
203 return; // FIXME: Emit a warning?
anatofuz
parents:
diff changeset
204 }
anatofuz
parents:
diff changeset
205
anatofuz
parents:
diff changeset
206 // Profile the node to see if we already have something matching it
anatofuz
parents:
diff changeset
207 llvm::FoldingSetNodeID profile;
anatofuz
parents:
diff changeset
208 D->Profile(profile);
anatofuz
parents:
diff changeset
209 void *InsertPos = nullptr;
anatofuz
parents:
diff changeset
210
anatofuz
parents:
diff changeset
211 if (PathDiagnostic *orig = Diags.FindNodeOrInsertPos(profile, InsertPos)) {
anatofuz
parents:
diff changeset
212 // Keep the PathDiagnostic with the shorter path.
anatofuz
parents:
diff changeset
213 // Note, the enclosing routine is called in deterministic order, so the
anatofuz
parents:
diff changeset
214 // results will be consistent between runs (no reason to break ties if the
anatofuz
parents:
diff changeset
215 // size is the same).
anatofuz
parents:
diff changeset
216 const unsigned orig_size = orig->full_size();
anatofuz
parents:
diff changeset
217 const unsigned new_size = D->full_size();
anatofuz
parents:
diff changeset
218 if (orig_size <= new_size)
anatofuz
parents:
diff changeset
219 return;
anatofuz
parents:
diff changeset
220
anatofuz
parents:
diff changeset
221 assert(orig != D.get());
anatofuz
parents:
diff changeset
222 Diags.RemoveNode(orig);
anatofuz
parents:
diff changeset
223 delete orig;
anatofuz
parents:
diff changeset
224 }
anatofuz
parents:
diff changeset
225
anatofuz
parents:
diff changeset
226 Diags.InsertNode(D.release());
anatofuz
parents:
diff changeset
227 }
anatofuz
parents:
diff changeset
228
anatofuz
parents:
diff changeset
229 static Optional<bool> comparePath(const PathPieces &X, const PathPieces &Y);
anatofuz
parents:
diff changeset
230
anatofuz
parents:
diff changeset
231 static Optional<bool>
anatofuz
parents:
diff changeset
232 compareControlFlow(const PathDiagnosticControlFlowPiece &X,
anatofuz
parents:
diff changeset
233 const PathDiagnosticControlFlowPiece &Y) {
anatofuz
parents:
diff changeset
234 FullSourceLoc XSL = X.getStartLocation().asLocation();
anatofuz
parents:
diff changeset
235 FullSourceLoc YSL = Y.getStartLocation().asLocation();
anatofuz
parents:
diff changeset
236 if (XSL != YSL)
anatofuz
parents:
diff changeset
237 return XSL.isBeforeInTranslationUnitThan(YSL);
anatofuz
parents:
diff changeset
238 FullSourceLoc XEL = X.getEndLocation().asLocation();
anatofuz
parents:
diff changeset
239 FullSourceLoc YEL = Y.getEndLocation().asLocation();
anatofuz
parents:
diff changeset
240 if (XEL != YEL)
anatofuz
parents:
diff changeset
241 return XEL.isBeforeInTranslationUnitThan(YEL);
anatofuz
parents:
diff changeset
242 return None;
anatofuz
parents:
diff changeset
243 }
anatofuz
parents:
diff changeset
244
anatofuz
parents:
diff changeset
245 static Optional<bool> compareMacro(const PathDiagnosticMacroPiece &X,
anatofuz
parents:
diff changeset
246 const PathDiagnosticMacroPiece &Y) {
anatofuz
parents:
diff changeset
247 return comparePath(X.subPieces, Y.subPieces);
anatofuz
parents:
diff changeset
248 }
anatofuz
parents:
diff changeset
249
anatofuz
parents:
diff changeset
250 static Optional<bool> compareCall(const PathDiagnosticCallPiece &X,
anatofuz
parents:
diff changeset
251 const PathDiagnosticCallPiece &Y) {
anatofuz
parents:
diff changeset
252 FullSourceLoc X_CEL = X.callEnter.asLocation();
anatofuz
parents:
diff changeset
253 FullSourceLoc Y_CEL = Y.callEnter.asLocation();
anatofuz
parents:
diff changeset
254 if (X_CEL != Y_CEL)
anatofuz
parents:
diff changeset
255 return X_CEL.isBeforeInTranslationUnitThan(Y_CEL);
anatofuz
parents:
diff changeset
256 FullSourceLoc X_CEWL = X.callEnterWithin.asLocation();
anatofuz
parents:
diff changeset
257 FullSourceLoc Y_CEWL = Y.callEnterWithin.asLocation();
anatofuz
parents:
diff changeset
258 if (X_CEWL != Y_CEWL)
anatofuz
parents:
diff changeset
259 return X_CEWL.isBeforeInTranslationUnitThan(Y_CEWL);
anatofuz
parents:
diff changeset
260 FullSourceLoc X_CRL = X.callReturn.asLocation();
anatofuz
parents:
diff changeset
261 FullSourceLoc Y_CRL = Y.callReturn.asLocation();
anatofuz
parents:
diff changeset
262 if (X_CRL != Y_CRL)
anatofuz
parents:
diff changeset
263 return X_CRL.isBeforeInTranslationUnitThan(Y_CRL);
anatofuz
parents:
diff changeset
264 return comparePath(X.path, Y.path);
anatofuz
parents:
diff changeset
265 }
anatofuz
parents:
diff changeset
266
anatofuz
parents:
diff changeset
267 static Optional<bool> comparePiece(const PathDiagnosticPiece &X,
anatofuz
parents:
diff changeset
268 const PathDiagnosticPiece &Y) {
anatofuz
parents:
diff changeset
269 if (X.getKind() != Y.getKind())
anatofuz
parents:
diff changeset
270 return X.getKind() < Y.getKind();
anatofuz
parents:
diff changeset
271
anatofuz
parents:
diff changeset
272 FullSourceLoc XL = X.getLocation().asLocation();
anatofuz
parents:
diff changeset
273 FullSourceLoc YL = Y.getLocation().asLocation();
anatofuz
parents:
diff changeset
274 if (XL != YL)
anatofuz
parents:
diff changeset
275 return XL.isBeforeInTranslationUnitThan(YL);
anatofuz
parents:
diff changeset
276
anatofuz
parents:
diff changeset
277 if (X.getString() != Y.getString())
anatofuz
parents:
diff changeset
278 return X.getString() < Y.getString();
anatofuz
parents:
diff changeset
279
anatofuz
parents:
diff changeset
280 if (X.getRanges().size() != Y.getRanges().size())
anatofuz
parents:
diff changeset
281 return X.getRanges().size() < Y.getRanges().size();
anatofuz
parents:
diff changeset
282
anatofuz
parents:
diff changeset
283 const SourceManager &SM = XL.getManager();
anatofuz
parents:
diff changeset
284
anatofuz
parents:
diff changeset
285 for (unsigned i = 0, n = X.getRanges().size(); i < n; ++i) {
anatofuz
parents:
diff changeset
286 SourceRange XR = X.getRanges()[i];
anatofuz
parents:
diff changeset
287 SourceRange YR = Y.getRanges()[i];
anatofuz
parents:
diff changeset
288 if (XR != YR) {
anatofuz
parents:
diff changeset
289 if (XR.getBegin() != YR.getBegin())
anatofuz
parents:
diff changeset
290 return SM.isBeforeInTranslationUnit(XR.getBegin(), YR.getBegin());
anatofuz
parents:
diff changeset
291 return SM.isBeforeInTranslationUnit(XR.getEnd(), YR.getEnd());
anatofuz
parents:
diff changeset
292 }
anatofuz
parents:
diff changeset
293 }
anatofuz
parents:
diff changeset
294
anatofuz
parents:
diff changeset
295 switch (X.getKind()) {
anatofuz
parents:
diff changeset
296 case PathDiagnosticPiece::ControlFlow:
anatofuz
parents:
diff changeset
297 return compareControlFlow(cast<PathDiagnosticControlFlowPiece>(X),
anatofuz
parents:
diff changeset
298 cast<PathDiagnosticControlFlowPiece>(Y));
anatofuz
parents:
diff changeset
299 case PathDiagnosticPiece::Macro:
anatofuz
parents:
diff changeset
300 return compareMacro(cast<PathDiagnosticMacroPiece>(X),
anatofuz
parents:
diff changeset
301 cast<PathDiagnosticMacroPiece>(Y));
anatofuz
parents:
diff changeset
302 case PathDiagnosticPiece::Call:
anatofuz
parents:
diff changeset
303 return compareCall(cast<PathDiagnosticCallPiece>(X),
anatofuz
parents:
diff changeset
304 cast<PathDiagnosticCallPiece>(Y));
anatofuz
parents:
diff changeset
305 case PathDiagnosticPiece::Event:
anatofuz
parents:
diff changeset
306 case PathDiagnosticPiece::Note:
anatofuz
parents:
diff changeset
307 case PathDiagnosticPiece::PopUp:
anatofuz
parents:
diff changeset
308 return None;
anatofuz
parents:
diff changeset
309 }
anatofuz
parents:
diff changeset
310 llvm_unreachable("all cases handled");
anatofuz
parents:
diff changeset
311 }
anatofuz
parents:
diff changeset
312
anatofuz
parents:
diff changeset
313 static Optional<bool> comparePath(const PathPieces &X, const PathPieces &Y) {
anatofuz
parents:
diff changeset
314 if (X.size() != Y.size())
anatofuz
parents:
diff changeset
315 return X.size() < Y.size();
anatofuz
parents:
diff changeset
316
anatofuz
parents:
diff changeset
317 PathPieces::const_iterator X_I = X.begin(), X_end = X.end();
anatofuz
parents:
diff changeset
318 PathPieces::const_iterator Y_I = Y.begin(), Y_end = Y.end();
anatofuz
parents:
diff changeset
319
anatofuz
parents:
diff changeset
320 for ( ; X_I != X_end && Y_I != Y_end; ++X_I, ++Y_I) {
anatofuz
parents:
diff changeset
321 Optional<bool> b = comparePiece(**X_I, **Y_I);
anatofuz
parents:
diff changeset
322 if (b.hasValue())
anatofuz
parents:
diff changeset
323 return b.getValue();
anatofuz
parents:
diff changeset
324 }
anatofuz
parents:
diff changeset
325
anatofuz
parents:
diff changeset
326 return None;
anatofuz
parents:
diff changeset
327 }
anatofuz
parents:
diff changeset
328
anatofuz
parents:
diff changeset
329 static bool compareCrossTUSourceLocs(FullSourceLoc XL, FullSourceLoc YL) {
anatofuz
parents:
diff changeset
330 std::pair<FileID, unsigned> XOffs = XL.getDecomposedLoc();
anatofuz
parents:
diff changeset
331 std::pair<FileID, unsigned> YOffs = YL.getDecomposedLoc();
anatofuz
parents:
diff changeset
332 const SourceManager &SM = XL.getManager();
anatofuz
parents:
diff changeset
333 std::pair<bool, bool> InSameTU = SM.isInTheSameTranslationUnit(XOffs, YOffs);
anatofuz
parents:
diff changeset
334 if (InSameTU.first)
anatofuz
parents:
diff changeset
335 return XL.isBeforeInTranslationUnitThan(YL);
anatofuz
parents:
diff changeset
336 const FileEntry *XFE = SM.getFileEntryForID(XL.getSpellingLoc().getFileID());
anatofuz
parents:
diff changeset
337 const FileEntry *YFE = SM.getFileEntryForID(YL.getSpellingLoc().getFileID());
anatofuz
parents:
diff changeset
338 if (!XFE || !YFE)
anatofuz
parents:
diff changeset
339 return XFE && !YFE;
anatofuz
parents:
diff changeset
340 int NameCmp = XFE->getName().compare(YFE->getName());
anatofuz
parents:
diff changeset
341 if (NameCmp != 0)
anatofuz
parents:
diff changeset
342 return NameCmp == -1;
anatofuz
parents:
diff changeset
343 // Last resort: Compare raw file IDs that are possibly expansions.
anatofuz
parents:
diff changeset
344 return XL.getFileID() < YL.getFileID();
anatofuz
parents:
diff changeset
345 }
anatofuz
parents:
diff changeset
346
anatofuz
parents:
diff changeset
347 static bool compare(const PathDiagnostic &X, const PathDiagnostic &Y) {
anatofuz
parents:
diff changeset
348 FullSourceLoc XL = X.getLocation().asLocation();
anatofuz
parents:
diff changeset
349 FullSourceLoc YL = Y.getLocation().asLocation();
anatofuz
parents:
diff changeset
350 if (XL != YL)
anatofuz
parents:
diff changeset
351 return compareCrossTUSourceLocs(XL, YL);
anatofuz
parents:
diff changeset
352 if (X.getBugType() != Y.getBugType())
anatofuz
parents:
diff changeset
353 return X.getBugType() < Y.getBugType();
anatofuz
parents:
diff changeset
354 if (X.getCategory() != Y.getCategory())
anatofuz
parents:
diff changeset
355 return X.getCategory() < Y.getCategory();
anatofuz
parents:
diff changeset
356 if (X.getVerboseDescription() != Y.getVerboseDescription())
anatofuz
parents:
diff changeset
357 return X.getVerboseDescription() < Y.getVerboseDescription();
anatofuz
parents:
diff changeset
358 if (X.getShortDescription() != Y.getShortDescription())
anatofuz
parents:
diff changeset
359 return X.getShortDescription() < Y.getShortDescription();
anatofuz
parents:
diff changeset
360 if (X.getDeclWithIssue() != Y.getDeclWithIssue()) {
anatofuz
parents:
diff changeset
361 const Decl *XD = X.getDeclWithIssue();
anatofuz
parents:
diff changeset
362 if (!XD)
anatofuz
parents:
diff changeset
363 return true;
anatofuz
parents:
diff changeset
364 const Decl *YD = Y.getDeclWithIssue();
anatofuz
parents:
diff changeset
365 if (!YD)
anatofuz
parents:
diff changeset
366 return false;
anatofuz
parents:
diff changeset
367 SourceLocation XDL = XD->getLocation();
anatofuz
parents:
diff changeset
368 SourceLocation YDL = YD->getLocation();
anatofuz
parents:
diff changeset
369 if (XDL != YDL) {
anatofuz
parents:
diff changeset
370 const SourceManager &SM = XL.getManager();
anatofuz
parents:
diff changeset
371 return compareCrossTUSourceLocs(FullSourceLoc(XDL, SM),
anatofuz
parents:
diff changeset
372 FullSourceLoc(YDL, SM));
anatofuz
parents:
diff changeset
373 }
anatofuz
parents:
diff changeset
374 }
anatofuz
parents:
diff changeset
375 PathDiagnostic::meta_iterator XI = X.meta_begin(), XE = X.meta_end();
anatofuz
parents:
diff changeset
376 PathDiagnostic::meta_iterator YI = Y.meta_begin(), YE = Y.meta_end();
anatofuz
parents:
diff changeset
377 if (XE - XI != YE - YI)
anatofuz
parents:
diff changeset
378 return (XE - XI) < (YE - YI);
anatofuz
parents:
diff changeset
379 for ( ; XI != XE ; ++XI, ++YI) {
anatofuz
parents:
diff changeset
380 if (*XI != *YI)
anatofuz
parents:
diff changeset
381 return (*XI) < (*YI);
anatofuz
parents:
diff changeset
382 }
anatofuz
parents:
diff changeset
383 Optional<bool> b = comparePath(X.path, Y.path);
anatofuz
parents:
diff changeset
384 assert(b.hasValue());
anatofuz
parents:
diff changeset
385 return b.getValue();
anatofuz
parents:
diff changeset
386 }
anatofuz
parents:
diff changeset
387
anatofuz
parents:
diff changeset
388 void PathDiagnosticConsumer::FlushDiagnostics(
anatofuz
parents:
diff changeset
389 PathDiagnosticConsumer::FilesMade *Files) {
anatofuz
parents:
diff changeset
390 if (flushed)
anatofuz
parents:
diff changeset
391 return;
anatofuz
parents:
diff changeset
392
anatofuz
parents:
diff changeset
393 flushed = true;
anatofuz
parents:
diff changeset
394
anatofuz
parents:
diff changeset
395 std::vector<const PathDiagnostic *> BatchDiags;
anatofuz
parents:
diff changeset
396 for (const auto &D : Diags)
anatofuz
parents:
diff changeset
397 BatchDiags.push_back(&D);
anatofuz
parents:
diff changeset
398
anatofuz
parents:
diff changeset
399 // Sort the diagnostics so that they are always emitted in a deterministic
anatofuz
parents:
diff changeset
400 // order.
anatofuz
parents:
diff changeset
401 int (*Comp)(const PathDiagnostic *const *, const PathDiagnostic *const *) =
anatofuz
parents:
diff changeset
402 [](const PathDiagnostic *const *X, const PathDiagnostic *const *Y) {
anatofuz
parents:
diff changeset
403 assert(*X != *Y && "PathDiagnostics not uniqued!");
anatofuz
parents:
diff changeset
404 if (compare(**X, **Y))
anatofuz
parents:
diff changeset
405 return -1;
anatofuz
parents:
diff changeset
406 assert(compare(**Y, **X) && "Not a total order!");
anatofuz
parents:
diff changeset
407 return 1;
anatofuz
parents:
diff changeset
408 };
anatofuz
parents:
diff changeset
409 array_pod_sort(BatchDiags.begin(), BatchDiags.end(), Comp);
anatofuz
parents:
diff changeset
410
anatofuz
parents:
diff changeset
411 FlushDiagnosticsImpl(BatchDiags, Files);
anatofuz
parents:
diff changeset
412
anatofuz
parents:
diff changeset
413 // Delete the flushed diagnostics.
anatofuz
parents:
diff changeset
414 for (const auto D : BatchDiags)
anatofuz
parents:
diff changeset
415 delete D;
anatofuz
parents:
diff changeset
416
anatofuz
parents:
diff changeset
417 // Clear out the FoldingSet.
anatofuz
parents:
diff changeset
418 Diags.clear();
anatofuz
parents:
diff changeset
419 }
anatofuz
parents:
diff changeset
420
anatofuz
parents:
diff changeset
421 PathDiagnosticConsumer::FilesMade::~FilesMade() {
anatofuz
parents:
diff changeset
422 for (PDFileEntry &Entry : Set)
anatofuz
parents:
diff changeset
423 Entry.~PDFileEntry();
anatofuz
parents:
diff changeset
424 }
anatofuz
parents:
diff changeset
425
anatofuz
parents:
diff changeset
426 void PathDiagnosticConsumer::FilesMade::addDiagnostic(const PathDiagnostic &PD,
anatofuz
parents:
diff changeset
427 StringRef ConsumerName,
anatofuz
parents:
diff changeset
428 StringRef FileName) {
anatofuz
parents:
diff changeset
429 llvm::FoldingSetNodeID NodeID;
anatofuz
parents:
diff changeset
430 NodeID.Add(PD);
anatofuz
parents:
diff changeset
431 void *InsertPos;
anatofuz
parents:
diff changeset
432 PDFileEntry *Entry = Set.FindNodeOrInsertPos(NodeID, InsertPos);
anatofuz
parents:
diff changeset
433 if (!Entry) {
anatofuz
parents:
diff changeset
434 Entry = Alloc.Allocate<PDFileEntry>();
anatofuz
parents:
diff changeset
435 Entry = new (Entry) PDFileEntry(NodeID);
anatofuz
parents:
diff changeset
436 Set.InsertNode(Entry, InsertPos);
anatofuz
parents:
diff changeset
437 }
anatofuz
parents:
diff changeset
438
anatofuz
parents:
diff changeset
439 // Allocate persistent storage for the file name.
anatofuz
parents:
diff changeset
440 char *FileName_cstr = (char*) Alloc.Allocate(FileName.size(), 1);
anatofuz
parents:
diff changeset
441 memcpy(FileName_cstr, FileName.data(), FileName.size());
anatofuz
parents:
diff changeset
442
anatofuz
parents:
diff changeset
443 Entry->files.push_back(std::make_pair(ConsumerName,
anatofuz
parents:
diff changeset
444 StringRef(FileName_cstr,
anatofuz
parents:
diff changeset
445 FileName.size())));
anatofuz
parents:
diff changeset
446 }
anatofuz
parents:
diff changeset
447
anatofuz
parents:
diff changeset
448 PathDiagnosticConsumer::PDFileEntry::ConsumerFiles *
anatofuz
parents:
diff changeset
449 PathDiagnosticConsumer::FilesMade::getFiles(const PathDiagnostic &PD) {
anatofuz
parents:
diff changeset
450 llvm::FoldingSetNodeID NodeID;
anatofuz
parents:
diff changeset
451 NodeID.Add(PD);
anatofuz
parents:
diff changeset
452 void *InsertPos;
anatofuz
parents:
diff changeset
453 PDFileEntry *Entry = Set.FindNodeOrInsertPos(NodeID, InsertPos);
anatofuz
parents:
diff changeset
454 if (!Entry)
anatofuz
parents:
diff changeset
455 return nullptr;
anatofuz
parents:
diff changeset
456 return &Entry->files;
anatofuz
parents:
diff changeset
457 }
anatofuz
parents:
diff changeset
458
anatofuz
parents:
diff changeset
459 //===----------------------------------------------------------------------===//
anatofuz
parents:
diff changeset
460 // PathDiagnosticLocation methods.
anatofuz
parents:
diff changeset
461 //===----------------------------------------------------------------------===//
anatofuz
parents:
diff changeset
462
anatofuz
parents:
diff changeset
463 SourceLocation PathDiagnosticLocation::getValidSourceLocation(
anatofuz
parents:
diff changeset
464 const Stmt *S, LocationOrAnalysisDeclContext LAC, bool UseEndOfStatement) {
anatofuz
parents:
diff changeset
465 SourceLocation L = UseEndOfStatement ? S->getEndLoc() : S->getBeginLoc();
anatofuz
parents:
diff changeset
466 assert(!LAC.isNull() &&
anatofuz
parents:
diff changeset
467 "A valid LocationContext or AnalysisDeclContext should be passed to "
anatofuz
parents:
diff changeset
468 "PathDiagnosticLocation upon creation.");
anatofuz
parents:
diff changeset
469
anatofuz
parents:
diff changeset
470 // S might be a temporary statement that does not have a location in the
anatofuz
parents:
diff changeset
471 // source code, so find an enclosing statement and use its location.
anatofuz
parents:
diff changeset
472 if (!L.isValid()) {
anatofuz
parents:
diff changeset
473 AnalysisDeclContext *ADC;
anatofuz
parents:
diff changeset
474 if (LAC.is<const LocationContext*>())
anatofuz
parents:
diff changeset
475 ADC = LAC.get<const LocationContext*>()->getAnalysisDeclContext();
anatofuz
parents:
diff changeset
476 else
anatofuz
parents:
diff changeset
477 ADC = LAC.get<AnalysisDeclContext*>();
anatofuz
parents:
diff changeset
478
anatofuz
parents:
diff changeset
479 ParentMap &PM = ADC->getParentMap();
anatofuz
parents:
diff changeset
480
anatofuz
parents:
diff changeset
481 const Stmt *Parent = S;
anatofuz
parents:
diff changeset
482 do {
anatofuz
parents:
diff changeset
483 Parent = PM.getParent(Parent);
anatofuz
parents:
diff changeset
484
anatofuz
parents:
diff changeset
485 // In rare cases, we have implicit top-level expressions,
anatofuz
parents:
diff changeset
486 // such as arguments for implicit member initializers.
anatofuz
parents:
diff changeset
487 // In this case, fall back to the start of the body (even if we were
anatofuz
parents:
diff changeset
488 // asked for the statement end location).
anatofuz
parents:
diff changeset
489 if (!Parent) {
anatofuz
parents:
diff changeset
490 const Stmt *Body = ADC->getBody();
anatofuz
parents:
diff changeset
491 if (Body)
anatofuz
parents:
diff changeset
492 L = Body->getBeginLoc();
anatofuz
parents:
diff changeset
493 else
anatofuz
parents:
diff changeset
494 L = ADC->getDecl()->getEndLoc();
anatofuz
parents:
diff changeset
495 break;
anatofuz
parents:
diff changeset
496 }
anatofuz
parents:
diff changeset
497
anatofuz
parents:
diff changeset
498 L = UseEndOfStatement ? Parent->getEndLoc() : Parent->getBeginLoc();
anatofuz
parents:
diff changeset
499 } while (!L.isValid());
anatofuz
parents:
diff changeset
500 }
anatofuz
parents:
diff changeset
501
anatofuz
parents:
diff changeset
502 // FIXME: Ironically, this assert actually fails in some cases.
anatofuz
parents:
diff changeset
503 //assert(L.isValid());
anatofuz
parents:
diff changeset
504 return L;
anatofuz
parents:
diff changeset
505 }
anatofuz
parents:
diff changeset
506
anatofuz
parents:
diff changeset
507 static PathDiagnosticLocation
anatofuz
parents:
diff changeset
508 getLocationForCaller(const StackFrameContext *SFC,
anatofuz
parents:
diff changeset
509 const LocationContext *CallerCtx,
anatofuz
parents:
diff changeset
510 const SourceManager &SM) {
anatofuz
parents:
diff changeset
511 const CFGBlock &Block = *SFC->getCallSiteBlock();
anatofuz
parents:
diff changeset
512 CFGElement Source = Block[SFC->getIndex()];
anatofuz
parents:
diff changeset
513
anatofuz
parents:
diff changeset
514 switch (Source.getKind()) {
anatofuz
parents:
diff changeset
515 case CFGElement::Statement:
anatofuz
parents:
diff changeset
516 case CFGElement::Constructor:
anatofuz
parents:
diff changeset
517 case CFGElement::CXXRecordTypedCall:
anatofuz
parents:
diff changeset
518 return PathDiagnosticLocation(Source.castAs<CFGStmt>().getStmt(),
anatofuz
parents:
diff changeset
519 SM, CallerCtx);
anatofuz
parents:
diff changeset
520 case CFGElement::Initializer: {
anatofuz
parents:
diff changeset
521 const CFGInitializer &Init = Source.castAs<CFGInitializer>();
anatofuz
parents:
diff changeset
522 return PathDiagnosticLocation(Init.getInitializer()->getInit(),
anatofuz
parents:
diff changeset
523 SM, CallerCtx);
anatofuz
parents:
diff changeset
524 }
anatofuz
parents:
diff changeset
525 case CFGElement::AutomaticObjectDtor: {
anatofuz
parents:
diff changeset
526 const CFGAutomaticObjDtor &Dtor = Source.castAs<CFGAutomaticObjDtor>();
anatofuz
parents:
diff changeset
527 return PathDiagnosticLocation::createEnd(Dtor.getTriggerStmt(),
anatofuz
parents:
diff changeset
528 SM, CallerCtx);
anatofuz
parents:
diff changeset
529 }
anatofuz
parents:
diff changeset
530 case CFGElement::DeleteDtor: {
anatofuz
parents:
diff changeset
531 const CFGDeleteDtor &Dtor = Source.castAs<CFGDeleteDtor>();
anatofuz
parents:
diff changeset
532 return PathDiagnosticLocation(Dtor.getDeleteExpr(), SM, CallerCtx);
anatofuz
parents:
diff changeset
533 }
anatofuz
parents:
diff changeset
534 case CFGElement::BaseDtor:
anatofuz
parents:
diff changeset
535 case CFGElement::MemberDtor: {
anatofuz
parents:
diff changeset
536 const AnalysisDeclContext *CallerInfo = CallerCtx->getAnalysisDeclContext();
anatofuz
parents:
diff changeset
537 if (const Stmt *CallerBody = CallerInfo->getBody())
anatofuz
parents:
diff changeset
538 return PathDiagnosticLocation::createEnd(CallerBody, SM, CallerCtx);
anatofuz
parents:
diff changeset
539 return PathDiagnosticLocation::create(CallerInfo->getDecl(), SM);
anatofuz
parents:
diff changeset
540 }
anatofuz
parents:
diff changeset
541 case CFGElement::NewAllocator: {
anatofuz
parents:
diff changeset
542 const CFGNewAllocator &Alloc = Source.castAs<CFGNewAllocator>();
anatofuz
parents:
diff changeset
543 return PathDiagnosticLocation(Alloc.getAllocatorExpr(), SM, CallerCtx);
anatofuz
parents:
diff changeset
544 }
anatofuz
parents:
diff changeset
545 case CFGElement::TemporaryDtor: {
anatofuz
parents:
diff changeset
546 // Temporary destructors are for temporaries. They die immediately at around
anatofuz
parents:
diff changeset
547 // the location of CXXBindTemporaryExpr. If they are lifetime-extended,
anatofuz
parents:
diff changeset
548 // they'd be dealt with via an AutomaticObjectDtor instead.
anatofuz
parents:
diff changeset
549 const auto &Dtor = Source.castAs<CFGTemporaryDtor>();
anatofuz
parents:
diff changeset
550 return PathDiagnosticLocation::createEnd(Dtor.getBindTemporaryExpr(), SM,
anatofuz
parents:
diff changeset
551 CallerCtx);
anatofuz
parents:
diff changeset
552 }
anatofuz
parents:
diff changeset
553 case CFGElement::ScopeBegin:
anatofuz
parents:
diff changeset
554 case CFGElement::ScopeEnd:
anatofuz
parents:
diff changeset
555 llvm_unreachable("not yet implemented!");
anatofuz
parents:
diff changeset
556 case CFGElement::LifetimeEnds:
anatofuz
parents:
diff changeset
557 case CFGElement::LoopExit:
anatofuz
parents:
diff changeset
558 llvm_unreachable("CFGElement kind should not be on callsite!");
anatofuz
parents:
diff changeset
559 }
anatofuz
parents:
diff changeset
560
anatofuz
parents:
diff changeset
561 llvm_unreachable("Unknown CFGElement kind");
anatofuz
parents:
diff changeset
562 }
anatofuz
parents:
diff changeset
563
anatofuz
parents:
diff changeset
564 PathDiagnosticLocation
anatofuz
parents:
diff changeset
565 PathDiagnosticLocation::createBegin(const Decl *D,
anatofuz
parents:
diff changeset
566 const SourceManager &SM) {
anatofuz
parents:
diff changeset
567 return PathDiagnosticLocation(D->getBeginLoc(), SM, SingleLocK);
anatofuz
parents:
diff changeset
568 }
anatofuz
parents:
diff changeset
569
anatofuz
parents:
diff changeset
570 PathDiagnosticLocation
anatofuz
parents:
diff changeset
571 PathDiagnosticLocation::createBegin(const Stmt *S,
anatofuz
parents:
diff changeset
572 const SourceManager &SM,
anatofuz
parents:
diff changeset
573 LocationOrAnalysisDeclContext LAC) {
anatofuz
parents:
diff changeset
574 return PathDiagnosticLocation(getValidSourceLocation(S, LAC),
anatofuz
parents:
diff changeset
575 SM, SingleLocK);
anatofuz
parents:
diff changeset
576 }
anatofuz
parents:
diff changeset
577
anatofuz
parents:
diff changeset
578 PathDiagnosticLocation
anatofuz
parents:
diff changeset
579 PathDiagnosticLocation::createEnd(const Stmt *S,
anatofuz
parents:
diff changeset
580 const SourceManager &SM,
anatofuz
parents:
diff changeset
581 LocationOrAnalysisDeclContext LAC) {
anatofuz
parents:
diff changeset
582 if (const auto *CS = dyn_cast<CompoundStmt>(S))
anatofuz
parents:
diff changeset
583 return createEndBrace(CS, SM);
anatofuz
parents:
diff changeset
584 return PathDiagnosticLocation(getValidSourceLocation(S, LAC, /*End=*/true),
anatofuz
parents:
diff changeset
585 SM, SingleLocK);
anatofuz
parents:
diff changeset
586 }
anatofuz
parents:
diff changeset
587
anatofuz
parents:
diff changeset
588 PathDiagnosticLocation
anatofuz
parents:
diff changeset
589 PathDiagnosticLocation::createOperatorLoc(const BinaryOperator *BO,
anatofuz
parents:
diff changeset
590 const SourceManager &SM) {
anatofuz
parents:
diff changeset
591 return PathDiagnosticLocation(BO->getOperatorLoc(), SM, SingleLocK);
anatofuz
parents:
diff changeset
592 }
anatofuz
parents:
diff changeset
593
anatofuz
parents:
diff changeset
594 PathDiagnosticLocation
anatofuz
parents:
diff changeset
595 PathDiagnosticLocation::createConditionalColonLoc(
anatofuz
parents:
diff changeset
596 const ConditionalOperator *CO,
anatofuz
parents:
diff changeset
597 const SourceManager &SM) {
anatofuz
parents:
diff changeset
598 return PathDiagnosticLocation(CO->getColonLoc(), SM, SingleLocK);
anatofuz
parents:
diff changeset
599 }
anatofuz
parents:
diff changeset
600
anatofuz
parents:
diff changeset
601 PathDiagnosticLocation
anatofuz
parents:
diff changeset
602 PathDiagnosticLocation::createMemberLoc(const MemberExpr *ME,
anatofuz
parents:
diff changeset
603 const SourceManager &SM) {
anatofuz
parents:
diff changeset
604
anatofuz
parents:
diff changeset
605 assert(ME->getMemberLoc().isValid() || ME->getBeginLoc().isValid());
anatofuz
parents:
diff changeset
606
anatofuz
parents:
diff changeset
607 // In some cases, getMemberLoc isn't valid -- in this case we'll return with
anatofuz
parents:
diff changeset
608 // some other related valid SourceLocation.
anatofuz
parents:
diff changeset
609 if (ME->getMemberLoc().isValid())
anatofuz
parents:
diff changeset
610 return PathDiagnosticLocation(ME->getMemberLoc(), SM, SingleLocK);
anatofuz
parents:
diff changeset
611
anatofuz
parents:
diff changeset
612 return PathDiagnosticLocation(ME->getBeginLoc(), SM, SingleLocK);
anatofuz
parents:
diff changeset
613 }
anatofuz
parents:
diff changeset
614
anatofuz
parents:
diff changeset
615 PathDiagnosticLocation
anatofuz
parents:
diff changeset
616 PathDiagnosticLocation::createBeginBrace(const CompoundStmt *CS,
anatofuz
parents:
diff changeset
617 const SourceManager &SM) {
anatofuz
parents:
diff changeset
618 SourceLocation L = CS->getLBracLoc();
anatofuz
parents:
diff changeset
619 return PathDiagnosticLocation(L, SM, SingleLocK);
anatofuz
parents:
diff changeset
620 }
anatofuz
parents:
diff changeset
621
anatofuz
parents:
diff changeset
622 PathDiagnosticLocation
anatofuz
parents:
diff changeset
623 PathDiagnosticLocation::createEndBrace(const CompoundStmt *CS,
anatofuz
parents:
diff changeset
624 const SourceManager &SM) {
anatofuz
parents:
diff changeset
625 SourceLocation L = CS->getRBracLoc();
anatofuz
parents:
diff changeset
626 return PathDiagnosticLocation(L, SM, SingleLocK);
anatofuz
parents:
diff changeset
627 }
anatofuz
parents:
diff changeset
628
anatofuz
parents:
diff changeset
629 PathDiagnosticLocation
anatofuz
parents:
diff changeset
630 PathDiagnosticLocation::createDeclBegin(const LocationContext *LC,
anatofuz
parents:
diff changeset
631 const SourceManager &SM) {
anatofuz
parents:
diff changeset
632 // FIXME: Should handle CXXTryStmt if analyser starts supporting C++.
anatofuz
parents:
diff changeset
633 if (const auto *CS = dyn_cast_or_null<CompoundStmt>(LC->getDecl()->getBody()))
anatofuz
parents:
diff changeset
634 if (!CS->body_empty()) {
anatofuz
parents:
diff changeset
635 SourceLocation Loc = (*CS->body_begin())->getBeginLoc();
anatofuz
parents:
diff changeset
636 return PathDiagnosticLocation(Loc, SM, SingleLocK);
anatofuz
parents:
diff changeset
637 }
anatofuz
parents:
diff changeset
638
anatofuz
parents:
diff changeset
639 return PathDiagnosticLocation();
anatofuz
parents:
diff changeset
640 }
anatofuz
parents:
diff changeset
641
anatofuz
parents:
diff changeset
642 PathDiagnosticLocation
anatofuz
parents:
diff changeset
643 PathDiagnosticLocation::createDeclEnd(const LocationContext *LC,
anatofuz
parents:
diff changeset
644 const SourceManager &SM) {
anatofuz
parents:
diff changeset
645 SourceLocation L = LC->getDecl()->getBodyRBrace();
anatofuz
parents:
diff changeset
646 return PathDiagnosticLocation(L, SM, SingleLocK);
anatofuz
parents:
diff changeset
647 }
anatofuz
parents:
diff changeset
648
anatofuz
parents:
diff changeset
649 PathDiagnosticLocation
anatofuz
parents:
diff changeset
650 PathDiagnosticLocation::create(const ProgramPoint& P,
anatofuz
parents:
diff changeset
651 const SourceManager &SMng) {
anatofuz
parents:
diff changeset
652 const Stmt* S = nullptr;
anatofuz
parents:
diff changeset
653 if (Optional<BlockEdge> BE = P.getAs<BlockEdge>()) {
anatofuz
parents:
diff changeset
654 const CFGBlock *BSrc = BE->getSrc();
anatofuz
parents:
diff changeset
655 if (BSrc->getTerminator().isVirtualBaseBranch()) {
anatofuz
parents:
diff changeset
656 // TODO: VirtualBaseBranches should also appear for destructors.
anatofuz
parents:
diff changeset
657 // In this case we should put the diagnostic at the end of decl.
anatofuz
parents:
diff changeset
658 return PathDiagnosticLocation::createBegin(
anatofuz
parents:
diff changeset
659 P.getLocationContext()->getDecl(), SMng);
anatofuz
parents:
diff changeset
660
anatofuz
parents:
diff changeset
661 } else {
anatofuz
parents:
diff changeset
662 S = BSrc->getTerminatorCondition();
anatofuz
parents:
diff changeset
663 if (!S) {
anatofuz
parents:
diff changeset
664 // If the BlockEdge has no terminator condition statement but its
anatofuz
parents:
diff changeset
665 // source is the entry of the CFG (e.g. a checker crated the branch at
anatofuz
parents:
diff changeset
666 // the beginning of a function), use the function's declaration instead.
anatofuz
parents:
diff changeset
667 assert(BSrc == &BSrc->getParent()->getEntry() && "CFGBlock has no "
anatofuz
parents:
diff changeset
668 "TerminatorCondition and is not the enrty block of the CFG");
anatofuz
parents:
diff changeset
669 return PathDiagnosticLocation::createBegin(
anatofuz
parents:
diff changeset
670 P.getLocationContext()->getDecl(), SMng);
anatofuz
parents:
diff changeset
671 }
anatofuz
parents:
diff changeset
672 }
anatofuz
parents:
diff changeset
673 } else if (Optional<StmtPoint> SP = P.getAs<StmtPoint>()) {
anatofuz
parents:
diff changeset
674 S = SP->getStmt();
anatofuz
parents:
diff changeset
675 if (P.getAs<PostStmtPurgeDeadSymbols>())
anatofuz
parents:
diff changeset
676 return PathDiagnosticLocation::createEnd(S, SMng, P.getLocationContext());
anatofuz
parents:
diff changeset
677 } else if (Optional<PostInitializer> PIP = P.getAs<PostInitializer>()) {
anatofuz
parents:
diff changeset
678 return PathDiagnosticLocation(PIP->getInitializer()->getSourceLocation(),
anatofuz
parents:
diff changeset
679 SMng);
anatofuz
parents:
diff changeset
680 } else if (Optional<PreImplicitCall> PIC = P.getAs<PreImplicitCall>()) {
anatofuz
parents:
diff changeset
681 return PathDiagnosticLocation(PIC->getLocation(), SMng);
anatofuz
parents:
diff changeset
682 } else if (Optional<PostImplicitCall> PIE = P.getAs<PostImplicitCall>()) {
anatofuz
parents:
diff changeset
683 return PathDiagnosticLocation(PIE->getLocation(), SMng);
anatofuz
parents:
diff changeset
684 } else if (Optional<CallEnter> CE = P.getAs<CallEnter>()) {
anatofuz
parents:
diff changeset
685 return getLocationForCaller(CE->getCalleeContext(),
anatofuz
parents:
diff changeset
686 CE->getLocationContext(),
anatofuz
parents:
diff changeset
687 SMng);
anatofuz
parents:
diff changeset
688 } else if (Optional<CallExitEnd> CEE = P.getAs<CallExitEnd>()) {
anatofuz
parents:
diff changeset
689 return getLocationForCaller(CEE->getCalleeContext(),
anatofuz
parents:
diff changeset
690 CEE->getLocationContext(),
anatofuz
parents:
diff changeset
691 SMng);
anatofuz
parents:
diff changeset
692 } else if (auto CEB = P.getAs<CallExitBegin>()) {
anatofuz
parents:
diff changeset
693 if (const ReturnStmt *RS = CEB->getReturnStmt())
anatofuz
parents:
diff changeset
694 return PathDiagnosticLocation::createBegin(RS, SMng,
anatofuz
parents:
diff changeset
695 CEB->getLocationContext());
anatofuz
parents:
diff changeset
696 return PathDiagnosticLocation(
anatofuz
parents:
diff changeset
697 CEB->getLocationContext()->getDecl()->getSourceRange().getEnd(), SMng);
anatofuz
parents:
diff changeset
698 } else if (Optional<BlockEntrance> BE = P.getAs<BlockEntrance>()) {
anatofuz
parents:
diff changeset
699 if (Optional<CFGElement> BlockFront = BE->getFirstElement()) {
anatofuz
parents:
diff changeset
700 if (auto StmtElt = BlockFront->getAs<CFGStmt>()) {
anatofuz
parents:
diff changeset
701 return PathDiagnosticLocation(StmtElt->getStmt()->getBeginLoc(), SMng);
anatofuz
parents:
diff changeset
702 } else if (auto NewAllocElt = BlockFront->getAs<CFGNewAllocator>()) {
anatofuz
parents:
diff changeset
703 return PathDiagnosticLocation(
anatofuz
parents:
diff changeset
704 NewAllocElt->getAllocatorExpr()->getBeginLoc(), SMng);
anatofuz
parents:
diff changeset
705 }
anatofuz
parents:
diff changeset
706 llvm_unreachable("Unexpected CFG element at front of block");
anatofuz
parents:
diff changeset
707 }
anatofuz
parents:
diff changeset
708
anatofuz
parents:
diff changeset
709 return PathDiagnosticLocation(
anatofuz
parents:
diff changeset
710 BE->getBlock()->getTerminatorStmt()->getBeginLoc(), SMng);
anatofuz
parents:
diff changeset
711 } else if (Optional<FunctionExitPoint> FE = P.getAs<FunctionExitPoint>()) {
anatofuz
parents:
diff changeset
712 return PathDiagnosticLocation(FE->getStmt(), SMng,
anatofuz
parents:
diff changeset
713 FE->getLocationContext());
anatofuz
parents:
diff changeset
714 } else {
anatofuz
parents:
diff changeset
715 llvm_unreachable("Unexpected ProgramPoint");
anatofuz
parents:
diff changeset
716 }
anatofuz
parents:
diff changeset
717
anatofuz
parents:
diff changeset
718 return PathDiagnosticLocation(S, SMng, P.getLocationContext());
anatofuz
parents:
diff changeset
719 }
anatofuz
parents:
diff changeset
720
anatofuz
parents:
diff changeset
721 PathDiagnosticLocation PathDiagnosticLocation::createSingleLocation(
anatofuz
parents:
diff changeset
722 const PathDiagnosticLocation &PDL) {
anatofuz
parents:
diff changeset
723 FullSourceLoc L = PDL.asLocation();
anatofuz
parents:
diff changeset
724 return PathDiagnosticLocation(L, L.getManager(), SingleLocK);
anatofuz
parents:
diff changeset
725 }
anatofuz
parents:
diff changeset
726
anatofuz
parents:
diff changeset
727 FullSourceLoc
anatofuz
parents:
diff changeset
728 PathDiagnosticLocation::genLocation(SourceLocation L,
anatofuz
parents:
diff changeset
729 LocationOrAnalysisDeclContext LAC) const {
anatofuz
parents:
diff changeset
730 assert(isValid());
anatofuz
parents:
diff changeset
731 // Note that we want a 'switch' here so that the compiler can warn us in
anatofuz
parents:
diff changeset
732 // case we add more cases.
anatofuz
parents:
diff changeset
733 switch (K) {
anatofuz
parents:
diff changeset
734 case SingleLocK:
anatofuz
parents:
diff changeset
735 case RangeK:
anatofuz
parents:
diff changeset
736 break;
anatofuz
parents:
diff changeset
737 case StmtK:
anatofuz
parents:
diff changeset
738 // Defensive checking.
anatofuz
parents:
diff changeset
739 if (!S)
anatofuz
parents:
diff changeset
740 break;
anatofuz
parents:
diff changeset
741 return FullSourceLoc(getValidSourceLocation(S, LAC),
anatofuz
parents:
diff changeset
742 const_cast<SourceManager&>(*SM));
anatofuz
parents:
diff changeset
743 case DeclK:
anatofuz
parents:
diff changeset
744 // Defensive checking.
anatofuz
parents:
diff changeset
745 if (!D)
anatofuz
parents:
diff changeset
746 break;
anatofuz
parents:
diff changeset
747 return FullSourceLoc(D->getLocation(), const_cast<SourceManager&>(*SM));
anatofuz
parents:
diff changeset
748 }
anatofuz
parents:
diff changeset
749
anatofuz
parents:
diff changeset
750 return FullSourceLoc(L, const_cast<SourceManager&>(*SM));
anatofuz
parents:
diff changeset
751 }
anatofuz
parents:
diff changeset
752
anatofuz
parents:
diff changeset
753 PathDiagnosticRange
anatofuz
parents:
diff changeset
754 PathDiagnosticLocation::genRange(LocationOrAnalysisDeclContext LAC) const {
anatofuz
parents:
diff changeset
755 assert(isValid());
anatofuz
parents:
diff changeset
756 // Note that we want a 'switch' here so that the compiler can warn us in
anatofuz
parents:
diff changeset
757 // case we add more cases.
anatofuz
parents:
diff changeset
758 switch (K) {
anatofuz
parents:
diff changeset
759 case SingleLocK:
anatofuz
parents:
diff changeset
760 return PathDiagnosticRange(SourceRange(Loc,Loc), true);
anatofuz
parents:
diff changeset
761 case RangeK:
anatofuz
parents:
diff changeset
762 break;
anatofuz
parents:
diff changeset
763 case StmtK: {
anatofuz
parents:
diff changeset
764 const Stmt *S = asStmt();
anatofuz
parents:
diff changeset
765 switch (S->getStmtClass()) {
anatofuz
parents:
diff changeset
766 default:
anatofuz
parents:
diff changeset
767 break;
anatofuz
parents:
diff changeset
768 case Stmt::DeclStmtClass: {
anatofuz
parents:
diff changeset
769 const auto *DS = cast<DeclStmt>(S);
anatofuz
parents:
diff changeset
770 if (DS->isSingleDecl()) {
anatofuz
parents:
diff changeset
771 // Should always be the case, but we'll be defensive.
anatofuz
parents:
diff changeset
772 return SourceRange(DS->getBeginLoc(),
anatofuz
parents:
diff changeset
773 DS->getSingleDecl()->getLocation());
anatofuz
parents:
diff changeset
774 }
anatofuz
parents:
diff changeset
775 break;
anatofuz
parents:
diff changeset
776 }
anatofuz
parents:
diff changeset
777 // FIXME: Provide better range information for different
anatofuz
parents:
diff changeset
778 // terminators.
anatofuz
parents:
diff changeset
779 case Stmt::IfStmtClass:
anatofuz
parents:
diff changeset
780 case Stmt::WhileStmtClass:
anatofuz
parents:
diff changeset
781 case Stmt::DoStmtClass:
anatofuz
parents:
diff changeset
782 case Stmt::ForStmtClass:
anatofuz
parents:
diff changeset
783 case Stmt::ChooseExprClass:
anatofuz
parents:
diff changeset
784 case Stmt::IndirectGotoStmtClass:
anatofuz
parents:
diff changeset
785 case Stmt::SwitchStmtClass:
anatofuz
parents:
diff changeset
786 case Stmt::BinaryConditionalOperatorClass:
anatofuz
parents:
diff changeset
787 case Stmt::ConditionalOperatorClass:
anatofuz
parents:
diff changeset
788 case Stmt::ObjCForCollectionStmtClass: {
anatofuz
parents:
diff changeset
789 SourceLocation L = getValidSourceLocation(S, LAC);
anatofuz
parents:
diff changeset
790 return SourceRange(L, L);
anatofuz
parents:
diff changeset
791 }
anatofuz
parents:
diff changeset
792 }
anatofuz
parents:
diff changeset
793 SourceRange R = S->getSourceRange();
anatofuz
parents:
diff changeset
794 if (R.isValid())
anatofuz
parents:
diff changeset
795 return R;
anatofuz
parents:
diff changeset
796 break;
anatofuz
parents:
diff changeset
797 }
anatofuz
parents:
diff changeset
798 case DeclK:
anatofuz
parents:
diff changeset
799 if (const auto *MD = dyn_cast<ObjCMethodDecl>(D))
anatofuz
parents:
diff changeset
800 return MD->getSourceRange();
anatofuz
parents:
diff changeset
801 if (const auto *FD = dyn_cast<FunctionDecl>(D)) {
anatofuz
parents:
diff changeset
802 if (Stmt *Body = FD->getBody())
anatofuz
parents:
diff changeset
803 return Body->getSourceRange();
anatofuz
parents:
diff changeset
804 }
anatofuz
parents:
diff changeset
805 else {
anatofuz
parents:
diff changeset
806 SourceLocation L = D->getLocation();
anatofuz
parents:
diff changeset
807 return PathDiagnosticRange(SourceRange(L, L), true);
anatofuz
parents:
diff changeset
808 }
anatofuz
parents:
diff changeset
809 }
anatofuz
parents:
diff changeset
810
anatofuz
parents:
diff changeset
811 return SourceRange(Loc, Loc);
anatofuz
parents:
diff changeset
812 }
anatofuz
parents:
diff changeset
813
anatofuz
parents:
diff changeset
814 void PathDiagnosticLocation::flatten() {
anatofuz
parents:
diff changeset
815 if (K == StmtK) {
anatofuz
parents:
diff changeset
816 K = RangeK;
anatofuz
parents:
diff changeset
817 S = nullptr;
anatofuz
parents:
diff changeset
818 D = nullptr;
anatofuz
parents:
diff changeset
819 }
anatofuz
parents:
diff changeset
820 else if (K == DeclK) {
anatofuz
parents:
diff changeset
821 K = SingleLocK;
anatofuz
parents:
diff changeset
822 S = nullptr;
anatofuz
parents:
diff changeset
823 D = nullptr;
anatofuz
parents:
diff changeset
824 }
anatofuz
parents:
diff changeset
825 }
anatofuz
parents:
diff changeset
826
anatofuz
parents:
diff changeset
827 //===----------------------------------------------------------------------===//
anatofuz
parents:
diff changeset
828 // Manipulation of PathDiagnosticCallPieces.
anatofuz
parents:
diff changeset
829 //===----------------------------------------------------------------------===//
anatofuz
parents:
diff changeset
830
anatofuz
parents:
diff changeset
831 std::shared_ptr<PathDiagnosticCallPiece>
anatofuz
parents:
diff changeset
832 PathDiagnosticCallPiece::construct(const CallExitEnd &CE,
anatofuz
parents:
diff changeset
833 const SourceManager &SM) {
anatofuz
parents:
diff changeset
834 const Decl *caller = CE.getLocationContext()->getDecl();
anatofuz
parents:
diff changeset
835 PathDiagnosticLocation pos = getLocationForCaller(CE.getCalleeContext(),
anatofuz
parents:
diff changeset
836 CE.getLocationContext(),
anatofuz
parents:
diff changeset
837 SM);
anatofuz
parents:
diff changeset
838 return std::shared_ptr<PathDiagnosticCallPiece>(
anatofuz
parents:
diff changeset
839 new PathDiagnosticCallPiece(caller, pos));
anatofuz
parents:
diff changeset
840 }
anatofuz
parents:
diff changeset
841
anatofuz
parents:
diff changeset
842 PathDiagnosticCallPiece *
anatofuz
parents:
diff changeset
843 PathDiagnosticCallPiece::construct(PathPieces &path,
anatofuz
parents:
diff changeset
844 const Decl *caller) {
anatofuz
parents:
diff changeset
845 std::shared_ptr<PathDiagnosticCallPiece> C(
anatofuz
parents:
diff changeset
846 new PathDiagnosticCallPiece(path, caller));
anatofuz
parents:
diff changeset
847 path.clear();
anatofuz
parents:
diff changeset
848 auto *R = C.get();
anatofuz
parents:
diff changeset
849 path.push_front(std::move(C));
anatofuz
parents:
diff changeset
850 return R;
anatofuz
parents:
diff changeset
851 }
anatofuz
parents:
diff changeset
852
anatofuz
parents:
diff changeset
853 void PathDiagnosticCallPiece::setCallee(const CallEnter &CE,
anatofuz
parents:
diff changeset
854 const SourceManager &SM) {
anatofuz
parents:
diff changeset
855 const StackFrameContext *CalleeCtx = CE.getCalleeContext();
anatofuz
parents:
diff changeset
856 Callee = CalleeCtx->getDecl();
anatofuz
parents:
diff changeset
857
anatofuz
parents:
diff changeset
858 callEnterWithin = PathDiagnosticLocation::createBegin(Callee, SM);
anatofuz
parents:
diff changeset
859 callEnter = getLocationForCaller(CalleeCtx, CE.getLocationContext(), SM);
anatofuz
parents:
diff changeset
860
anatofuz
parents:
diff changeset
861 // Autosynthesized property accessors are special because we'd never
anatofuz
parents:
diff changeset
862 // pop back up to non-autosynthesized code until we leave them.
anatofuz
parents:
diff changeset
863 // This is not generally true for autosynthesized callees, which may call
anatofuz
parents:
diff changeset
864 // non-autosynthesized callbacks.
anatofuz
parents:
diff changeset
865 // Unless set here, the IsCalleeAnAutosynthesizedPropertyAccessor flag
anatofuz
parents:
diff changeset
866 // defaults to false.
anatofuz
parents:
diff changeset
867 if (const auto *MD = dyn_cast<ObjCMethodDecl>(Callee))
anatofuz
parents:
diff changeset
868 IsCalleeAnAutosynthesizedPropertyAccessor = (
anatofuz
parents:
diff changeset
869 MD->isPropertyAccessor() &&
anatofuz
parents:
diff changeset
870 CalleeCtx->getAnalysisDeclContext()->isBodyAutosynthesized());
anatofuz
parents:
diff changeset
871 }
anatofuz
parents:
diff changeset
872
anatofuz
parents:
diff changeset
873 static void describeTemplateParameters(raw_ostream &Out,
anatofuz
parents:
diff changeset
874 const ArrayRef<TemplateArgument> TAList,
anatofuz
parents:
diff changeset
875 const LangOptions &LO,
anatofuz
parents:
diff changeset
876 StringRef Prefix = StringRef(),
anatofuz
parents:
diff changeset
877 StringRef Postfix = StringRef());
anatofuz
parents:
diff changeset
878
anatofuz
parents:
diff changeset
879 static void describeTemplateParameter(raw_ostream &Out,
anatofuz
parents:
diff changeset
880 const TemplateArgument &TArg,
anatofuz
parents:
diff changeset
881 const LangOptions &LO) {
anatofuz
parents:
diff changeset
882
anatofuz
parents:
diff changeset
883 if (TArg.getKind() == TemplateArgument::ArgKind::Pack) {
anatofuz
parents:
diff changeset
884 describeTemplateParameters(Out, TArg.getPackAsArray(), LO);
anatofuz
parents:
diff changeset
885 } else {
anatofuz
parents:
diff changeset
886 TArg.print(PrintingPolicy(LO), Out);
anatofuz
parents:
diff changeset
887 }
anatofuz
parents:
diff changeset
888 }
anatofuz
parents:
diff changeset
889
anatofuz
parents:
diff changeset
890 static void describeTemplateParameters(raw_ostream &Out,
anatofuz
parents:
diff changeset
891 const ArrayRef<TemplateArgument> TAList,
anatofuz
parents:
diff changeset
892 const LangOptions &LO,
anatofuz
parents:
diff changeset
893 StringRef Prefix, StringRef Postfix) {
anatofuz
parents:
diff changeset
894 if (TAList.empty())
anatofuz
parents:
diff changeset
895 return;
anatofuz
parents:
diff changeset
896
anatofuz
parents:
diff changeset
897 Out << Prefix;
anatofuz
parents:
diff changeset
898 for (int I = 0, Last = TAList.size() - 1; I != Last; ++I) {
anatofuz
parents:
diff changeset
899 describeTemplateParameter(Out, TAList[I], LO);
anatofuz
parents:
diff changeset
900 Out << ", ";
anatofuz
parents:
diff changeset
901 }
anatofuz
parents:
diff changeset
902 describeTemplateParameter(Out, TAList[TAList.size() - 1], LO);
anatofuz
parents:
diff changeset
903 Out << Postfix;
anatofuz
parents:
diff changeset
904 }
anatofuz
parents:
diff changeset
905
anatofuz
parents:
diff changeset
906 static void describeClass(raw_ostream &Out, const CXXRecordDecl *D,
anatofuz
parents:
diff changeset
907 StringRef Prefix = StringRef()) {
anatofuz
parents:
diff changeset
908 if (!D->getIdentifier())
anatofuz
parents:
diff changeset
909 return;
anatofuz
parents:
diff changeset
910 Out << Prefix << '\'' << *D;
anatofuz
parents:
diff changeset
911 if (const auto T = dyn_cast<ClassTemplateSpecializationDecl>(D))
anatofuz
parents:
diff changeset
912 describeTemplateParameters(Out, T->getTemplateArgs().asArray(),
173
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
913 D->getLangOpts(), "<", ">");
150
anatofuz
parents:
diff changeset
914
anatofuz
parents:
diff changeset
915 Out << '\'';
anatofuz
parents:
diff changeset
916 }
anatofuz
parents:
diff changeset
917
anatofuz
parents:
diff changeset
918 static bool describeCodeDecl(raw_ostream &Out, const Decl *D,
anatofuz
parents:
diff changeset
919 bool ExtendedDescription,
anatofuz
parents:
diff changeset
920 StringRef Prefix = StringRef()) {
anatofuz
parents:
diff changeset
921 if (!D)
anatofuz
parents:
diff changeset
922 return false;
anatofuz
parents:
diff changeset
923
anatofuz
parents:
diff changeset
924 if (isa<BlockDecl>(D)) {
anatofuz
parents:
diff changeset
925 if (ExtendedDescription)
anatofuz
parents:
diff changeset
926 Out << Prefix << "anonymous block";
anatofuz
parents:
diff changeset
927 return ExtendedDescription;
anatofuz
parents:
diff changeset
928 }
anatofuz
parents:
diff changeset
929
anatofuz
parents:
diff changeset
930 if (const auto *MD = dyn_cast<CXXMethodDecl>(D)) {
anatofuz
parents:
diff changeset
931 Out << Prefix;
anatofuz
parents:
diff changeset
932 if (ExtendedDescription && !MD->isUserProvided()) {
anatofuz
parents:
diff changeset
933 if (MD->isExplicitlyDefaulted())
anatofuz
parents:
diff changeset
934 Out << "defaulted ";
anatofuz
parents:
diff changeset
935 else
anatofuz
parents:
diff changeset
936 Out << "implicit ";
anatofuz
parents:
diff changeset
937 }
anatofuz
parents:
diff changeset
938
anatofuz
parents:
diff changeset
939 if (const auto *CD = dyn_cast<CXXConstructorDecl>(MD)) {
anatofuz
parents:
diff changeset
940 if (CD->isDefaultConstructor())
anatofuz
parents:
diff changeset
941 Out << "default ";
anatofuz
parents:
diff changeset
942 else if (CD->isCopyConstructor())
anatofuz
parents:
diff changeset
943 Out << "copy ";
anatofuz
parents:
diff changeset
944 else if (CD->isMoveConstructor())
anatofuz
parents:
diff changeset
945 Out << "move ";
anatofuz
parents:
diff changeset
946
anatofuz
parents:
diff changeset
947 Out << "constructor";
anatofuz
parents:
diff changeset
948 describeClass(Out, MD->getParent(), " for ");
anatofuz
parents:
diff changeset
949 } else if (isa<CXXDestructorDecl>(MD)) {
anatofuz
parents:
diff changeset
950 if (!MD->isUserProvided()) {
anatofuz
parents:
diff changeset
951 Out << "destructor";
anatofuz
parents:
diff changeset
952 describeClass(Out, MD->getParent(), " for ");
anatofuz
parents:
diff changeset
953 } else {
anatofuz
parents:
diff changeset
954 // Use ~Foo for explicitly-written destructors.
anatofuz
parents:
diff changeset
955 Out << "'" << *MD << "'";
anatofuz
parents:
diff changeset
956 }
anatofuz
parents:
diff changeset
957 } else if (MD->isCopyAssignmentOperator()) {
anatofuz
parents:
diff changeset
958 Out << "copy assignment operator";
anatofuz
parents:
diff changeset
959 describeClass(Out, MD->getParent(), " for ");
anatofuz
parents:
diff changeset
960 } else if (MD->isMoveAssignmentOperator()) {
anatofuz
parents:
diff changeset
961 Out << "move assignment operator";
anatofuz
parents:
diff changeset
962 describeClass(Out, MD->getParent(), " for ");
anatofuz
parents:
diff changeset
963 } else {
anatofuz
parents:
diff changeset
964 if (MD->getParent()->getIdentifier())
anatofuz
parents:
diff changeset
965 Out << "'" << *MD->getParent() << "::" << *MD << "'";
anatofuz
parents:
diff changeset
966 else
anatofuz
parents:
diff changeset
967 Out << "'" << *MD << "'";
anatofuz
parents:
diff changeset
968 }
anatofuz
parents:
diff changeset
969
anatofuz
parents:
diff changeset
970 return true;
anatofuz
parents:
diff changeset
971 }
anatofuz
parents:
diff changeset
972
anatofuz
parents:
diff changeset
973 Out << Prefix << '\'' << cast<NamedDecl>(*D);
anatofuz
parents:
diff changeset
974
anatofuz
parents:
diff changeset
975 // Adding template parameters.
anatofuz
parents:
diff changeset
976 if (const auto FD = dyn_cast<FunctionDecl>(D))
anatofuz
parents:
diff changeset
977 if (const TemplateArgumentList *TAList =
anatofuz
parents:
diff changeset
978 FD->getTemplateSpecializationArgs())
173
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
979 describeTemplateParameters(Out, TAList->asArray(), FD->getLangOpts(), "<",
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
980 ">");
150
anatofuz
parents:
diff changeset
981
anatofuz
parents:
diff changeset
982 Out << '\'';
anatofuz
parents:
diff changeset
983 return true;
anatofuz
parents:
diff changeset
984 }
anatofuz
parents:
diff changeset
985
anatofuz
parents:
diff changeset
986 std::shared_ptr<PathDiagnosticEventPiece>
anatofuz
parents:
diff changeset
987 PathDiagnosticCallPiece::getCallEnterEvent() const {
anatofuz
parents:
diff changeset
988 // We do not produce call enters and call exits for autosynthesized property
anatofuz
parents:
diff changeset
989 // accessors. We do generally produce them for other functions coming from
anatofuz
parents:
diff changeset
990 // the body farm because they may call callbacks that bring us back into
anatofuz
parents:
diff changeset
991 // visible code.
anatofuz
parents:
diff changeset
992 if (!Callee || IsCalleeAnAutosynthesizedPropertyAccessor)
anatofuz
parents:
diff changeset
993 return nullptr;
anatofuz
parents:
diff changeset
994
anatofuz
parents:
diff changeset
995 SmallString<256> buf;
anatofuz
parents:
diff changeset
996 llvm::raw_svector_ostream Out(buf);
anatofuz
parents:
diff changeset
997
anatofuz
parents:
diff changeset
998 Out << "Calling ";
anatofuz
parents:
diff changeset
999 describeCodeDecl(Out, Callee, /*ExtendedDescription=*/true);
anatofuz
parents:
diff changeset
1000
anatofuz
parents:
diff changeset
1001 assert(callEnter.asLocation().isValid());
anatofuz
parents:
diff changeset
1002 return std::make_shared<PathDiagnosticEventPiece>(callEnter, Out.str());
anatofuz
parents:
diff changeset
1003 }
anatofuz
parents:
diff changeset
1004
anatofuz
parents:
diff changeset
1005 std::shared_ptr<PathDiagnosticEventPiece>
anatofuz
parents:
diff changeset
1006 PathDiagnosticCallPiece::getCallEnterWithinCallerEvent() const {
anatofuz
parents:
diff changeset
1007 if (!callEnterWithin.asLocation().isValid())
anatofuz
parents:
diff changeset
1008 return nullptr;
anatofuz
parents:
diff changeset
1009 if (Callee->isImplicit() || !Callee->hasBody())
anatofuz
parents:
diff changeset
1010 return nullptr;
anatofuz
parents:
diff changeset
1011 if (const auto *MD = dyn_cast<CXXMethodDecl>(Callee))
anatofuz
parents:
diff changeset
1012 if (MD->isDefaulted())
anatofuz
parents:
diff changeset
1013 return nullptr;
anatofuz
parents:
diff changeset
1014
anatofuz
parents:
diff changeset
1015 SmallString<256> buf;
anatofuz
parents:
diff changeset
1016 llvm::raw_svector_ostream Out(buf);
anatofuz
parents:
diff changeset
1017
anatofuz
parents:
diff changeset
1018 Out << "Entered call";
anatofuz
parents:
diff changeset
1019 describeCodeDecl(Out, Caller, /*ExtendedDescription=*/false, " from ");
anatofuz
parents:
diff changeset
1020
anatofuz
parents:
diff changeset
1021 return std::make_shared<PathDiagnosticEventPiece>(callEnterWithin, Out.str());
anatofuz
parents:
diff changeset
1022 }
anatofuz
parents:
diff changeset
1023
anatofuz
parents:
diff changeset
1024 std::shared_ptr<PathDiagnosticEventPiece>
anatofuz
parents:
diff changeset
1025 PathDiagnosticCallPiece::getCallExitEvent() const {
anatofuz
parents:
diff changeset
1026 // We do not produce call enters and call exits for autosynthesized property
anatofuz
parents:
diff changeset
1027 // accessors. We do generally produce them for other functions coming from
anatofuz
parents:
diff changeset
1028 // the body farm because they may call callbacks that bring us back into
anatofuz
parents:
diff changeset
1029 // visible code.
anatofuz
parents:
diff changeset
1030 if (NoExit || IsCalleeAnAutosynthesizedPropertyAccessor)
anatofuz
parents:
diff changeset
1031 return nullptr;
anatofuz
parents:
diff changeset
1032
anatofuz
parents:
diff changeset
1033 SmallString<256> buf;
anatofuz
parents:
diff changeset
1034 llvm::raw_svector_ostream Out(buf);
anatofuz
parents:
diff changeset
1035
anatofuz
parents:
diff changeset
1036 if (!CallStackMessage.empty()) {
anatofuz
parents:
diff changeset
1037 Out << CallStackMessage;
anatofuz
parents:
diff changeset
1038 } else {
anatofuz
parents:
diff changeset
1039 bool DidDescribe = describeCodeDecl(Out, Callee,
anatofuz
parents:
diff changeset
1040 /*ExtendedDescription=*/false,
anatofuz
parents:
diff changeset
1041 "Returning from ");
anatofuz
parents:
diff changeset
1042 if (!DidDescribe)
anatofuz
parents:
diff changeset
1043 Out << "Returning to caller";
anatofuz
parents:
diff changeset
1044 }
anatofuz
parents:
diff changeset
1045
anatofuz
parents:
diff changeset
1046 assert(callReturn.asLocation().isValid());
anatofuz
parents:
diff changeset
1047 return std::make_shared<PathDiagnosticEventPiece>(callReturn, Out.str());
anatofuz
parents:
diff changeset
1048 }
anatofuz
parents:
diff changeset
1049
anatofuz
parents:
diff changeset
1050 static void compute_path_size(const PathPieces &pieces, unsigned &size) {
anatofuz
parents:
diff changeset
1051 for (const auto &I : pieces) {
anatofuz
parents:
diff changeset
1052 const PathDiagnosticPiece *piece = I.get();
anatofuz
parents:
diff changeset
1053 if (const auto *cp = dyn_cast<PathDiagnosticCallPiece>(piece))
anatofuz
parents:
diff changeset
1054 compute_path_size(cp->path, size);
anatofuz
parents:
diff changeset
1055 else
anatofuz
parents:
diff changeset
1056 ++size;
anatofuz
parents:
diff changeset
1057 }
anatofuz
parents:
diff changeset
1058 }
anatofuz
parents:
diff changeset
1059
anatofuz
parents:
diff changeset
1060 unsigned PathDiagnostic::full_size() {
anatofuz
parents:
diff changeset
1061 unsigned size = 0;
anatofuz
parents:
diff changeset
1062 compute_path_size(path, size);
anatofuz
parents:
diff changeset
1063 return size;
anatofuz
parents:
diff changeset
1064 }
anatofuz
parents:
diff changeset
1065
anatofuz
parents:
diff changeset
1066 //===----------------------------------------------------------------------===//
anatofuz
parents:
diff changeset
1067 // FoldingSet profiling methods.
anatofuz
parents:
diff changeset
1068 //===----------------------------------------------------------------------===//
anatofuz
parents:
diff changeset
1069
anatofuz
parents:
diff changeset
1070 void PathDiagnosticLocation::Profile(llvm::FoldingSetNodeID &ID) const {
anatofuz
parents:
diff changeset
1071 ID.AddInteger(Range.getBegin().getRawEncoding());
anatofuz
parents:
diff changeset
1072 ID.AddInteger(Range.getEnd().getRawEncoding());
anatofuz
parents:
diff changeset
1073 ID.AddInteger(Loc.getRawEncoding());
anatofuz
parents:
diff changeset
1074 }
anatofuz
parents:
diff changeset
1075
anatofuz
parents:
diff changeset
1076 void PathDiagnosticPiece::Profile(llvm::FoldingSetNodeID &ID) const {
anatofuz
parents:
diff changeset
1077 ID.AddInteger((unsigned) getKind());
anatofuz
parents:
diff changeset
1078 ID.AddString(str);
anatofuz
parents:
diff changeset
1079 // FIXME: Add profiling support for code hints.
anatofuz
parents:
diff changeset
1080 ID.AddInteger((unsigned) getDisplayHint());
anatofuz
parents:
diff changeset
1081 ArrayRef<SourceRange> Ranges = getRanges();
anatofuz
parents:
diff changeset
1082 for (const auto &I : Ranges) {
anatofuz
parents:
diff changeset
1083 ID.AddInteger(I.getBegin().getRawEncoding());
anatofuz
parents:
diff changeset
1084 ID.AddInteger(I.getEnd().getRawEncoding());
anatofuz
parents:
diff changeset
1085 }
anatofuz
parents:
diff changeset
1086 }
anatofuz
parents:
diff changeset
1087
anatofuz
parents:
diff changeset
1088 void PathDiagnosticCallPiece::Profile(llvm::FoldingSetNodeID &ID) const {
anatofuz
parents:
diff changeset
1089 PathDiagnosticPiece::Profile(ID);
anatofuz
parents:
diff changeset
1090 for (const auto &I : path)
anatofuz
parents:
diff changeset
1091 ID.Add(*I);
anatofuz
parents:
diff changeset
1092 }
anatofuz
parents:
diff changeset
1093
anatofuz
parents:
diff changeset
1094 void PathDiagnosticSpotPiece::Profile(llvm::FoldingSetNodeID &ID) const {
anatofuz
parents:
diff changeset
1095 PathDiagnosticPiece::Profile(ID);
anatofuz
parents:
diff changeset
1096 ID.Add(Pos);
anatofuz
parents:
diff changeset
1097 }
anatofuz
parents:
diff changeset
1098
anatofuz
parents:
diff changeset
1099 void PathDiagnosticControlFlowPiece::Profile(llvm::FoldingSetNodeID &ID) const {
anatofuz
parents:
diff changeset
1100 PathDiagnosticPiece::Profile(ID);
anatofuz
parents:
diff changeset
1101 for (const auto &I : *this)
anatofuz
parents:
diff changeset
1102 ID.Add(I);
anatofuz
parents:
diff changeset
1103 }
anatofuz
parents:
diff changeset
1104
anatofuz
parents:
diff changeset
1105 void PathDiagnosticMacroPiece::Profile(llvm::FoldingSetNodeID &ID) const {
anatofuz
parents:
diff changeset
1106 PathDiagnosticSpotPiece::Profile(ID);
anatofuz
parents:
diff changeset
1107 for (const auto &I : subPieces)
anatofuz
parents:
diff changeset
1108 ID.Add(*I);
anatofuz
parents:
diff changeset
1109 }
anatofuz
parents:
diff changeset
1110
anatofuz
parents:
diff changeset
1111 void PathDiagnosticNotePiece::Profile(llvm::FoldingSetNodeID &ID) const {
anatofuz
parents:
diff changeset
1112 PathDiagnosticSpotPiece::Profile(ID);
anatofuz
parents:
diff changeset
1113 }
anatofuz
parents:
diff changeset
1114
anatofuz
parents:
diff changeset
1115 void PathDiagnosticPopUpPiece::Profile(llvm::FoldingSetNodeID &ID) const {
anatofuz
parents:
diff changeset
1116 PathDiagnosticSpotPiece::Profile(ID);
anatofuz
parents:
diff changeset
1117 }
anatofuz
parents:
diff changeset
1118
anatofuz
parents:
diff changeset
1119 void PathDiagnostic::Profile(llvm::FoldingSetNodeID &ID) const {
anatofuz
parents:
diff changeset
1120 ID.Add(getLocation());
anatofuz
parents:
diff changeset
1121 ID.AddString(BugType);
anatofuz
parents:
diff changeset
1122 ID.AddString(VerboseDesc);
anatofuz
parents:
diff changeset
1123 ID.AddString(Category);
anatofuz
parents:
diff changeset
1124 }
anatofuz
parents:
diff changeset
1125
anatofuz
parents:
diff changeset
1126 void PathDiagnostic::FullProfile(llvm::FoldingSetNodeID &ID) const {
anatofuz
parents:
diff changeset
1127 Profile(ID);
anatofuz
parents:
diff changeset
1128 for (const auto &I : path)
anatofuz
parents:
diff changeset
1129 ID.Add(*I);
anatofuz
parents:
diff changeset
1130 for (meta_iterator I = meta_begin(), E = meta_end(); I != E; ++I)
anatofuz
parents:
diff changeset
1131 ID.AddString(*I);
anatofuz
parents:
diff changeset
1132 }
anatofuz
parents:
diff changeset
1133
anatofuz
parents:
diff changeset
1134 LLVM_DUMP_METHOD void PathPieces::dump() const {
anatofuz
parents:
diff changeset
1135 unsigned index = 0;
anatofuz
parents:
diff changeset
1136 for (PathPieces::const_iterator I = begin(), E = end(); I != E; ++I) {
anatofuz
parents:
diff changeset
1137 llvm::errs() << "[" << index++ << "] ";
anatofuz
parents:
diff changeset
1138 (*I)->dump();
anatofuz
parents:
diff changeset
1139 llvm::errs() << "\n";
anatofuz
parents:
diff changeset
1140 }
anatofuz
parents:
diff changeset
1141 }
anatofuz
parents:
diff changeset
1142
anatofuz
parents:
diff changeset
1143 LLVM_DUMP_METHOD void PathDiagnosticCallPiece::dump() const {
anatofuz
parents:
diff changeset
1144 llvm::errs() << "CALL\n--------------\n";
anatofuz
parents:
diff changeset
1145
anatofuz
parents:
diff changeset
1146 if (const Stmt *SLoc = getLocation().getStmtOrNull())
anatofuz
parents:
diff changeset
1147 SLoc->dump();
anatofuz
parents:
diff changeset
1148 else if (const auto *ND = dyn_cast_or_null<NamedDecl>(getCallee()))
anatofuz
parents:
diff changeset
1149 llvm::errs() << *ND << "\n";
anatofuz
parents:
diff changeset
1150 else
anatofuz
parents:
diff changeset
1151 getLocation().dump();
anatofuz
parents:
diff changeset
1152 }
anatofuz
parents:
diff changeset
1153
anatofuz
parents:
diff changeset
1154 LLVM_DUMP_METHOD void PathDiagnosticEventPiece::dump() const {
anatofuz
parents:
diff changeset
1155 llvm::errs() << "EVENT\n--------------\n";
anatofuz
parents:
diff changeset
1156 llvm::errs() << getString() << "\n";
anatofuz
parents:
diff changeset
1157 llvm::errs() << " ---- at ----\n";
anatofuz
parents:
diff changeset
1158 getLocation().dump();
anatofuz
parents:
diff changeset
1159 }
anatofuz
parents:
diff changeset
1160
anatofuz
parents:
diff changeset
1161 LLVM_DUMP_METHOD void PathDiagnosticControlFlowPiece::dump() const {
anatofuz
parents:
diff changeset
1162 llvm::errs() << "CONTROL\n--------------\n";
anatofuz
parents:
diff changeset
1163 getStartLocation().dump();
anatofuz
parents:
diff changeset
1164 llvm::errs() << " ---- to ----\n";
anatofuz
parents:
diff changeset
1165 getEndLocation().dump();
anatofuz
parents:
diff changeset
1166 }
anatofuz
parents:
diff changeset
1167
anatofuz
parents:
diff changeset
1168 LLVM_DUMP_METHOD void PathDiagnosticMacroPiece::dump() const {
anatofuz
parents:
diff changeset
1169 llvm::errs() << "MACRO\n--------------\n";
anatofuz
parents:
diff changeset
1170 // FIXME: Print which macro is being invoked.
anatofuz
parents:
diff changeset
1171 }
anatofuz
parents:
diff changeset
1172
anatofuz
parents:
diff changeset
1173 LLVM_DUMP_METHOD void PathDiagnosticNotePiece::dump() const {
anatofuz
parents:
diff changeset
1174 llvm::errs() << "NOTE\n--------------\n";
anatofuz
parents:
diff changeset
1175 llvm::errs() << getString() << "\n";
anatofuz
parents:
diff changeset
1176 llvm::errs() << " ---- at ----\n";
anatofuz
parents:
diff changeset
1177 getLocation().dump();
anatofuz
parents:
diff changeset
1178 }
anatofuz
parents:
diff changeset
1179
anatofuz
parents:
diff changeset
1180 LLVM_DUMP_METHOD void PathDiagnosticPopUpPiece::dump() const {
anatofuz
parents:
diff changeset
1181 llvm::errs() << "POP-UP\n--------------\n";
anatofuz
parents:
diff changeset
1182 llvm::errs() << getString() << "\n";
anatofuz
parents:
diff changeset
1183 llvm::errs() << " ---- at ----\n";
anatofuz
parents:
diff changeset
1184 getLocation().dump();
anatofuz
parents:
diff changeset
1185 }
anatofuz
parents:
diff changeset
1186
anatofuz
parents:
diff changeset
1187 LLVM_DUMP_METHOD void PathDiagnosticLocation::dump() const {
anatofuz
parents:
diff changeset
1188 if (!isValid()) {
anatofuz
parents:
diff changeset
1189 llvm::errs() << "<INVALID>\n";
anatofuz
parents:
diff changeset
1190 return;
anatofuz
parents:
diff changeset
1191 }
anatofuz
parents:
diff changeset
1192
anatofuz
parents:
diff changeset
1193 switch (K) {
anatofuz
parents:
diff changeset
1194 case RangeK:
anatofuz
parents:
diff changeset
1195 // FIXME: actually print the range.
anatofuz
parents:
diff changeset
1196 llvm::errs() << "<range>\n";
anatofuz
parents:
diff changeset
1197 break;
anatofuz
parents:
diff changeset
1198 case SingleLocK:
anatofuz
parents:
diff changeset
1199 asLocation().dump();
anatofuz
parents:
diff changeset
1200 llvm::errs() << "\n";
anatofuz
parents:
diff changeset
1201 break;
anatofuz
parents:
diff changeset
1202 case StmtK:
anatofuz
parents:
diff changeset
1203 if (S)
anatofuz
parents:
diff changeset
1204 S->dump();
anatofuz
parents:
diff changeset
1205 else
anatofuz
parents:
diff changeset
1206 llvm::errs() << "<NULL STMT>\n";
anatofuz
parents:
diff changeset
1207 break;
anatofuz
parents:
diff changeset
1208 case DeclK:
anatofuz
parents:
diff changeset
1209 if (const auto *ND = dyn_cast_or_null<NamedDecl>(D))
anatofuz
parents:
diff changeset
1210 llvm::errs() << *ND << "\n";
anatofuz
parents:
diff changeset
1211 else if (isa<BlockDecl>(D))
anatofuz
parents:
diff changeset
1212 // FIXME: Make this nicer.
anatofuz
parents:
diff changeset
1213 llvm::errs() << "<block>\n";
anatofuz
parents:
diff changeset
1214 else if (D)
anatofuz
parents:
diff changeset
1215 llvm::errs() << "<unknown decl>\n";
anatofuz
parents:
diff changeset
1216 else
anatofuz
parents:
diff changeset
1217 llvm::errs() << "<NULL DECL>\n";
anatofuz
parents:
diff changeset
1218 break;
anatofuz
parents:
diff changeset
1219 }
anatofuz
parents:
diff changeset
1220 }