Coverage Report

Created: 2021-08-24 07:12

/Users/buildslave/jenkins/workspace/coverage/llvm-project/clang/lib/Frontend/HeaderIncludeGen.cpp
Line
Count
Source (jump to first uncovered line)
1
//===-- HeaderIncludeGen.cpp - Generate Header Includes -------------------===//
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
#include "clang/Frontend/DependencyOutputOptions.h"
10
#include "clang/Frontend/Utils.h"
11
#include "clang/Basic/SourceManager.h"
12
#include "clang/Frontend/FrontendDiagnostic.h"
13
#include "clang/Lex/Preprocessor.h"
14
#include "llvm/ADT/SmallString.h"
15
#include "llvm/Support/raw_ostream.h"
16
using namespace clang;
17
18
namespace {
19
class HeaderIncludesCallback : public PPCallbacks {
20
  SourceManager &SM;
21
  raw_ostream *OutputFile;
22
  const DependencyOutputOptions &DepOpts;
23
  unsigned CurrentIncludeDepth;
24
  bool HasProcessedPredefines;
25
  bool OwnsOutputFile;
26
  bool ShowAllHeaders;
27
  bool ShowDepth;
28
  bool MSStyle;
29
30
public:
31
  HeaderIncludesCallback(const Preprocessor *PP, bool ShowAllHeaders_,
32
                         raw_ostream *OutputFile_,
33
                         const DependencyOutputOptions &DepOpts,
34
                         bool OwnsOutputFile_, bool ShowDepth_, bool MSStyle_)
35
      : SM(PP->getSourceManager()), OutputFile(OutputFile_), DepOpts(DepOpts),
36
        CurrentIncludeDepth(0), HasProcessedPredefines(false),
37
        OwnsOutputFile(OwnsOutputFile_), ShowAllHeaders(ShowAllHeaders_),
38
20
        ShowDepth(ShowDepth_), MSStyle(MSStyle_) {}
39
40
6
  ~HeaderIncludesCallback() override {
41
6
    if (OwnsOutputFile)
42
0
      delete OutputFile;
43
6
  }
44
45
  void FileChanged(SourceLocation Loc, FileChangeReason Reason,
46
                   SrcMgr::CharacteristicKind FileType,
47
                   FileID PrevFID) override;
48
49
  void FileSkipped(const FileEntryRef &SkippedFile, const Token &FilenameTok,
50
                   SrcMgr::CharacteristicKind FileType) override;
51
};
52
}
53
54
static void PrintHeaderInfo(raw_ostream *OutputFile, StringRef Filename,
55
                            bool ShowDepth, unsigned CurrentIncludeDepth,
56
37
                            bool MSStyle) {
57
  // Write to a temporary string to avoid unnecessary flushing on errs().
58
37
  SmallString<512> Pathname(Filename);
59
37
  if (!MSStyle)
60
14
    Lexer::Stringify(Pathname);
61
62
37
  SmallString<256> Msg;
63
37
  if (MSStyle)
64
23
    Msg += "Note: including file:";
65
66
37
  if (ShowDepth) {
67
    // The main source file is at depth 1, so skip one dot.
68
78
    for (unsigned i = 1; i != CurrentIncludeDepth; 
++i44
)
69
44
      Msg += MSStyle ? 
' '29
:
'.'15
;
70
71
34
    if (!MSStyle)
72
11
      Msg += ' ';
73
34
  }
74
37
  Msg += Pathname;
75
37
  Msg += '\n';
76
77
37
  *OutputFile << Msg;
78
37
  OutputFile->flush();
79
37
}
80
81
void clang::AttachHeaderIncludeGen(Preprocessor &PP,
82
                                   const DependencyOutputOptions &DepOpts,
83
                                   bool ShowAllHeaders, StringRef OutputPath,
84
20
                                   bool ShowDepth, bool MSStyle) {
85
20
  raw_ostream *OutputFile = &llvm::errs();
86
20
  bool OwnsOutputFile = false;
87
88
  // Choose output stream, when printing in cl.exe /showIncludes style.
89
20
  if (MSStyle) {
90
10
    switch (DepOpts.ShowIncludesDest) {
91
0
    default:
92
0
      llvm_unreachable("Invalid destination for /showIncludes output!");
93
1
    case ShowIncludesDestination::Stderr:
94
1
      OutputFile = &llvm::errs();
95
1
      break;
96
9
    case ShowIncludesDestination::Stdout:
97
9
      OutputFile = &llvm::outs();
98
9
      break;
99
10
    }
100
10
  }
101
102
  // Open the output file, if used.
103
20
  if (!OutputPath.empty()) {
104
0
    std::error_code EC;
105
0
    llvm::raw_fd_ostream *OS = new llvm::raw_fd_ostream(
106
0
        OutputPath.str(), EC,
107
0
        llvm::sys::fs::OF_Append | llvm::sys::fs::OF_TextWithCRLF);
108
0
    if (EC) {
109
0
      PP.getDiagnostics().Report(clang::diag::warn_fe_cc_print_header_failure)
110
0
          << EC.message();
111
0
      delete OS;
112
0
    } else {
113
0
      OS->SetUnbuffered();
114
0
      OutputFile = OS;
115
0
      OwnsOutputFile = true;
116
0
    }
117
0
  }
118
119
  // Print header info for extra headers, pretending they were discovered by
120
  // the regular preprocessor. The primary use case is to support proper
121
  // generation of Make / Ninja file dependencies for implicit includes, such
122
  // as sanitizer blacklists. It's only important for cl.exe compatibility,
123
  // the GNU way to generate rules is -M / -MM / -MD / -MMD.
124
20
  for (const auto &Header : DepOpts.ExtraDeps)
125
1
    PrintHeaderInfo(OutputFile, Header.first, ShowDepth, 2, MSStyle);
126
20
  PP.addPPCallbacks(std::make_unique<HeaderIncludesCallback>(
127
20
      &PP, ShowAllHeaders, OutputFile, DepOpts, OwnsOutputFile, ShowDepth,
128
20
      MSStyle));
129
20
}
130
131
void HeaderIncludesCallback::FileChanged(SourceLocation Loc,
132
                                         FileChangeReason Reason,
133
                                         SrcMgr::CharacteristicKind NewFileType,
134
190
                                         FileID PrevFID) {
135
  // Unless we are exiting a #include, make sure to skip ahead to the line the
136
  // #include directive was at.
137
190
  PresumedLoc UserLoc = SM.getPresumedLoc(Loc);
138
190
  if (UserLoc.isInvalid())
139
0
    return;
140
141
  // Adjust the current include depth.
142
190
  if (Reason == PPCallbacks::EnterFile) {
143
98
    ++CurrentIncludeDepth;
144
98
  } else 
if (92
Reason == PPCallbacks::ExitFile92
) {
145
76
    if (CurrentIncludeDepth)
146
76
      --CurrentIncludeDepth;
147
148
    // We track when we are done with the predefines by watching for the first
149
    // place where we drop back to a nesting depth of 1.
150
76
    if (CurrentIncludeDepth == 1 && 
!HasProcessedPredefines41
) {
151
18
      if (!DepOpts.ShowIncludesPretendHeader.empty()) {
152
0
        PrintHeaderInfo(OutputFile, DepOpts.ShowIncludesPretendHeader,
153
0
                        ShowDepth, 2, MSStyle);
154
0
      }
155
18
      HasProcessedPredefines = true;
156
18
    }
157
158
76
    return;
159
76
  } else
160
16
    return;
161
162
  // Show the header if we are (a) past the predefines, or (b) showing all
163
  // headers and in the predefines at a depth past the initial file and command
164
  // line buffers.
165
98
  bool ShowHeader = (HasProcessedPredefines ||
166
98
                     
(69
ShowAllHeaders69
&&
CurrentIncludeDepth > 255
));
167
98
  unsigned IncludeDepth = CurrentIncludeDepth;
168
98
  if (!HasProcessedPredefines)
169
69
    --IncludeDepth; // Ignore indent from <built-in>.
170
29
  else if (!DepOpts.ShowIncludesPretendHeader.empty())
171
0
    ++IncludeDepth; // Pretend inclusion by ShowIncludesPretendHeader.
172
173
98
  if (!DepOpts.IncludeSystemHeaders && 
isSystem(NewFileType)33
)
174
5
    ShowHeader = false;
175
176
  // Dump the header include information we are past the predefines buffer or
177
  // are showing all headers and this isn't the magic implicit <command line>
178
  // header.
179
  // FIXME: Identify headers in a more robust way than comparing their name to
180
  // "<command line>" and "<built-in>" in a bunch of places.
181
98
  if (ShowHeader && 
Reason == PPCallbacks::EnterFile47
&&
182
98
      
UserLoc.getFilename() != StringRef("<command line>")47
) {
183
35
    PrintHeaderInfo(OutputFile, UserLoc.getFilename(), ShowDepth, IncludeDepth,
184
35
                    MSStyle);
185
35
  }
186
98
}
187
188
void HeaderIncludesCallback::FileSkipped(const FileEntryRef &SkippedFile, const
189
                                         Token &FilenameTok,
190
6
                                         SrcMgr::CharacteristicKind FileType) {
191
6
  if (!DepOpts.ShowSkippedHeaderIncludes)
192
5
    return;
193
194
1
  if (!DepOpts.IncludeSystemHeaders && isSystem(FileType))
195
0
    return;
196
197
1
  PrintHeaderInfo(OutputFile, SkippedFile.getName(), ShowDepth,
198
1
                  CurrentIncludeDepth + 1, MSStyle);
199
1
}