llvm-project/clang/test/Frontend/dump-minimization-hints.cpp
Viktoriia Bakalova 9eeafc63d2
Implement -dump-minimization-hints flag. (#133910)
This PR implements a CC1 flag `-dump-minimization-hints`.
The flag allows to specify a file path to dump ranges of deserialized
declarations in `ASTReader`. Example usage:

```
clang -Xclang=-dump-minimization-hints=/tmp/decls -c file.cc -o file.o
```

Example output:
```
// /tmp/decls
{
  "required_ranges": [
    {
      "file": "foo.h",
      "range": [
        {
          "from": {
            "line": 26,
            "column": 1
          },
          "to": {
            "line": 27,
            "column": 77
          }
        }
      ]
    },
    {
      "file": "bar.h",
      "range": [
        {
          "from": {
            "line": 30,
            "column": 1
          },
          "to": {
            "line": 35,
            "column": 1
          }
        },
        {
          "from": {
            "line": 92,
            "column": 1
          },
          "to": {
            "line": 95,
            "column": 1
          }
        }
      ]
    }
  ]
}

```
Specifying the flag creates an instance of
`DeserializedDeclsSourceRangePrinter`, which dumps ranges of deserialized
declarations to aid debugging and bug minimization (we use is as input to [C-Vise](https://github.com/emaxx-google/cvise/tree/multifile-hints).

Required ranges are computed from source ranges of Decls.
`TranslationUnitDecl`, `LinkageSpecDecl` and `NamespaceDecl` are ignored
for the sake of this PR.

Technical details:
* `DeserializedDeclsSourceRangePrinter` implements `ASTConsumer` and
`ASTDeserializationListener`, so that an object of
`DeserializedDeclsSourceRangePrinter` registers as its own listener.
* `ASTDeserializationListener` interface provides the `DeclRead`
callback that we use to collect the deserialized Decls.
Printing or otherwise processing them as this point is dangerous, since
that could trigger additional deserialization and crash compilation.
* The collected Decls are processed in `HandleTranslationUnit` method of
`ASTConsumer`. This is a safe point, since we know that by this point
all the Decls needed by the compiler frontend have been deserialized.
* In case our processing causes further deserialization, `DeclRead` from
the listener might be called again. However, at that point we don't
accept any more Decls for processing.
2025-04-11 12:48:18 +02:00

80 lines
2.0 KiB
C++

// RUN: rm -rf %t
// RUN: mkdir -p %t
// RUN: split-file %s %t
// RUN: %clang_cc1 -xc++ -fmodules -fmodule-name=foo -fmodule-map-file=%t/foo.cppmap -emit-module %t/foo.cppmap -o %t/foo.pcm
// RUN: %clang_cc1 -xc++ -fmodules -dump-minimization-hints=%t/decls -fmodule-file=%t/foo.pcm %t/foo.cpp -o %t/foo.o
// RUN: cat %t/decls
// RUN: cat %t/decls | FileCheck -check-prefix=RANGE %s
// RANGE:{
// RANGE-NEXT: "required_ranges": [
// RANGE-NEXT: {
// RANGE-NEXT: "file": "{{.+}}foo.h",
// RANGE-NEXT: "range": [
// RANGE-NEXT: {
// RANGE-NEXT: "from": {
// RANGE-NEXT: "line": 1,
// RANGE-NEXT: "column": 1
// RANGE-NEXT: },
// RANGE-NEXT: "to": {
// RANGE-NEXT: "line": 9,
// RANGE-NEXT: "column": 3
// RANGE-NEXT: }
// RANGE-NEXT: },
// RANGE-NEXT: {
// RANGE-NEXT: "from": {
// RANGE-NEXT: "line": 11,
// RANGE-NEXT: "column": 1
// RANGE-NEXT: },
// RANGE-NEXT: "to": {
// RANGE-NEXT: "line": 11,
// RANGE-NEXT: "column": 25
// RANGE-NEXT: }
// RANGE-NEXT: },
// RANGE-NEXT: {
// RANGE-NEXT: "from": {
// RANGE-NEXT: "line": 13,
// RANGE-NEXT: "column": 1
// RANGE-NEXT: },
// RANGE-NEXT: "to": {
// RANGE-NEXT: "line": 15,
// RANGE-NEXT: "column": 2
// RANGE-NEXT: }
// RANGE-NEXT: }
// RANGE-NEXT: ]
// RANGE-NEXT: }
// RANGE-NEXT: ]
// RANGE-NEXT:}
//--- foo.cppmap
module foo {
header "foo.h"
export *
}
//--- foo.h
class MyData {
public:
MyData(int val): value_(val) {}
int getValue() const {
return 5;
}
private:
int value_;
};
extern int global_value;
int multiply(int a, int b) {
return a * b;
}
//--- foo.cpp
#include "foo.h"
int global_value = 5;
int main() {
MyData data(5);
int current_value = data.getValue();
int doubled_value = multiply(current_value, 2);
int final_result = doubled_value + global_value;
}