Coverage Report

Created: 2020-10-24 06:27

/Users/buildslave/jenkins/workspace/coverage/llvm-project/clang/lib/StaticAnalyzer/Core/TextDiagnostics.cpp
Line
Count
Source (jump to first uncovered line)
1
//===--- TextDiagnostics.cpp - Text Diagnostics for Paths -------*- C++ -*-===//
2
//
3
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4
// See https://llvm.org/LICENSE.txt for license information.
5
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6
//
7
//===----------------------------------------------------------------------===//
8
//
9
//  This file defines the TextDiagnostics object.
10
//
11
//===----------------------------------------------------------------------===//
12
13
#include "clang/Analysis/PathDiagnostic.h"
14
#include "clang/Basic/SourceManager.h"
15
#include "clang/Basic/Version.h"
16
#include "clang/CrossTU/CrossTranslationUnit.h"
17
#include "clang/Frontend/ASTUnit.h"
18
#include "clang/Lex/Preprocessor.h"
19
#include "clang/Rewrite/Core/Rewriter.h"
20
#include "clang/StaticAnalyzer/Core/AnalyzerOptions.h"
21
#include "clang/StaticAnalyzer/Core/PathDiagnosticConsumers.h"
22
#include "clang/Tooling/Core/Replacement.h"
23
#include "clang/Tooling/Tooling.h"
24
#include "llvm/ADT/SmallPtrSet.h"
25
#include "llvm/ADT/SmallVector.h"
26
#include "llvm/Support/Casting.h"
27
28
using namespace clang;
29
using namespace ento;
30
using namespace tooling;
31
32
namespace {
33
/// Emitsd minimal diagnostics (report message + notes) for the 'none' output
34
/// type to the standard error, or to to compliment many others. Emits detailed
35
/// diagnostics in textual format for the 'text' output type.
36
class TextDiagnostics : public PathDiagnosticConsumer {
37
  DiagnosticsEngine &DiagEng;
38
  const LangOptions &LO;
39
  const bool IncludePath = false;
40
  const bool ShouldEmitAsError = false;
41
  const bool ApplyFixIts = false;
42
  const bool ShouldDisplayCheckerName = false;
43
44
public:
45
  TextDiagnostics(DiagnosticsEngine &DiagEng, const LangOptions &LO,
46
                  bool ShouldIncludePath, const AnalyzerOptions &AnOpts)
47
      : DiagEng(DiagEng), LO(LO), IncludePath(ShouldIncludePath),
48
        ShouldEmitAsError(AnOpts.AnalyzerWerror),
49
        ApplyFixIts(AnOpts.ShouldApplyFixIts),
50
1.34k
        ShouldDisplayCheckerName(AnOpts.ShouldDisplayCheckerNameForText) {}
51
1.34k
  ~TextDiagnostics() override {}
52
53
0
  StringRef getName() const override { return "TextDiagnostics"; }
54
55
81
  bool supportsLogicalOpControlFlow() const override { return true; }
56
15.2k
  bool supportsCrossFileDiagnostics() const override { return true; }
57
58
139k
  PathGenerationScheme getGenerationScheme() const override {
59
126k
    return IncludePath ? Minimal : 
None12.8k
;
60
139k
  }
61
62
  void FlushDiagnosticsImpl(std::vector<const PathDiagnostic *> &Diags,
63
1.34k
                            FilesMade *filesMade) override {
64
1.34k
    unsigned WarnID =
65
1.34k
        ShouldEmitAsError
66
1
            ? DiagEng.getCustomDiagID(DiagnosticsEngine::Error, "%0")
67
1.34k
            : DiagEng.getCustomDiagID(DiagnosticsEngine::Warning, "%0");
68
1.34k
    unsigned NoteID = DiagEng.getCustomDiagID(DiagnosticsEngine::Note, "%0");
69
1.34k
    SourceManager &SM = DiagEng.getSourceManager();
70
71
1.34k
    Replacements Repls;
72
1.34k
    auto reportPiece = [&](unsigned ID, FullSourceLoc Loc, StringRef String,
73
1.34k
                           ArrayRef<SourceRange> Ranges,
74
19.4k
                           ArrayRef<FixItHint> Fixits) {
75
19.4k
      if (!ApplyFixIts) {
76
19.3k
        DiagEng.Report(Loc, ID) << String << Ranges << Fixits;
77
19.3k
        return;
78
19.3k
      }
79
80
61
      DiagEng.Report(Loc, ID) << String << Ranges;
81
11
      for (const FixItHint &Hint : Fixits) {
82
11
        Replacement Repl(SM, Hint.RemoveRange, Hint.CodeToInsert);
83
84
11
        if (llvm::Error Err = Repls.add(Repl)) {
85
0
          llvm::errs() << "Error applying replacement " << Repl.toString()
86
0
                       << ": " << Err << "\n";
87
0
        }
88
11
      }
89
61
    };
90
91
1.34k
    for (std::vector<const PathDiagnostic *>::iterator I = Diags.begin(),
92
1.34k
         E = Diags.end();
93
16.5k
         I != E; 
++I15.2k
) {
94
15.2k
      const PathDiagnostic *PD = *I;
95
15.2k
      std::string WarningMsg =
96
13.0k
          (ShouldDisplayCheckerName ? " [" + PD->getCheckerName() + "]" : 
""2.19k
)
97
15.2k
              .str();
98
99
15.2k
      reportPiece(WarnID, PD->getLocation().asLocation(),
100
15.2k
                  (PD->getShortDescription() + WarningMsg).str(),
101
15.2k
                  PD->path.back()->getRanges(), PD->path.back()->getFixits());
102
103
      // First, add extra notes, even if paths should not be included.
104
17.6k
      for (const auto &Piece : PD->path) {
105
17.6k
        if (!isa<PathDiagnosticNotePiece>(Piece.get()))
106
17.5k
          continue;
107
108
165
        reportPiece(NoteID, Piece->getLocation().asLocation(),
109
165
                    Piece->getString(), Piece->getRanges(),
110
165
                    Piece->getFixits());
111
165
      }
112
113
15.2k
      if (!IncludePath)
114
14.0k
        continue;
115
116
      // Then, add the path notes if necessary.
117
1.17k
      PathPieces FlatPath = PD->path.flatten(/*ShouldFlattenMacros=*/true);
118
4.02k
      for (const auto &Piece : FlatPath) {
119
4.02k
        if (isa<PathDiagnosticNotePiece>(Piece.get()))
120
1
          continue;
121
122
4.01k
        reportPiece(NoteID, Piece->getLocation().asLocation(),
123
4.01k
                    Piece->getString(), Piece->getRanges(),
124
4.01k
                    Piece->getFixits());
125
4.01k
      }
126
1.17k
    }
127
128
1.34k
    if (!ApplyFixIts || 
Repls.empty()3
)
129
1.33k
      return;
130
131
3
    Rewriter Rewrite(SM, LO);
132
3
    if (!applyAllReplacements(Repls, Rewrite)) {
133
0
      llvm::errs() << "An error occured during applying fix-it.\n";
134
0
    }
135
136
3
    Rewrite.overwriteChangedFiles();
137
3
  }
138
};
139
} // end anonymous namespace
140
141
void ento::createTextPathDiagnosticConsumer(
142
    AnalyzerOptions &AnalyzerOpts, PathDiagnosticConsumers &C,
143
    const std::string &Prefix, const clang::Preprocessor &PP,
144
126
    const cross_tu::CrossTranslationUnitContext &CTU) {
145
126
  C.emplace_back(new TextDiagnostics(PP.getDiagnostics(), PP.getLangOpts(),
146
126
                                     /*ShouldIncludePath*/ true, AnalyzerOpts));
147
126
}
148
149
void ento::createTextMinimalPathDiagnosticConsumer(
150
    AnalyzerOptions &AnalyzerOpts, PathDiagnosticConsumers &C,
151
    const std::string &Prefix, const clang::Preprocessor &PP,
152
1.21k
    const cross_tu::CrossTranslationUnitContext &CTU) {
153
1.21k
  C.emplace_back(new TextDiagnostics(PP.getDiagnostics(), PP.getLangOpts(),
154
1.21k
                                     /*ShouldIncludePath*/ false,
155
1.21k
                                     AnalyzerOpts));
156
1.21k
}