PathDiagnostic.h 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915
  1. #pragma once
  2. #ifdef __GNUC__
  3. #pragma GCC diagnostic push
  4. #pragma GCC diagnostic ignored "-Wunused-parameter"
  5. #endif
  6. //===- PathDiagnostic.h - Path-Specific Diagnostic Handling -----*- C++ -*-===//
  7. //
  8. // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
  9. // See https://llvm.org/LICENSE.txt for license information.
  10. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  11. //
  12. //===----------------------------------------------------------------------===//
  13. //
  14. // This file defines the PathDiagnostic-related interfaces.
  15. //
  16. //===----------------------------------------------------------------------===//
  17. #ifndef LLVM_CLANG_ANALYSIS_PATHDIAGNOSTIC_H
  18. #define LLVM_CLANG_ANALYSIS_PATHDIAGNOSTIC_H
  19. #include "clang/AST/Stmt.h"
  20. #include "clang/Analysis/AnalysisDeclContext.h"
  21. #include "clang/Basic/LLVM.h"
  22. #include "clang/Basic/SourceLocation.h"
  23. #include "llvm/ADT/ArrayRef.h"
  24. #include "llvm/ADT/FoldingSet.h"
  25. #include "llvm/ADT/PointerUnion.h"
  26. #include "llvm/ADT/SmallVector.h"
  27. #include "llvm/ADT/StringRef.h"
  28. #include "llvm/Support/Allocator.h"
  29. #include <cassert>
  30. #include <deque>
  31. #include <iterator>
  32. #include <list>
  33. #include <map>
  34. #include <memory>
  35. #include <optional>
  36. #include <set>
  37. #include <string>
  38. #include <utility>
  39. #include <vector>
  40. namespace clang {
  41. class AnalysisDeclContext;
  42. class BinaryOperator;
  43. class CallEnter;
  44. class CallExitEnd;
  45. class ConditionalOperator;
  46. class Decl;
  47. class LocationContext;
  48. class MemberExpr;
  49. class ProgramPoint;
  50. class SourceManager;
  51. namespace ento {
  52. //===----------------------------------------------------------------------===//
  53. // High-level interface for handlers of path-sensitive diagnostics.
  54. //===----------------------------------------------------------------------===//
  55. class PathDiagnostic;
  56. /// These options tweak the behavior of path diangostic consumers.
  57. /// Most of these options are currently supported by very few consumers.
  58. struct PathDiagnosticConsumerOptions {
  59. /// Run-line of the tool that produced the diagnostic.
  60. /// It can be included with the diagnostic for debugging purposes.
  61. std::string ToolInvocation;
  62. /// Whether to include additional information about macro expansions
  63. /// with the diagnostics, because otherwise they can be hard to obtain
  64. /// without re-compiling the program under analysis.
  65. bool ShouldDisplayMacroExpansions = false;
  66. /// Whether to include LLVM statistics of the process in the diagnostic.
  67. /// Useful for profiling the tool on large real-world codebases.
  68. bool ShouldSerializeStats = false;
  69. /// If the consumer intends to produce multiple output files, should it
  70. /// use a pseudo-random file name or a human-readable file name.
  71. bool ShouldWriteVerboseReportFilename = false;
  72. /// Whether the consumer should treat consumed diagnostics as hard errors.
  73. /// Useful for breaking your build when issues are found.
  74. bool ShouldDisplayWarningsAsErrors = false;
  75. /// Whether the consumer should attempt to rewrite the source file
  76. /// with fix-it hints attached to the diagnostics it consumes.
  77. bool ShouldApplyFixIts = false;
  78. /// Whether the consumer should present the name of the entity that emitted
  79. /// the diagnostic (eg., a checker) so that the user knew how to disable it.
  80. bool ShouldDisplayDiagnosticName = false;
  81. };
  82. class PathDiagnosticConsumer {
  83. public:
  84. class PDFileEntry : public llvm::FoldingSetNode {
  85. public:
  86. PDFileEntry(llvm::FoldingSetNodeID &NodeID) : NodeID(NodeID) {}
  87. using ConsumerFiles = std::vector<std::pair<StringRef, StringRef>>;
  88. /// A vector of <consumer,file> pairs.
  89. ConsumerFiles files;
  90. /// A precomputed hash tag used for uniquing PDFileEntry objects.
  91. const llvm::FoldingSetNodeID NodeID;
  92. /// Used for profiling in the FoldingSet.
  93. void Profile(llvm::FoldingSetNodeID &ID) { ID = NodeID; }
  94. };
  95. class FilesMade {
  96. llvm::BumpPtrAllocator Alloc;
  97. llvm::FoldingSet<PDFileEntry> Set;
  98. public:
  99. ~FilesMade();
  100. bool empty() const { return Set.empty(); }
  101. void addDiagnostic(const PathDiagnostic &PD,
  102. StringRef ConsumerName,
  103. StringRef fileName);
  104. PDFileEntry::ConsumerFiles *getFiles(const PathDiagnostic &PD);
  105. };
  106. private:
  107. virtual void anchor();
  108. public:
  109. PathDiagnosticConsumer() = default;
  110. virtual ~PathDiagnosticConsumer();
  111. void FlushDiagnostics(FilesMade *FilesMade);
  112. virtual void FlushDiagnosticsImpl(std::vector<const PathDiagnostic *> &Diags,
  113. FilesMade *filesMade) = 0;
  114. virtual StringRef getName() const = 0;
  115. void HandlePathDiagnostic(std::unique_ptr<PathDiagnostic> D);
  116. enum PathGenerationScheme {
  117. /// Only runs visitors, no output generated.
  118. None,
  119. /// Used for SARIF and text output.
  120. Minimal,
  121. /// Used for plist output, used for "arrows" generation.
  122. Extensive,
  123. /// Used for HTML, shows both "arrows" and control notes.
  124. Everything
  125. };
  126. virtual PathGenerationScheme getGenerationScheme() const { return Minimal; }
  127. bool shouldGenerateDiagnostics() const {
  128. return getGenerationScheme() != None;
  129. }
  130. bool shouldAddPathEdges() const { return getGenerationScheme() >= Extensive; }
  131. bool shouldAddControlNotes() const {
  132. return getGenerationScheme() == Minimal ||
  133. getGenerationScheme() == Everything;
  134. }
  135. virtual bool supportsLogicalOpControlFlow() const { return false; }
  136. /// Return true if the PathDiagnosticConsumer supports individual
  137. /// PathDiagnostics that span multiple files.
  138. virtual bool supportsCrossFileDiagnostics() const { return false; }
  139. protected:
  140. bool flushed = false;
  141. llvm::FoldingSet<PathDiagnostic> Diags;
  142. };
  143. //===----------------------------------------------------------------------===//
  144. // Path-sensitive diagnostics.
  145. //===----------------------------------------------------------------------===//
  146. class PathDiagnosticRange : public SourceRange {
  147. public:
  148. bool isPoint = false;
  149. PathDiagnosticRange(SourceRange R, bool isP = false)
  150. : SourceRange(R), isPoint(isP) {}
  151. PathDiagnosticRange() = default;
  152. };
  153. using LocationOrAnalysisDeclContext =
  154. llvm::PointerUnion<const LocationContext *, AnalysisDeclContext *>;
  155. class PathDiagnosticLocation {
  156. private:
  157. enum Kind { RangeK, SingleLocK, StmtK, DeclK } K = SingleLocK;
  158. const Stmt *S = nullptr;
  159. const Decl *D = nullptr;
  160. const SourceManager *SM = nullptr;
  161. FullSourceLoc Loc;
  162. PathDiagnosticRange Range;
  163. PathDiagnosticLocation(SourceLocation L, const SourceManager &sm, Kind kind)
  164. : K(kind), SM(&sm), Loc(genLocation(L)), Range(genRange()) {}
  165. FullSourceLoc genLocation(
  166. SourceLocation L = SourceLocation(),
  167. LocationOrAnalysisDeclContext LAC = (AnalysisDeclContext *)nullptr) const;
  168. PathDiagnosticRange genRange(
  169. LocationOrAnalysisDeclContext LAC = (AnalysisDeclContext *)nullptr) const;
  170. public:
  171. /// Create an invalid location.
  172. PathDiagnosticLocation() = default;
  173. /// Create a location corresponding to the given statement.
  174. PathDiagnosticLocation(const Stmt *s, const SourceManager &sm,
  175. LocationOrAnalysisDeclContext lac)
  176. : K(s->getBeginLoc().isValid() ? StmtK : SingleLocK),
  177. S(K == StmtK ? s : nullptr), SM(&sm),
  178. Loc(genLocation(SourceLocation(), lac)), Range(genRange(lac)) {
  179. assert(K == SingleLocK || S);
  180. assert(K == SingleLocK || Loc.isValid());
  181. assert(K == SingleLocK || Range.isValid());
  182. }
  183. /// Create a location corresponding to the given declaration.
  184. PathDiagnosticLocation(const Decl *d, const SourceManager &sm)
  185. : K(DeclK), D(d), SM(&sm), Loc(genLocation()), Range(genRange()) {
  186. assert(D);
  187. assert(Loc.isValid());
  188. assert(Range.isValid());
  189. }
  190. /// Create a location at an explicit offset in the source.
  191. ///
  192. /// This should only be used if there are no more appropriate constructors.
  193. PathDiagnosticLocation(SourceLocation loc, const SourceManager &sm)
  194. : SM(&sm), Loc(loc, sm), Range(genRange()) {
  195. assert(Loc.isValid());
  196. assert(Range.isValid());
  197. }
  198. /// Create a location corresponding to the given declaration.
  199. static PathDiagnosticLocation create(const Decl *D,
  200. const SourceManager &SM) {
  201. return PathDiagnosticLocation(D, SM);
  202. }
  203. /// Create a location for the beginning of the declaration.
  204. static PathDiagnosticLocation createBegin(const Decl *D,
  205. const SourceManager &SM);
  206. /// Create a location for the beginning of the declaration.
  207. /// The third argument is ignored, useful for generic treatment
  208. /// of statements and declarations.
  209. static PathDiagnosticLocation
  210. createBegin(const Decl *D, const SourceManager &SM,
  211. const LocationOrAnalysisDeclContext LAC) {
  212. return createBegin(D, SM);
  213. }
  214. /// Create a location for the beginning of the statement.
  215. static PathDiagnosticLocation createBegin(const Stmt *S,
  216. const SourceManager &SM,
  217. const LocationOrAnalysisDeclContext LAC);
  218. /// Create a location for the end of the statement.
  219. ///
  220. /// If the statement is a CompoundStatement, the location will point to the
  221. /// closing brace instead of following it.
  222. static PathDiagnosticLocation createEnd(const Stmt *S,
  223. const SourceManager &SM,
  224. const LocationOrAnalysisDeclContext LAC);
  225. /// Create the location for the operator of the binary expression.
  226. /// Assumes the statement has a valid location.
  227. static PathDiagnosticLocation createOperatorLoc(const BinaryOperator *BO,
  228. const SourceManager &SM);
  229. static PathDiagnosticLocation createConditionalColonLoc(
  230. const ConditionalOperator *CO,
  231. const SourceManager &SM);
  232. /// For member expressions, return the location of the '.' or '->'.
  233. /// Assumes the statement has a valid location.
  234. static PathDiagnosticLocation createMemberLoc(const MemberExpr *ME,
  235. const SourceManager &SM);
  236. /// Create a location for the beginning of the compound statement.
  237. /// Assumes the statement has a valid location.
  238. static PathDiagnosticLocation createBeginBrace(const CompoundStmt *CS,
  239. const SourceManager &SM);
  240. /// Create a location for the end of the compound statement.
  241. /// Assumes the statement has a valid location.
  242. static PathDiagnosticLocation createEndBrace(const CompoundStmt *CS,
  243. const SourceManager &SM);
  244. /// Create a location for the beginning of the enclosing declaration body.
  245. /// Defaults to the beginning of the first statement in the declaration body.
  246. static PathDiagnosticLocation createDeclBegin(const LocationContext *LC,
  247. const SourceManager &SM);
  248. /// Constructs a location for the end of the enclosing declaration body.
  249. /// Defaults to the end of brace.
  250. static PathDiagnosticLocation createDeclEnd(const LocationContext *LC,
  251. const SourceManager &SM);
  252. /// Create a location corresponding to the given valid ProgramPoint.
  253. static PathDiagnosticLocation create(const ProgramPoint &P,
  254. const SourceManager &SMng);
  255. /// Convert the given location into a single kind location.
  256. static PathDiagnosticLocation createSingleLocation(
  257. const PathDiagnosticLocation &PDL);
  258. /// Construct a source location that corresponds to either the beginning
  259. /// or the end of the given statement, or a nearby valid source location
  260. /// if the statement does not have a valid source location of its own.
  261. static SourceLocation
  262. getValidSourceLocation(const Stmt *S, LocationOrAnalysisDeclContext LAC,
  263. bool UseEndOfStatement = false);
  264. bool operator==(const PathDiagnosticLocation &X) const {
  265. return K == X.K && Loc == X.Loc && Range == X.Range;
  266. }
  267. bool operator!=(const PathDiagnosticLocation &X) const {
  268. return !(*this == X);
  269. }
  270. bool isValid() const {
  271. return SM != nullptr;
  272. }
  273. FullSourceLoc asLocation() const {
  274. return Loc;
  275. }
  276. PathDiagnosticRange asRange() const {
  277. return Range;
  278. }
  279. const Stmt *asStmt() const { assert(isValid()); return S; }
  280. const Stmt *getStmtOrNull() const {
  281. if (!isValid())
  282. return nullptr;
  283. return asStmt();
  284. }
  285. const Decl *asDecl() const { assert(isValid()); return D; }
  286. bool hasRange() const { return K == StmtK || K == RangeK || K == DeclK; }
  287. bool hasValidLocation() const { return asLocation().isValid(); }
  288. void invalidate() {
  289. *this = PathDiagnosticLocation();
  290. }
  291. void flatten();
  292. const SourceManager& getManager() const { assert(isValid()); return *SM; }
  293. void Profile(llvm::FoldingSetNodeID &ID) const;
  294. void dump() const;
  295. };
  296. class PathDiagnosticLocationPair {
  297. private:
  298. PathDiagnosticLocation Start, End;
  299. public:
  300. PathDiagnosticLocationPair(const PathDiagnosticLocation &start,
  301. const PathDiagnosticLocation &end)
  302. : Start(start), End(end) {}
  303. const PathDiagnosticLocation &getStart() const { return Start; }
  304. const PathDiagnosticLocation &getEnd() const { return End; }
  305. void setStart(const PathDiagnosticLocation &L) { Start = L; }
  306. void setEnd(const PathDiagnosticLocation &L) { End = L; }
  307. void flatten() {
  308. Start.flatten();
  309. End.flatten();
  310. }
  311. void Profile(llvm::FoldingSetNodeID &ID) const {
  312. Start.Profile(ID);
  313. End.Profile(ID);
  314. }
  315. };
  316. //===----------------------------------------------------------------------===//
  317. // Path "pieces" for path-sensitive diagnostics.
  318. //===----------------------------------------------------------------------===//
  319. class PathDiagnosticPiece: public llvm::FoldingSetNode {
  320. public:
  321. enum Kind { ControlFlow, Event, Macro, Call, Note, PopUp };
  322. enum DisplayHint { Above, Below };
  323. private:
  324. const std::string str;
  325. const Kind kind;
  326. const DisplayHint Hint;
  327. /// In the containing bug report, this piece is the last piece from
  328. /// the main source file.
  329. bool LastInMainSourceFile = false;
  330. /// A constant string that can be used to tag the PathDiagnosticPiece,
  331. /// typically with the identification of the creator. The actual pointer
  332. /// value is meant to be an identifier; the string itself is useful for
  333. /// debugging.
  334. StringRef Tag;
  335. std::vector<SourceRange> ranges;
  336. std::vector<FixItHint> fixits;
  337. protected:
  338. PathDiagnosticPiece(StringRef s, Kind k, DisplayHint hint = Below);
  339. PathDiagnosticPiece(Kind k, DisplayHint hint = Below);
  340. public:
  341. PathDiagnosticPiece() = delete;
  342. PathDiagnosticPiece(const PathDiagnosticPiece &) = delete;
  343. PathDiagnosticPiece &operator=(const PathDiagnosticPiece &) = delete;
  344. virtual ~PathDiagnosticPiece();
  345. StringRef getString() const { return str; }
  346. /// Tag this PathDiagnosticPiece with the given C-string.
  347. void setTag(const char *tag) { Tag = tag; }
  348. /// Return the opaque tag (if any) on the PathDiagnosticPiece.
  349. const void *getTag() const { return Tag.data(); }
  350. /// Return the string representation of the tag. This is useful
  351. /// for debugging.
  352. StringRef getTagStr() const { return Tag; }
  353. /// getDisplayHint - Return a hint indicating where the diagnostic should
  354. /// be displayed by the PathDiagnosticConsumer.
  355. DisplayHint getDisplayHint() const { return Hint; }
  356. virtual PathDiagnosticLocation getLocation() const = 0;
  357. virtual void flattenLocations() = 0;
  358. Kind getKind() const { return kind; }
  359. void addRange(SourceRange R) {
  360. if (!R.isValid())
  361. return;
  362. ranges.push_back(R);
  363. }
  364. void addRange(SourceLocation B, SourceLocation E) {
  365. if (!B.isValid() || !E.isValid())
  366. return;
  367. ranges.push_back(SourceRange(B,E));
  368. }
  369. void addFixit(FixItHint F) {
  370. fixits.push_back(F);
  371. }
  372. /// Return the SourceRanges associated with this PathDiagnosticPiece.
  373. ArrayRef<SourceRange> getRanges() const { return ranges; }
  374. /// Return the fix-it hints associated with this PathDiagnosticPiece.
  375. ArrayRef<FixItHint> getFixits() const { return fixits; }
  376. virtual void Profile(llvm::FoldingSetNodeID &ID) const;
  377. void setAsLastInMainSourceFile() {
  378. LastInMainSourceFile = true;
  379. }
  380. bool isLastInMainSourceFile() const {
  381. return LastInMainSourceFile;
  382. }
  383. virtual void dump() const = 0;
  384. };
  385. using PathDiagnosticPieceRef = std::shared_ptr<PathDiagnosticPiece>;
  386. class PathPieces : public std::list<PathDiagnosticPieceRef> {
  387. void flattenTo(PathPieces &Primary, PathPieces &Current,
  388. bool ShouldFlattenMacros) const;
  389. public:
  390. PathPieces flatten(bool ShouldFlattenMacros) const {
  391. PathPieces Result;
  392. flattenTo(Result, Result, ShouldFlattenMacros);
  393. return Result;
  394. }
  395. void dump() const;
  396. };
  397. class PathDiagnosticSpotPiece : public PathDiagnosticPiece {
  398. private:
  399. PathDiagnosticLocation Pos;
  400. public:
  401. PathDiagnosticSpotPiece(const PathDiagnosticLocation &pos,
  402. StringRef s,
  403. PathDiagnosticPiece::Kind k,
  404. bool addPosRange = true)
  405. : PathDiagnosticPiece(s, k), Pos(pos) {
  406. assert(Pos.isValid() && Pos.hasValidLocation() &&
  407. "PathDiagnosticSpotPiece's must have a valid location.");
  408. if (addPosRange && Pos.hasRange()) addRange(Pos.asRange());
  409. }
  410. PathDiagnosticLocation getLocation() const override { return Pos; }
  411. void flattenLocations() override { Pos.flatten(); }
  412. void Profile(llvm::FoldingSetNodeID &ID) const override;
  413. static bool classof(const PathDiagnosticPiece *P) {
  414. return P->getKind() == Event || P->getKind() == Macro ||
  415. P->getKind() == Note || P->getKind() == PopUp;
  416. }
  417. };
  418. class PathDiagnosticEventPiece : public PathDiagnosticSpotPiece {
  419. std::optional<bool> IsPrunable;
  420. public:
  421. PathDiagnosticEventPiece(const PathDiagnosticLocation &pos,
  422. StringRef s, bool addPosRange = true)
  423. : PathDiagnosticSpotPiece(pos, s, Event, addPosRange) {}
  424. ~PathDiagnosticEventPiece() override;
  425. /// Mark the diagnostic piece as being potentially prunable. This
  426. /// flag may have been previously set, at which point it will not
  427. /// be reset unless one specifies to do so.
  428. void setPrunable(bool isPrunable, bool override = false) {
  429. if (IsPrunable && !override)
  430. return;
  431. IsPrunable = isPrunable;
  432. }
  433. /// Return true if the diagnostic piece is prunable.
  434. bool isPrunable() const { return IsPrunable.value_or(false); }
  435. void dump() const override;
  436. static bool classof(const PathDiagnosticPiece *P) {
  437. return P->getKind() == Event;
  438. }
  439. };
  440. class PathDiagnosticCallPiece : public PathDiagnosticPiece {
  441. const Decl *Caller;
  442. const Decl *Callee = nullptr;
  443. // Flag signifying that this diagnostic has only call enter and no matching
  444. // call exit.
  445. bool NoExit;
  446. // Flag signifying that the callee function is an Objective-C autosynthesized
  447. // property getter or setter.
  448. bool IsCalleeAnAutosynthesizedPropertyAccessor = false;
  449. // The custom string, which should appear after the call Return Diagnostic.
  450. // TODO: Should we allow multiple diagnostics?
  451. std::string CallStackMessage;
  452. PathDiagnosticCallPiece(const Decl *callerD,
  453. const PathDiagnosticLocation &callReturnPos)
  454. : PathDiagnosticPiece(Call), Caller(callerD), NoExit(false),
  455. callReturn(callReturnPos) {}
  456. PathDiagnosticCallPiece(PathPieces &oldPath, const Decl *caller)
  457. : PathDiagnosticPiece(Call), Caller(caller), NoExit(true),
  458. path(oldPath) {}
  459. public:
  460. PathDiagnosticLocation callEnter;
  461. PathDiagnosticLocation callEnterWithin;
  462. PathDiagnosticLocation callReturn;
  463. PathPieces path;
  464. ~PathDiagnosticCallPiece() override;
  465. const Decl *getCaller() const { return Caller; }
  466. const Decl *getCallee() const { return Callee; }
  467. void setCallee(const CallEnter &CE, const SourceManager &SM);
  468. bool hasCallStackMessage() { return !CallStackMessage.empty(); }
  469. void setCallStackMessage(StringRef st) { CallStackMessage = std::string(st); }
  470. PathDiagnosticLocation getLocation() const override { return callEnter; }
  471. std::shared_ptr<PathDiagnosticEventPiece> getCallEnterEvent() const;
  472. std::shared_ptr<PathDiagnosticEventPiece>
  473. getCallEnterWithinCallerEvent() const;
  474. std::shared_ptr<PathDiagnosticEventPiece> getCallExitEvent() const;
  475. void flattenLocations() override {
  476. callEnter.flatten();
  477. callReturn.flatten();
  478. for (const auto &I : path)
  479. I->flattenLocations();
  480. }
  481. static std::shared_ptr<PathDiagnosticCallPiece>
  482. construct(const CallExitEnd &CE,
  483. const SourceManager &SM);
  484. static PathDiagnosticCallPiece *construct(PathPieces &pieces,
  485. const Decl *caller);
  486. void dump() const override;
  487. void Profile(llvm::FoldingSetNodeID &ID) const override;
  488. static bool classof(const PathDiagnosticPiece *P) {
  489. return P->getKind() == Call;
  490. }
  491. };
  492. class PathDiagnosticControlFlowPiece : public PathDiagnosticPiece {
  493. std::vector<PathDiagnosticLocationPair> LPairs;
  494. public:
  495. PathDiagnosticControlFlowPiece(const PathDiagnosticLocation &startPos,
  496. const PathDiagnosticLocation &endPos,
  497. StringRef s)
  498. : PathDiagnosticPiece(s, ControlFlow) {
  499. LPairs.push_back(PathDiagnosticLocationPair(startPos, endPos));
  500. }
  501. PathDiagnosticControlFlowPiece(const PathDiagnosticLocation &startPos,
  502. const PathDiagnosticLocation &endPos)
  503. : PathDiagnosticPiece(ControlFlow) {
  504. LPairs.push_back(PathDiagnosticLocationPair(startPos, endPos));
  505. }
  506. ~PathDiagnosticControlFlowPiece() override;
  507. PathDiagnosticLocation getStartLocation() const {
  508. assert(!LPairs.empty() &&
  509. "PathDiagnosticControlFlowPiece needs at least one location.");
  510. return LPairs[0].getStart();
  511. }
  512. PathDiagnosticLocation getEndLocation() const {
  513. assert(!LPairs.empty() &&
  514. "PathDiagnosticControlFlowPiece needs at least one location.");
  515. return LPairs[0].getEnd();
  516. }
  517. void setStartLocation(const PathDiagnosticLocation &L) {
  518. LPairs[0].setStart(L);
  519. }
  520. void setEndLocation(const PathDiagnosticLocation &L) {
  521. LPairs[0].setEnd(L);
  522. }
  523. void push_back(const PathDiagnosticLocationPair &X) { LPairs.push_back(X); }
  524. PathDiagnosticLocation getLocation() const override {
  525. return getStartLocation();
  526. }
  527. using iterator = std::vector<PathDiagnosticLocationPair>::iterator;
  528. iterator begin() { return LPairs.begin(); }
  529. iterator end() { return LPairs.end(); }
  530. void flattenLocations() override {
  531. for (auto &I : *this)
  532. I.flatten();
  533. }
  534. using const_iterator =
  535. std::vector<PathDiagnosticLocationPair>::const_iterator;
  536. const_iterator begin() const { return LPairs.begin(); }
  537. const_iterator end() const { return LPairs.end(); }
  538. static bool classof(const PathDiagnosticPiece *P) {
  539. return P->getKind() == ControlFlow;
  540. }
  541. void dump() const override;
  542. void Profile(llvm::FoldingSetNodeID &ID) const override;
  543. };
  544. class PathDiagnosticMacroPiece : public PathDiagnosticSpotPiece {
  545. public:
  546. PathDiagnosticMacroPiece(const PathDiagnosticLocation &pos)
  547. : PathDiagnosticSpotPiece(pos, "", Macro) {}
  548. ~PathDiagnosticMacroPiece() override;
  549. PathPieces subPieces;
  550. void flattenLocations() override {
  551. PathDiagnosticSpotPiece::flattenLocations();
  552. for (const auto &I : subPieces)
  553. I->flattenLocations();
  554. }
  555. static bool classof(const PathDiagnosticPiece *P) {
  556. return P->getKind() == Macro;
  557. }
  558. void dump() const override;
  559. void Profile(llvm::FoldingSetNodeID &ID) const override;
  560. };
  561. class PathDiagnosticNotePiece: public PathDiagnosticSpotPiece {
  562. public:
  563. PathDiagnosticNotePiece(const PathDiagnosticLocation &Pos, StringRef S,
  564. bool AddPosRange = true)
  565. : PathDiagnosticSpotPiece(Pos, S, Note, AddPosRange) {}
  566. ~PathDiagnosticNotePiece() override;
  567. static bool classof(const PathDiagnosticPiece *P) {
  568. return P->getKind() == Note;
  569. }
  570. void dump() const override;
  571. void Profile(llvm::FoldingSetNodeID &ID) const override;
  572. };
  573. class PathDiagnosticPopUpPiece: public PathDiagnosticSpotPiece {
  574. public:
  575. PathDiagnosticPopUpPiece(const PathDiagnosticLocation &Pos, StringRef S,
  576. bool AddPosRange = true)
  577. : PathDiagnosticSpotPiece(Pos, S, PopUp, AddPosRange) {}
  578. ~PathDiagnosticPopUpPiece() override;
  579. static bool classof(const PathDiagnosticPiece *P) {
  580. return P->getKind() == PopUp;
  581. }
  582. void dump() const override;
  583. void Profile(llvm::FoldingSetNodeID &ID) const override;
  584. };
  585. /// File IDs mapped to sets of line numbers.
  586. using FilesToLineNumsMap = std::map<FileID, std::set<unsigned>>;
  587. /// PathDiagnostic - PathDiagnostic objects represent a single path-sensitive
  588. /// diagnostic. It represents an ordered-collection of PathDiagnosticPieces,
  589. /// each which represent the pieces of the path.
  590. class PathDiagnostic : public llvm::FoldingSetNode {
  591. std::string CheckerName;
  592. const Decl *DeclWithIssue;
  593. std::string BugType;
  594. std::string VerboseDesc;
  595. std::string ShortDesc;
  596. std::string Category;
  597. std::deque<std::string> OtherDesc;
  598. /// Loc The location of the path diagnostic report.
  599. PathDiagnosticLocation Loc;
  600. PathPieces pathImpl;
  601. SmallVector<PathPieces *, 3> pathStack;
  602. /// Important bug uniqueing location.
  603. /// The location info is useful to differentiate between bugs.
  604. PathDiagnosticLocation UniqueingLoc;
  605. const Decl *UniqueingDecl;
  606. /// Lines executed in the path.
  607. std::unique_ptr<FilesToLineNumsMap> ExecutedLines;
  608. public:
  609. PathDiagnostic() = delete;
  610. PathDiagnostic(StringRef CheckerName, const Decl *DeclWithIssue,
  611. StringRef bugtype, StringRef verboseDesc, StringRef shortDesc,
  612. StringRef category, PathDiagnosticLocation LocationToUnique,
  613. const Decl *DeclToUnique,
  614. std::unique_ptr<FilesToLineNumsMap> ExecutedLines);
  615. ~PathDiagnostic();
  616. const PathPieces &path;
  617. /// Return the path currently used by builders for constructing the
  618. /// PathDiagnostic.
  619. PathPieces &getActivePath() {
  620. if (pathStack.empty())
  621. return pathImpl;
  622. return *pathStack.back();
  623. }
  624. /// Return a mutable version of 'path'.
  625. PathPieces &getMutablePieces() {
  626. return pathImpl;
  627. }
  628. /// Return the unrolled size of the path.
  629. unsigned full_size();
  630. void pushActivePath(PathPieces *p) { pathStack.push_back(p); }
  631. void popActivePath() { if (!pathStack.empty()) pathStack.pop_back(); }
  632. bool isWithinCall() const { return !pathStack.empty(); }
  633. void setEndOfPath(PathDiagnosticPieceRef EndPiece) {
  634. assert(!Loc.isValid() && "End location already set!");
  635. Loc = EndPiece->getLocation();
  636. assert(Loc.isValid() && "Invalid location for end-of-path piece");
  637. getActivePath().push_back(std::move(EndPiece));
  638. }
  639. void appendToDesc(StringRef S) {
  640. if (!ShortDesc.empty())
  641. ShortDesc += S;
  642. VerboseDesc += S;
  643. }
  644. StringRef getVerboseDescription() const { return VerboseDesc; }
  645. StringRef getShortDescription() const {
  646. return ShortDesc.empty() ? VerboseDesc : ShortDesc;
  647. }
  648. StringRef getCheckerName() const { return CheckerName; }
  649. StringRef getBugType() const { return BugType; }
  650. StringRef getCategory() const { return Category; }
  651. using meta_iterator = std::deque<std::string>::const_iterator;
  652. meta_iterator meta_begin() const { return OtherDesc.begin(); }
  653. meta_iterator meta_end() const { return OtherDesc.end(); }
  654. void addMeta(StringRef s) { OtherDesc.push_back(std::string(s)); }
  655. const FilesToLineNumsMap &getExecutedLines() const {
  656. return *ExecutedLines;
  657. }
  658. FilesToLineNumsMap &getExecutedLines() {
  659. return *ExecutedLines;
  660. }
  661. /// Return the semantic context where an issue occurred. If the
  662. /// issue occurs along a path, this represents the "central" area
  663. /// where the bug manifests.
  664. const Decl *getDeclWithIssue() const { return DeclWithIssue; }
  665. void setDeclWithIssue(const Decl *D) {
  666. DeclWithIssue = D;
  667. }
  668. PathDiagnosticLocation getLocation() const {
  669. return Loc;
  670. }
  671. void setLocation(PathDiagnosticLocation NewLoc) {
  672. Loc = NewLoc;
  673. }
  674. /// Get the location on which the report should be uniqued.
  675. PathDiagnosticLocation getUniqueingLoc() const {
  676. return UniqueingLoc;
  677. }
  678. /// Get the declaration containing the uniqueing location.
  679. const Decl *getUniqueingDecl() const {
  680. return UniqueingDecl;
  681. }
  682. void flattenLocations() {
  683. Loc.flatten();
  684. for (const auto &I : pathImpl)
  685. I->flattenLocations();
  686. }
  687. /// Profiles the diagnostic, independent of the path it references.
  688. ///
  689. /// This can be used to merge diagnostics that refer to the same issue
  690. /// along different paths.
  691. void Profile(llvm::FoldingSetNodeID &ID) const;
  692. /// Profiles the diagnostic, including its path.
  693. ///
  694. /// Two diagnostics with the same issue along different paths will generate
  695. /// different profiles.
  696. void FullProfile(llvm::FoldingSetNodeID &ID) const;
  697. };
  698. } // namespace ento
  699. } // namespace clang
  700. #endif // LLVM_CLANG_ANALYSIS_PATHDIAGNOSTIC_H
  701. #ifdef __GNUC__
  702. #pragma GCC diagnostic pop
  703. #endif