diff --git a/clang/include/clang/Basic/CodeGenOptions.def b/clang/include/clang/Basic/CodeGenOptions.def --- a/clang/include/clang/Basic/CodeGenOptions.def +++ b/clang/include/clang/Basic/CodeGenOptions.def @@ -211,6 +211,7 @@ ///< enable code coverage analysis. CODEGENOPT(DumpCoverageMapping , 1, 0) ///< Dump the generated coverage mapping ///< regions. +CODEGENOPT(OmitBlankLines , 1, 0) ///< Skip blank lines in coverage mapping. /// If -fpcc-struct-return or -freg-struct-return is specified. ENUM_CODEGENOPT(StructReturnConvention, StructReturnConventionKind, 2, SRCK_Default) diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td --- a/clang/include/clang/Driver/Options.td +++ b/clang/include/clang/Driver/Options.td @@ -5158,6 +5158,9 @@ def dump_coverage_mapping : Flag<["-"], "dump-coverage-mapping">, HelpText<"Dump the coverage mapping records, for testing">, MarshallingInfoFlag>; +def omit_blank_lines : Flag<["-"], "omit-blank-lines">, + HelpText<"Skip blank lines in coverage mapping">, + MarshallingInfoFlag>; def fuse_register_sized_bitfield_access: Flag<["-"], "fuse-register-sized-bitfield-access">, HelpText<"Use register sized accesses to bit-fields, when possible.">, MarshallingInfoFlag>; diff --git a/clang/include/clang/Lex/PPCallbacks.h b/clang/include/clang/Lex/PPCallbacks.h --- a/clang/include/clang/Lex/PPCallbacks.h +++ b/clang/include/clang/Lex/PPCallbacks.h @@ -317,6 +317,12 @@ virtual void SourceRangeSkipped(SourceRange Range, SourceLocation EndifLoc) { } + /// Hook called when blank lines are seen. + /// \param Range A Source Range spanning from column one of the first line to + /// column one of the last line of one or more contiguous blank lines. A + /// blank line is one that has no tokens (comments and whitespace may exist). + virtual void BlankLines(SourceRange Range) {} + enum ConditionValueKind { CVK_NotEvaluated, CVK_False, CVK_True }; @@ -594,6 +600,11 @@ Second->SourceRangeSkipped(Range, EndifLoc); } + void BlankLines(SourceRange Range) override { + First->BlankLines(Range); + Second->BlankLines(Range); + } + /// Hook called whenever an \#if is seen. void If(SourceLocation Loc, SourceRange ConditionRange, ConditionValueKind ConditionValue) override { diff --git a/clang/include/clang/Lex/Preprocessor.h b/clang/include/clang/Lex/Preprocessor.h --- a/clang/include/clang/Lex/Preprocessor.h +++ b/clang/include/clang/Lex/Preprocessor.h @@ -940,6 +940,11 @@ void updateOutOfDateIdentifier(IdentifierInfo &II) const; + typedef std::map HighestLineNumberMap; + + /// Highest line number where a token was found for each FileID + HighestLineNumberMap HighestLineNumbers; + public: Preprocessor(std::shared_ptr PPOpts, DiagnosticsEngine &diags, LangOptions &opts, SourceManager &SM, diff --git a/clang/lib/CodeGen/CodeGenPGO.cpp b/clang/lib/CodeGen/CodeGenPGO.cpp --- a/clang/lib/CodeGen/CodeGenPGO.cpp +++ b/clang/lib/CodeGen/CodeGenPGO.cpp @@ -889,9 +889,9 @@ std::string CoverageMapping; llvm::raw_string_ostream OS(CoverageMapping); - CoverageMappingGen MappingGen(*CGM.getCoverageMapping(), - CGM.getContext().getSourceManager(), - CGM.getLangOpts(), RegionCounterMap.get()); + CoverageMappingGen MappingGen( + *CGM.getCoverageMapping(), CGM.getContext().getSourceManager(), + CGM.getCodeGenOpts(), CGM.getLangOpts(), RegionCounterMap.get()); MappingGen.emitCounterMapping(D, OS); OS.flush(); @@ -912,7 +912,7 @@ llvm::raw_string_ostream OS(CoverageMapping); CoverageMappingGen MappingGen(*CGM.getCoverageMapping(), CGM.getContext().getSourceManager(), - CGM.getLangOpts()); + CGM.getCodeGenOpts(), CGM.getLangOpts()); MappingGen.emitEmptyMapping(D, OS); OS.flush(); diff --git a/clang/lib/CodeGen/CoverageMappingGen.h b/clang/lib/CodeGen/CoverageMappingGen.h --- a/clang/lib/CodeGen/CoverageMappingGen.h +++ b/clang/lib/CodeGen/CoverageMappingGen.h @@ -23,6 +23,7 @@ namespace clang { +class CodeGenOptions; class LangOptions; class SourceManager; class FileEntry; @@ -50,6 +51,7 @@ public EmptylineHandler { // A vector of skipped source ranges and PrevTokLoc with NextTokLoc. std::vector SkippedRanges; + std::vector BlankLineRanges; SourceManager &SourceMgr; @@ -61,8 +63,10 @@ CoverageSourceInfo(SourceManager &SourceMgr) : SourceMgr(SourceMgr) {} std::vector &getSkippedRanges() { return SkippedRanges; } + ArrayRef getBlankLines() const { return BlankLineRanges; } void AddSkippedRange(SourceRange Range); + void BlankLines(SourceRange Range) override; void SourceRangeSkipped(SourceRange Range, SourceLocation EndifLoc) override; @@ -135,18 +139,23 @@ class CoverageMappingGen { CoverageMappingModuleGen &CVM; SourceManager &SM; + const CodeGenOptions &CodeGenOpts; const LangOptions &LangOpts; llvm::DenseMap *CounterMap; public: CoverageMappingGen(CoverageMappingModuleGen &CVM, SourceManager &SM, + const CodeGenOptions &CodeGenOpts, const LangOptions &LangOpts) - : CVM(CVM), SM(SM), LangOpts(LangOpts), CounterMap(nullptr) {} + : CVM(CVM), SM(SM), CodeGenOpts(CodeGenOpts), LangOpts(LangOpts), + CounterMap(nullptr) {} CoverageMappingGen(CoverageMappingModuleGen &CVM, SourceManager &SM, + const CodeGenOptions &CodeGenOpts, const LangOptions &LangOpts, llvm::DenseMap *CounterMap) - : CVM(CVM), SM(SM), LangOpts(LangOpts), CounterMap(CounterMap) {} + : CVM(CVM), SM(SM), CodeGenOpts(CodeGenOpts), LangOpts(LangOpts), + CounterMap(CounterMap) {} /// Emit the coverage mapping data which maps the regions of /// code to counters that will be used to find the execution diff --git a/clang/lib/CodeGen/CoverageMappingGen.cpp b/clang/lib/CodeGen/CoverageMappingGen.cpp --- a/clang/lib/CodeGen/CoverageMappingGen.cpp +++ b/clang/lib/CodeGen/CoverageMappingGen.cpp @@ -88,6 +88,10 @@ SkippedRanges.back().NextTokLoc = Loc; } +void CoverageSourceInfo::BlankLines(SourceRange Range) { + BlankLineRanges.push_back(Range); +} + namespace { /// A region of source code that can be mapped to a counter. @@ -196,6 +200,7 @@ public: CoverageMappingModuleGen &CVM; SourceManager &SM; + const CodeGenOptions &CodeGenOpts; const LangOptions &LangOpts; private: @@ -218,8 +223,9 @@ SourceRegionFilter; CoverageMappingBuilder(CoverageMappingModuleGen &CVM, SourceManager &SM, + const CodeGenOptions &CodeGenOpts, const LangOptions &LangOpts) - : CVM(CVM), SM(SM), LangOpts(LangOpts) {} + : CVM(CVM), SM(SM), CodeGenOpts(CodeGenOpts), LangOpts(LangOpts) {} /// Return the precise end location for the given token. SourceLocation getPreciseTokenLocEnd(SourceLocation Loc) { @@ -395,6 +401,33 @@ Region.LineEnd <= FileLineRanges[*CovFileID].second) MappingRegions.push_back(Region); } + + if (CodeGenOpts.OmitBlankLines) { + auto BlankLines = CVM.getSourceInfo().getBlankLines(); + for (const auto &I : BlankLines) { + auto LocStart = I.getBegin(); + auto LocEnd = I.getEnd(); + assert(SM.isWrittenInSameFile(LocStart, LocEnd) && + "region spans multiple files"); + assert(!SM.isBeforeInTranslationUnit(LocEnd, LocStart) && + "Blank region end points are out of order"); + + auto CovFileID = getCoverageFileID(LocStart); + if (!CovFileID) + continue; + SpellingRegion SR{SM, LocStart, LocEnd}; + // see comment in readMappingRegionsSubArray in llvm/lib/ProfileData/ + // Coverage/CoverageMappingReader.cpp for an explanation of why we + // use 0 for start and end column on lines we want to omit + auto Region = CounterMappingRegion::makeSkipped( + *CovFileID, SR.LineStart, 0, SR.LineEnd, 0); + // Make sure that we only collect the regions that are inside + // the source code of this function. + if (Region.LineStart >= FileLineRanges[*CovFileID].first && + Region.LineEnd <= FileLineRanges[*CovFileID].second) + MappingRegions.push_back(Region); + } + } } /// Generate the coverage counter mapping regions from collected @@ -480,8 +513,9 @@ /// are not emitted. struct EmptyCoverageMappingBuilder : public CoverageMappingBuilder { EmptyCoverageMappingBuilder(CoverageMappingModuleGen &CVM, SourceManager &SM, + const CodeGenOptions &CodeGenOpts, const LangOptions &LangOpts) - : CoverageMappingBuilder(CVM, SM, LangOpts) {} + : CoverageMappingBuilder(CVM, SM, CodeGenOpts, LangOpts) {} void VisitDecl(const Decl *D) { if (!D->hasBody()) @@ -938,8 +972,9 @@ CounterCoverageMappingBuilder( CoverageMappingModuleGen &CVM, llvm::DenseMap &CounterMap, SourceManager &SM, - const LangOptions &LangOpts) - : CoverageMappingBuilder(CVM, SM, LangOpts), CounterMap(CounterMap) {} + const CodeGenOptions &CodeGenOpts, const LangOptions &LangOpts) + : CoverageMappingBuilder(CVM, SM, CodeGenOpts, LangOpts), + CounterMap(CounterMap) {} /// Write the mapping data to the output stream void write(llvm::raw_ostream &OS) { @@ -1756,14 +1791,15 @@ void CoverageMappingGen::emitCounterMapping(const Decl *D, llvm::raw_ostream &OS) { assert(CounterMap); - CounterCoverageMappingBuilder Walker(CVM, *CounterMap, SM, LangOpts); + CounterCoverageMappingBuilder Walker(CVM, *CounterMap, SM, CodeGenOpts, + LangOpts); Walker.VisitDecl(D); Walker.write(OS); } void CoverageMappingGen::emitEmptyMapping(const Decl *D, llvm::raw_ostream &OS) { - EmptyCoverageMappingBuilder Walker(CVM, SM, LangOpts); + EmptyCoverageMappingBuilder Walker(CVM, SM, CodeGenOpts, LangOpts); Walker.VisitDecl(D); Walker.write(OS); } diff --git a/clang/lib/Lex/Preprocessor.cpp b/clang/lib/Lex/Preprocessor.cpp --- a/clang/lib/Lex/Preprocessor.cpp +++ b/clang/lib/Lex/Preprocessor.cpp @@ -964,6 +964,31 @@ } } + if (Callbacks) { + SourceLocation TokenLoc = Result.getLocation(); + if (TokenLoc.isFileID() && + !SourceMgr.isInSystemHeader(SourceMgr.getSpellingLoc(TokenLoc))) { + bool Invalid = false; + unsigned LineNumber = SourceMgr.getSpellingLineNumber(TokenLoc, &Invalid); + if (!Invalid) { + FileID FID = SourceMgr.getFileID(TokenLoc); + HighestLineNumberMap::iterator fi = HighestLineNumbers.find(FID); + unsigned HighestLineNumber = + fi == HighestLineNumbers.end() ? 0 : fi->second; + if (LineNumber > HighestLineNumber + 1) { + SourceLocation BlankStart = + SourceMgr.translateLineCol(FID, HighestLineNumber + 1, 1); + SourceLocation BlankEnd = + SourceMgr.translateLineCol(FID, LineNumber - 1, 1); + Callbacks->BlankLines(SourceRange(BlankStart, BlankEnd)); + } + if (LineNumber > HighestLineNumber) { + HighestLineNumbers[FID] = LineNumber; + } + } + } + } + LastTokenWasAt = Result.is(tok::at); --LexLevel; diff --git a/llvm/tools/llvm-cov/CoverageExporterLcov.cpp b/llvm/tools/llvm-cov/CoverageExporterLcov.cpp --- a/llvm/tools/llvm-cov/CoverageExporterLcov.cpp +++ b/llvm/tools/llvm-cov/CoverageExporterLcov.cpp @@ -70,7 +70,10 @@ for (; LCI != LCIEnd; ++LCI) { const coverage::LineCoverageStats &LCS = *LCI; if (LCS.isMapped()) { - OS << "DA:" << LCS.getLine() << ',' << LCS.getExecutionCount() << '\n'; + OS << "DA:" << LCS.getLine() << ',' + << ((LCS.getExecutionCount() & (1ULL << 63)) ? 0 + : LCS.getExecutionCount()) + << '\n'; } } }