]> granicus.if.org Git - clang/commitdiff
[Coverage] Do not visit artificial stmts in defaulted methods (PR39822)
authorVedant Kumar <vsk@apple.com>
Wed, 28 Nov 2018 20:48:07 +0000 (20:48 +0000)
committerVedant Kumar <vsk@apple.com>
Wed, 28 Nov 2018 20:48:07 +0000 (20:48 +0000)
There is no reason to emit coverage mappings for artificial statements
contained within defaulted methods, as these statements are not visible
to users.

Only emit a mapping for the body of the defaulted method (clang treats
the text of the "default" keyword as the body when reporting locations).
This allows users to see how often the default method is called, but
trims down the coverage mapping by skipping visitation of the children
of the method.

The immediate motivation for this change is that the lexer's
getPreciseTokenLocEnd API cannot return the correct location when given
an artificial statement (with a somewhat made-up location) as an input.

Test by Orivej Desh!

Fixes llvm.org/PR39822.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@347803 91177308-0d34-0410-b5e6-96231b3b80d8

lib/CodeGen/CoverageMappingGen.cpp
test/CoverageMapping/default-method.cpp [new file with mode: 0644]

index 732ecd05abf116355566a153ec69fd123c6f647d..35962c73d9a8254afba7162a15a2e45cb9ef7fd5 100644 (file)
@@ -656,12 +656,15 @@ struct CounterCoverageMappingBuilder
     return RegionStack.back();
   }
 
-  /// Propagate counts through the children of \c S.
-  Counter propagateCounts(Counter TopCount, const Stmt *S) {
+  /// Propagate counts through the children of \p S if \p VisitChildren is true.
+  /// Otherwise, only emit a count for \p S itself.
+  Counter propagateCounts(Counter TopCount, const Stmt *S,
+                          bool VisitChildren = true) {
     SourceLocation StartLoc = getStart(S);
     SourceLocation EndLoc = getEnd(S);
     size_t Index = pushRegion(TopCount, StartLoc, EndLoc);
-    Visit(S);
+    if (VisitChildren)
+      Visit(S);
     Counter ExitCount = getRegion().getCounter();
     popRegions(Index);
 
@@ -874,7 +877,16 @@ struct CounterCoverageMappingBuilder
     if (Body && SM.isInSystemHeader(SM.getSpellingLoc(getStart(Body))))
       return;
 
-    propagateCounts(getRegionCounter(Body), Body);
+    // Do not visit the artificial children nodes of defaulted methods. The
+    // lexer may not be able to report back precise token end locations for
+    // these children nodes (llvm.org/PR39822), and moreover users will not be
+    // able to see coverage for them.
+    bool Defaulted = false;
+    if (auto *Method = dyn_cast<CXXMethodDecl>(D))
+      Defaulted = Method->isDefaulted();
+
+    propagateCounts(getRegionCounter(Body), Body,
+                    /*VisitChildren=*/!Defaulted);
     assert(RegionStack.empty() && "Regions entered but never exited");
 
     // Discard the last uncompleted deferred region in a decl, if one exists.
diff --git a/test/CoverageMapping/default-method.cpp b/test/CoverageMapping/default-method.cpp
new file mode 100644 (file)
index 0000000..e097a16
--- /dev/null
@@ -0,0 +1,17 @@
+// RUN: %clang_cc1 -std=c++17 -fprofile-instrument=clang -fcoverage-mapping -dump-coverage-mapping -emit-llvm-only -main-file-name default-method.cpp -w %s | FileCheck %s -implicit-check-not="->"
+
+namespace PR39822 {
+  struct unique_ptr {
+    unique_ptr &operator=(unique_ptr &);
+  };
+
+  class foo {
+    foo &operator=(foo &);
+    unique_ptr convertable_values_[2];
+  };
+
+  // CHECK: _ZN7PR398223fooaSERS0_:
+  // CHECK-NEXT: File 0, [[@LINE+1]]:28 -> [[@LINE+1]]:29 = #0
+  foo &foo::operator=(foo &) = default;
+} // namespace PR39822
+