/// \brief Return a memory buffer for the given source file.
ErrorOr<const MemoryBuffer &> getSourceFile(StringRef SourceFile);
- /// \brief Return true if two filepaths refer to the same file.
- bool equivalentFiles(StringRef A, StringRef B);
-
/// \brief Collect a set of function's file ids which correspond to the
/// given source file. Return false if the set is empty.
bool gatherInterestingFileIDs(StringRef SourceFile,
LoadedSourceFiles;
std::vector<FunctionCoverageMapping> FunctionMappingRecords;
bool CompareFilenamesOnly;
+ StringMap<std::string> RemappedFilenames;
};
}
+static std::vector<StringRef>
+getUniqueFilenames(ArrayRef<FunctionCoverageMapping> FunctionMappingRecords) {
+ std::vector<StringRef> Filenames;
+ for (const auto &Function : FunctionMappingRecords)
+ for (const auto &Filename : Function.Filenames)
+ Filenames.push_back(Filename);
+ std::sort(Filenames.begin(), Filenames.end());
+ auto Last = std::unique(Filenames.begin(), Filenames.end());
+ Filenames.erase(Last, Filenames.end());
+ return Filenames;
+}
+
void CodeCoverageTool::error(const Twine &Message, StringRef Whence) {
errs() << "error: ";
if (!Whence.empty())
ErrorOr<const MemoryBuffer &>
CodeCoverageTool::getSourceFile(StringRef SourceFile) {
- SmallString<256> Path(SourceFile);
- sys::fs::make_absolute(Path);
- for (const auto &Files : LoadedSourceFiles) {
- if (equivalentFiles(Path.str(), Files.first)) {
- return *Files.second;
- }
+ // If we've remapped filenames, look up the real location for this file.
+ if (!RemappedFilenames.empty()) {
+ auto Loc = RemappedFilenames.find(SourceFile);
+ if (Loc != RemappedFilenames.end())
+ SourceFile = Loc->second;
}
+ for (const auto &Files : LoadedSourceFiles)
+ if (sys::fs::equivalent(SourceFile, Files.first))
+ return *Files.second;
auto Buffer = MemoryBuffer::getFile(SourceFile);
if (auto EC = Buffer.getError()) {
error(EC.message(), SourceFile);
return EC;
}
- LoadedSourceFiles.push_back(std::make_pair(
- std::string(Path.begin(), Path.end()), std::move(Buffer.get())));
+ LoadedSourceFiles.push_back(
+ std::make_pair(SourceFile, std::move(Buffer.get())));
return *LoadedSourceFiles.back().second;
}
-bool CodeCoverageTool::equivalentFiles(StringRef A, StringRef B) {
- if (CompareFilenamesOnly)
- return sys::path::filename(A).equals_lower(sys::path::filename(B));
- return sys::fs::equivalent(A, B);
-}
-
bool CodeCoverageTool::gatherInterestingFileIDs(
StringRef SourceFile, const FunctionCoverageMapping &Function,
SmallSet<unsigned, 8> &InterestingFileIDs) {
bool Interesting = false;
for (unsigned I = 0, E = Function.Filenames.size(); I < E; ++I) {
- if (equivalentFiles(SourceFile, Function.Filenames[I])) {
+ if (SourceFile == Function.Filenames[I]) {
InterestingFileIDs.insert(I);
Interesting = true;
}
llvm::SmallVector<bool, 8> FilenameEquivalence(Function.Filenames.size(),
false);
for (unsigned I = 0, E = Function.Filenames.size(); I < E; ++I) {
- if (equivalentFiles(SourceFile, Function.Filenames[I]))
+ if (SourceFile == Function.Filenames[I])
FilenameEquivalence[I] = true;
}
for (const auto &CR : Function.CountedRegions) {
FunctionMappingRecords.push_back(Function);
}
+
+ if (CompareFilenamesOnly) {
+ auto CoveredFiles = getUniqueFilenames(FunctionMappingRecords);
+ for (auto &SF : SourceFiles) {
+ StringRef SFBase = sys::path::filename(SF);
+ for (const auto &CF : CoveredFiles)
+ if (SFBase == sys::path::filename(CF)) {
+ RemappedFilenames[CF] = SF;
+ SF = CF;
+ break;
+ }
+ }
+ }
+
return false;
}
cl::opt<bool> FilenameEquivalence(
"filename-equivalence", cl::Optional,
- cl::desc("Compare the filenames instead of full filepaths"));
+ cl::desc("Treat source files as equivalent to paths in the coverage data "
+ "when the file names match, even if the full paths do not"));
cl::OptionCategory FilteringCategory("Function filtering options");
Filters.push_back(std::unique_ptr<CoverageFilter>(StatFilterer));
}
- SourceFiles = InputSourceFiles;
+ for (const auto &File : InputSourceFiles) {
+ SmallString<128> Path(File);
+ if (std::error_code EC = sys::fs::make_absolute(Path)) {
+ errs() << "error: " << File << ": " << EC.message();
+ return 1;
+ }
+ SourceFiles.push_back(Path.str());
+ }
return 0;
};
// Show files
bool ShowFilenames = SourceFiles.size() != 1;
- if (SourceFiles.empty()) {
+ if (SourceFiles.empty())
// Get the source files from the function coverage mapping
- std::set<StringRef> UniqueFilenames;
- for (const auto &Function : FunctionMappingRecords) {
- for (const auto &Filename : Function.Filenames)
- UniqueFilenames.insert(Filename);
- }
- for (const auto &Filename : UniqueFilenames)
+ for (StringRef Filename : getUniqueFilenames(FunctionMappingRecords))
SourceFiles.push_back(Filename);
- }
for (const auto &SourceFile : SourceFiles) {
auto SourceBuffer = getSourceFile(SourceFile);