Index: cfe/trunk/lib/CodeGen/CoverageMappingGen.cpp =================================================================== --- cfe/trunk/lib/CodeGen/CoverageMappingGen.cpp +++ cfe/trunk/lib/CodeGen/CoverageMappingGen.cpp @@ -130,6 +130,16 @@ return strcmp(SM.getBufferName(SM.getSpellingLoc(Loc)), "") == 0; } + /// \brief Check whether \c Loc is included or expanded from \c Parent. + bool isNestedIn(SourceLocation Loc, FileID Parent) { + do { + Loc = getIncludeOrExpansionLoc(Loc); + if (Loc.isInvalid()) + return false; + } while (!SM.isInFileID(Loc, Parent)); + return true; + } + /// \brief Get the start of \c S ignoring macro arguments and builtin macros. SourceLocation getStart(const Stmt *S) { SourceLocation Loc = S->getLocStart(); @@ -310,7 +320,27 @@ if (!D->hasBody()) return; auto Body = D->getBody(); - SourceRegions.emplace_back(Counter(), getStart(Body), getEnd(Body)); + SourceLocation Start = getStart(Body); + SourceLocation End = getEnd(Body); + if (!SM.isWrittenInSameFile(Start, End)) { + // Walk up to find the common ancestor. + // Correct the locations accordingly. + FileID StartFileID = SM.getFileID(Start); + FileID EndFileID = SM.getFileID(End); + while (StartFileID != EndFileID && !isNestedIn(End, StartFileID)) { + Start = getIncludeOrExpansionLoc(Start); + assert(Start.isValid() && + "Declaration start location not nested within a known region"); + StartFileID = SM.getFileID(Start); + } + while (StartFileID != EndFileID) { + End = getPreciseTokenLocEnd(getIncludeOrExpansionLoc(End)); + assert(End.isValid() && + "Declaration end location not nested within a known region"); + EndFileID = SM.getFileID(End); + } + } + SourceRegions.emplace_back(Counter(), Start, End); } /// \brief Write the mapping data to the output stream @@ -471,16 +501,6 @@ MostRecentLocation = getIncludeOrExpansionLoc(MostRecentLocation); } - /// \brief Check whether \c Loc is included or expanded from \c Parent. - bool isNestedIn(SourceLocation Loc, FileID Parent) { - do { - Loc = getIncludeOrExpansionLoc(Loc); - if (Loc.isInvalid()) - return false; - } while (!SM.isInFileID(Loc, Parent)); - return true; - } - /// \brief Adjust regions and state when \c NewLoc exits a file. /// /// If moving from our most recently tracked location to \c NewLoc exits any Index: cfe/trunk/test/CoverageMapping/Inputs/ends_a_scope_only =================================================================== --- cfe/trunk/test/CoverageMapping/Inputs/ends_a_scope_only +++ cfe/trunk/test/CoverageMapping/Inputs/ends_a_scope_only @@ -0,0 +1 @@ +} Index: cfe/trunk/test/CoverageMapping/Inputs/starts_a_scope_only =================================================================== --- cfe/trunk/test/CoverageMapping/Inputs/starts_a_scope_only +++ cfe/trunk/test/CoverageMapping/Inputs/starts_a_scope_only @@ -0,0 +1 @@ +{ Index: cfe/trunk/test/CoverageMapping/unused_function.cpp =================================================================== --- cfe/trunk/test/CoverageMapping/unused_function.cpp +++ cfe/trunk/test/CoverageMapping/unused_function.cpp @@ -0,0 +1,37 @@ +// RUN: %clang_cc1 -fprofile-instrument=clang -fcoverage-mapping -dump-coverage-mapping -emit-llvm-only %s | FileCheck %s + +#define START_SCOPE { +#define END_SCOPE } + +// CHECK: _Z2f0v: +// CHECK-NEXT: File 0, [[@LINE+1]]:18 -> [[@LINE+1]]:20 = 0 +inline void f0() {} + +// CHECK: _Z2f1v: +// CHECK-NEXT: File 0, [[@LINE+1]]:18 -> [[@LINE+1]]:31 = 0 +inline void f1() START_SCOPE } + +// CHECK: _Z2f2v: +// CHECK-NEXT: File 0, [[@LINE+1]]:18 -> [[@LINE+1]]:29 = 0 +inline void f2() { END_SCOPE + +// CHECK: _Z2f3v: +// CHECK-NEXT: File 0, [[@LINE+1]]:18 -> [[@LINE+1]]:39 = 0 +inline void f3() START_SCOPE END_SCOPE + +// CHECK: _Z2f4v: +// CHECK-NEXT: File 0, [[@LINE+2]]:10 -> [[@LINE+3]]:2 = 0 +inline void f4() +#include "Inputs/starts_a_scope_only" +} + +// CHECK: _Z2f5v: +// CHECK-NEXT: File 0, [[@LINE+1]]:18 -> [[@LINE+2]]:36 = 0 +inline void f5() { +#include "Inputs/ends_a_scope_only" + +// CHECK: _Z2f6v: +// CHECK-NEXT: File 0, [[@LINE+2]]:10 -> [[@LINE+3]]:36 = 0 +inline void f6() +#include "Inputs/starts_a_scope_only" +#include "Inputs/ends_a_scope_only"