[clang-tools-extra] 2675773 - [include-cleaner] add macro symbols and implicit refs to HTML report
Sam McCall via cfe-commits
cfe-commits at lists.llvm.org
Thu Nov 17 08:29:48 PST 2022
Author: Sam McCall
Date: 2022-11-17T17:29:41+01:00
New Revision: 267577325876d7e3e2b96c0a577b1b8ce076dfbb
URL: https://github.com/llvm/llvm-project/commit/267577325876d7e3e2b96c0a577b1b8ce076dfbb
DIFF: https://github.com/llvm/llvm-project/commit/267577325876d7e3e2b96c0a577b1b8ce076dfbb.diff
LOG: [include-cleaner] add macro symbols and implicit refs to HTML report
Demo: http://htmlpreview.github.io/?https://gist.githubusercontent.com/sam-mccall/fec9b77c726cfb3cc7c424b197e3f68c/raw/8c5c5ad927b0485db76c34c25250b0ae8f7637f8/ASTTests.html
Differential Revision: https://reviews.llvm.org/D137677
Added:
Modified:
clang-tools-extra/include-cleaner/include/clang-include-cleaner/Analysis.h
clang-tools-extra/include-cleaner/lib/Analysis.cpp
clang-tools-extra/include-cleaner/lib/AnalysisInternal.h
clang-tools-extra/include-cleaner/lib/FindHeaders.cpp
clang-tools-extra/include-cleaner/lib/HTMLReport.cpp
clang-tools-extra/include-cleaner/lib/Types.cpp
clang-tools-extra/include-cleaner/tool/IncludeCleaner.cpp
clang-tools-extra/include-cleaner/unittests/AnalysisTest.cpp
clang-tools-extra/include-cleaner/unittests/FindHeadersTest.cpp
Removed:
################################################################################
diff --git a/clang-tools-extra/include-cleaner/include/clang-include-cleaner/Analysis.h b/clang-tools-extra/include-cleaner/include/clang-include-cleaner/Analysis.h
index 7b8606f4a6ce4..31ae7592ceec0 100644
--- a/clang-tools-extra/include-cleaner/include/clang-include-cleaner/Analysis.h
+++ b/clang-tools-extra/include-cleaner/include/clang-include-cleaner/Analysis.h
@@ -45,7 +45,7 @@ using UsedSymbolCB = llvm::function_ref<void(const SymbolReference &SymRef,
/// the headers for any referenced symbol
void walkUsed(llvm::ArrayRef<Decl *> ASTRoots,
llvm::ArrayRef<SymbolReference> MacroRefs,
- const PragmaIncludes &PI, const SourceManager &, UsedSymbolCB CB);
+ const PragmaIncludes *PI, const SourceManager &, UsedSymbolCB CB);
} // namespace include_cleaner
} // namespace clang
diff --git a/clang-tools-extra/include-cleaner/lib/Analysis.cpp b/clang-tools-extra/include-cleaner/lib/Analysis.cpp
index 890e5e13fa57f..e2455e115de24 100644
--- a/clang-tools-extra/include-cleaner/lib/Analysis.cpp
+++ b/clang-tools-extra/include-cleaner/lib/Analysis.cpp
@@ -19,8 +19,9 @@ namespace clang::include_cleaner {
void walkUsed(llvm::ArrayRef<Decl *> ASTRoots,
llvm::ArrayRef<SymbolReference> MacroRefs,
- const PragmaIncludes &PI, const SourceManager &SM,
+ const PragmaIncludes *PI, const SourceManager &SM,
UsedSymbolCB CB) {
+ // This is duplicated in writeHTMLReport, changes should be mirrored there.
tooling::stdlib::Recognizer Recognizer;
for (auto *Root : ASTRoots) {
auto &SM = Root->getASTContext().getSourceManager();
diff --git a/clang-tools-extra/include-cleaner/lib/AnalysisInternal.h b/clang-tools-extra/include-cleaner/lib/AnalysisInternal.h
index 17c11c1218dde..ec378dca6ec70 100644
--- a/clang-tools-extra/include-cleaner/lib/AnalysisInternal.h
+++ b/clang-tools-extra/include-cleaner/lib/AnalysisInternal.h
@@ -75,18 +75,18 @@ struct SymbolLocation {
// Order must match Kind enum!
std::variant<SourceLocation, tooling::stdlib::Symbol> Storage;
};
-llvm::raw_ostream &operator<<(llvm::raw_ostream &, const Header &);
+llvm::raw_ostream &operator<<(llvm::raw_ostream &, const SymbolLocation &);
/// Finds the headers that provide the symbol location.
// FIXME: expose signals
llvm::SmallVector<Header> findHeaders(const SymbolLocation &Loc,
const SourceManager &SM,
- const PragmaIncludes &PI);
+ const PragmaIncludes *PI);
/// Write an HTML summary of the analysis to the given stream.
-/// FIXME: Once analysis has a public API, this should be public too.
-void writeHTMLReport(FileID File, llvm::ArrayRef<Decl *> Roots, ASTContext &Ctx,
- llvm::raw_ostream &OS);
+void writeHTMLReport(FileID File, llvm::ArrayRef<Decl *> Roots,
+ llvm::ArrayRef<SymbolReference> MacroRefs, ASTContext &Ctx,
+ PragmaIncludes *PI, llvm::raw_ostream &OS);
} // namespace include_cleaner
} // namespace clang
diff --git a/clang-tools-extra/include-cleaner/lib/FindHeaders.cpp b/clang-tools-extra/include-cleaner/lib/FindHeaders.cpp
index 093cba8b769a9..c782ff89755cb 100644
--- a/clang-tools-extra/include-cleaner/lib/FindHeaders.cpp
+++ b/clang-tools-extra/include-cleaner/lib/FindHeaders.cpp
@@ -14,7 +14,7 @@ namespace clang::include_cleaner {
llvm::SmallVector<Header> findHeaders(const SymbolLocation &Loc,
const SourceManager &SM,
- const PragmaIncludes &PI) {
+ const PragmaIncludes *PI) {
llvm::SmallVector<Header> Results;
switch (Loc.kind()) {
case SymbolLocation::Physical: {
@@ -25,18 +25,21 @@ llvm::SmallVector<Header> findHeaders(const SymbolLocation &Loc,
if (!FE)
return {};
- // We treat the spelling header in the IWYU pragma as the final public
- // header.
- // FIXME: look for exporters if the public header is exported by another
- // header.
- llvm::StringRef VerbatimSpelling = PI.getPublic(FE);
- if (!VerbatimSpelling.empty())
- return {Header(VerbatimSpelling)};
-
Results = {Header(FE)};
- // FIXME: compute transitive exporter headers.
- for (const auto *Export : PI.getExporters(FE, SM.getFileManager()))
- Results.push_back(Export);
+ if (PI) {
+ // We treat the spelling header in the IWYU pragma as the final public
+ // header.
+ // FIXME: look for exporters if the public header is exported by another
+ // header.
+ llvm::StringRef VerbatimSpelling = PI->getPublic(FE);
+ if (!VerbatimSpelling.empty())
+ return {Header(VerbatimSpelling)};
+
+ // FIXME: compute transitive exporter headers.
+ for (const auto *Export : PI->getExporters(FE, SM.getFileManager()))
+ Results.push_back(Export);
+ }
+
return Results;
}
case SymbolLocation::Standard: {
diff --git a/clang-tools-extra/include-cleaner/lib/HTMLReport.cpp b/clang-tools-extra/include-cleaner/lib/HTMLReport.cpp
index f54b4f4da8267..b1c9f6d548662 100644
--- a/clang-tools-extra/include-cleaner/lib/HTMLReport.cpp
+++ b/clang-tools-extra/include-cleaner/lib/HTMLReport.cpp
@@ -14,12 +14,13 @@
//===----------------------------------------------------------------------===//
#include "AnalysisInternal.h"
-#include "clang-include-cleaner/Analysis.h"
+#include "clang-include-cleaner/Types.h"
#include "clang/AST/ASTContext.h"
-#include "clang/AST/Decl.h"
#include "clang/AST/PrettyPrinter.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Lex/Lexer.h"
+#include "clang/Tooling/Inclusions/StandardLibrary.h"
+#include "llvm/Support/ScopedPrinter.h"
#include "llvm/Support/raw_ostream.h"
namespace clang::include_cleaner {
@@ -38,16 +39,24 @@ constexpr llvm::StringLiteral CSS = R"css(
}
.ref { text-decoration: underline; color: #008; }
.sel { position: relative; cursor: pointer; }
+ .ref.implicit { background-color: #ff8; }
#hover {
- background-color: #aaccff; border: 1px solid black;
+ color: black;
+ background-color: #aaccff; border: 1px solid #444;
z-index: 1;
position: absolute; top: 100%; left: 0;
font-family: sans-serif;
padding: 0.5em;
}
#hover p, #hover pre { margin: 0; }
- #hover section header { font-weight: bold; }
- #hover section:not(:first-child) { margin-top: 1em; }
+ #hover .target.implicit { background-color: #bbb; }
+ #hover .target.ambiguous { background-color: #caf; }
+ #hover th { color: #008; text-align: right; padding-right: 0.5em; }
+ #hover .target:not(:first-child) {
+ margin-top: 1em;
+ padding-top: 1em;
+ border-top: 1px solid #444;
+ }
)css";
constexpr llvm::StringLiteral JS = R"js(
@@ -74,49 +83,95 @@ constexpr llvm::StringLiteral JS = R"js(
}
)js";
-// Print the declaration tersely, but enough to identify e.g. which overload.
-std::string printDecl(const NamedDecl &ND) {
- std::string S;
- llvm::raw_string_ostream OS(S);
- PrintingPolicy PP = ND.getASTContext().getPrintingPolicy();
- PP.FullyQualifiedName = true;
- PP.TerseOutput = true;
- PP.SuppressInitializers = true;
- ND.print(OS, PP);
- llvm::erase_value(S, '\n');
- return S;
+// Categorize the symbol, like FunctionDecl or Macro
+llvm::StringRef describeSymbol(const Symbol &Sym) {
+ switch (Sym.kind()) {
+ case Symbol::Declaration:
+ return Sym.declaration().getDeclKindName();
+ case Symbol::Macro:
+ return "Macro";
+ }
+ llvm_unreachable("unhandled symbol kind");
+}
+
+llvm::StringRef refType(RefType T) {
+ switch (T) {
+ case RefType::Explicit:
+ return "explicit";
+ case RefType::Implicit:
+ return "implicit";
+ case RefType::Ambiguous:
+ return "ambiguous";
+ }
}
class Reporter {
llvm::raw_ostream &OS;
const ASTContext &Ctx;
const SourceManager &SM;
+ const PragmaIncludes *PI;
FileID File;
- // Symbols that are referenced from the main file.
+ // References to symbols from the main file.
+ // FIXME: should we deduplicate these?
struct Target {
- const NamedDecl *D;
+ Symbol Sym;
+ RefType Type;
+ SmallVector<SymbolLocation> Locations;
+ SmallVector<Header> Headers;
};
std::vector<Target> Targets;
// Points within the main file that reference a Target.
- std::vector<std::pair</*Offset*/ unsigned, /*TargetIndex*/ unsigned>> Refs;
+ // Implicit refs will be marked with a symbol just before the token.
+ struct Ref {
+ unsigned Offset;
+ bool Implicit;
+ size_t TargetIndex;
+ bool operator<(const Ref &Other) const {
+ return std::forward_as_tuple(Offset, !Implicit, TargetIndex) <
+ std::forward_as_tuple(Other.Offset, !Other.Implicit, TargetIndex);
+ }
+ };
+ std::vector<Ref> Refs;
+
+ Target makeTarget(const SymbolReference &SR) {
+ Target T{SR.Target, SR.RT, {}, {}};
+
+ // Duplicates logic from walkUsed(), which doesn't expose SymbolLocations.
+ // FIXME: use locateDecl and friends once implemented.
+ // This doesn't use stdlib::Recognizer, but locateDecl will soon do that.
+ switch (SR.Target.kind()) {
+ case Symbol::Declaration:
+ T.Locations.push_back(SR.Target.declaration().getLocation());
+ break;
+ case Symbol::Macro:
+ T.Locations.push_back(SR.Target.macro().Definition);
+ break;
+ }
+
+ for (const auto &Loc : T.Locations)
+ T.Headers = findHeaders(Loc, SM, PI);
+
+ return T;
+ }
public:
- Reporter(llvm::raw_ostream &OS, ASTContext &Ctx, FileID File)
- : OS(OS), Ctx(Ctx), SM(Ctx.getSourceManager()), File(File) {}
+ Reporter(llvm::raw_ostream &OS, ASTContext &Ctx, const PragmaIncludes *PI,
+ FileID File)
+ : OS(OS), Ctx(Ctx), SM(Ctx.getSourceManager()), PI(PI), File(File) {}
- void addRef(SourceLocation Loc, const NamedDecl &D) {
- auto [File, Offset] = SM.getDecomposedLoc(SM.getFileLoc(Loc));
+ void addRef(const SymbolReference &SR) {
+ auto [File, Offset] = SM.getDecomposedLoc(SM.getFileLoc(SR.RefLocation));
if (File != this->File) {
// Can get here e.g. if there's an #include inside a root Decl.
// FIXME: do something more useful than this.
- llvm::errs() << "Ref location outside file! "
- << D.getQualifiedNameAsString() << " at "
- << Loc.printToString(SM) << "\n";
+ llvm::errs() << "Ref location outside file! " << SR.Target << " at "
+ << SR.RefLocation.printToString(SM) << "\n";
return;
}
- Targets.push_back({&D});
- Refs.push_back({Offset, Targets.size() - 1});
+
+ Refs.push_back({Offset, SR.RT == RefType::Implicit, Targets.size()});
+ Targets.push_back(makeTarget(SR));
}
void write() {
@@ -126,9 +181,9 @@ class Reporter {
OS << "<style>" << CSS << "</style>\n";
OS << "<script>" << JS << "</script>\n";
for (unsigned I = 0; I < Targets.size(); ++I) {
- OS << "<template id='t" << I << "'><section>";
+ OS << "<template id='t" << I << "'>";
writeTarget(Targets[I]);
- OS << "</section></template>\n";
+ OS << "</template>\n";
}
OS << "</head>\n";
OS << "<body>\n";
@@ -156,16 +211,84 @@ class Reporter {
escapeChar(C);
}
+ // Abbreviate a path ('path/to/Foo.h') to just the filename ('Foo.h').
+ // The full path is available on hover.
+ void printFilename(llvm::StringRef Path) {
+ llvm::StringRef File = llvm::sys::path::filename(Path);
+ if (File == Path)
+ return escapeString(Path);
+ OS << "<span title='";
+ escapeString(Path);
+ OS << "'>";
+ escapeString(File);
+ OS << "</span>";
+ }
+
+ // Print a source location in compact style.
+ void printSourceLocation(SourceLocation Loc) {
+ if (Loc.isInvalid())
+ return escapeString("<invalid>");
+ if (!Loc.isMacroID())
+ return printFilename(Loc.printToString(SM));
+
+ // Replicating printToString() is a bit simpler than parsing/reformatting.
+ printFilename(SM.getExpansionLoc(Loc).printToString(SM));
+ OS << " <Spelling=";
+ printFilename(SM.getSpellingLoc(Loc).printToString(SM));
+ OS << ">";
+ }
+
void writeTarget(const Target &T) {
- OS << "<header>" << T.D->getDeclKindName() << " ";
- escapeString(T.D->getQualifiedNameAsString());
- OS << "</header>";
+ OS << "<table class='target " << refType(T.Type) << "'>";
+
+ OS << "<tr><th>Symbol</th><td>";
+ OS << describeSymbol(T.Sym) << " <code>";
+ escapeString(llvm::to_string(T.Sym));
+ OS << "</code></td></tr>\n";
+
+ if (T.Sym.kind() == Symbol::Declaration) {
+ // Print the declaration of the symbol, e.g. to disambiguate overloads.
+ const auto &D = T.Sym.declaration();
+ PrintingPolicy PP = D.getASTContext().getPrintingPolicy();
+ PP.FullyQualifiedName = true;
+ PP.TerseOutput = true;
+ PP.SuppressInitializers = true;
+ std::string S;
+ llvm::raw_string_ostream SS(S);
+ D.print(SS, PP);
+
+ OS << "<tr><td></td><td><code>";
+ escapeString(S);
+ OS << "</code></td></tr>\n";
+ }
+
+ for (const auto &Loc : T.Locations) {
+ OS << "<tr><th>Location</th><td>";
+ if (Loc.kind() == SymbolLocation::Physical) // needs SM to print properly.
+ printSourceLocation(Loc.physical());
+ else
+ escapeString(llvm::to_string(Loc));
+ OS << "</td></tr>\n";
+ }
+
+ for (const auto &H : T.Headers) {
+ OS << "<tr><th>Header</th><td>";
+ switch (H.kind()) {
+ case Header::Physical:
+ printFilename(H.physical()->getName());
+ break;
+ case Header::Standard:
+ OS << "stdlib " << H.standard().name();
+ break;
+ case Header::Verbatim:
+ OS << "verbatim ";
+ escapeString(H.verbatim());
+ break;
+ }
+ OS << "</td></tr>\n";
+ }
- OS << "<p>declared at ";
- escapeString(SM.getFileLoc(T.D->getLocation()).printToString(SM));
- OS << "</p><pre>";
- escapeString(printDecl(*T.D));
- OS << "</pre>";
+ OS << "</table>";
}
void writeCode() {
@@ -182,14 +305,23 @@ class Reporter {
OS << "</span>";
End = 0;
}
+ // Handle implicit refs, which are rendered *before* the token.
+ while (!Rest.empty() && Rest.front().Offset == I &&
+ Rest.front().Implicit) {
+ const Ref &R = Rest.front();
+ OS << "<span class='ref sel implicit' data-hover='t" << R.TargetIndex
+ << "'>◊</span>";
+ Rest = Rest.drop_front();
+ };
+ // Accumulate all explicit refs that appear on the same token.
std::string TargetList;
- Rest = Rest.drop_while([&](auto &R) {
- if (R.first != I)
+ Rest = Rest.drop_while([&](const Ref &R) {
+ if (R.Offset != I)
return false;
if (!TargetList.empty())
TargetList.push_back(',');
TargetList.push_back('t');
- TargetList.append(std::to_string(R.second));
+ TargetList.append(std::to_string(R.TargetIndex));
return true;
});
if (!TargetList.empty()) {
@@ -209,13 +341,16 @@ class Reporter {
} // namespace
-void writeHTMLReport(FileID File, llvm::ArrayRef<Decl *> Roots, ASTContext &Ctx,
- llvm::raw_ostream &OS) {
- Reporter R(OS, Ctx, File);
+void writeHTMLReport(FileID File, llvm::ArrayRef<Decl *> Roots,
+ llvm::ArrayRef<SymbolReference> MacroRefs, ASTContext &Ctx,
+ PragmaIncludes *PI, llvm::raw_ostream &OS) {
+ Reporter R(OS, Ctx, PI, File);
for (Decl *Root : Roots)
- walkAST(*Root, [&](SourceLocation Loc, const NamedDecl &D, RefType) {
- R.addRef(Loc, D);
+ walkAST(*Root, [&](SourceLocation Loc, const NamedDecl &D, RefType T) {
+ R.addRef(SymbolReference{Loc, D, T});
});
+ for (const SymbolReference &Ref : MacroRefs)
+ R.addRef(Ref);
R.write();
}
diff --git a/clang-tools-extra/include-cleaner/lib/Types.cpp b/clang-tools-extra/include-cleaner/lib/Types.cpp
index 08c9b5980060b..0aa527946bb0d 100644
--- a/clang-tools-extra/include-cleaner/lib/Types.cpp
+++ b/clang-tools-extra/include-cleaner/lib/Types.cpp
@@ -18,10 +18,10 @@ llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const Symbol &S) {
switch (S.kind()) {
case Symbol::Declaration:
if (const auto *ND = llvm::dyn_cast<NamedDecl>(&S.declaration()))
- return OS << ND->getNameAsString();
+ return OS << ND->getQualifiedNameAsString();
return OS << S.declaration().getDeclKindName();
case Symbol::Macro:
- return OS << S.macro().Name;
+ return OS << S.macro().Name->getName();
}
llvm_unreachable("Unhandled Symbol kind");
}
diff --git a/clang-tools-extra/include-cleaner/tool/IncludeCleaner.cpp b/clang-tools-extra/include-cleaner/tool/IncludeCleaner.cpp
index 6d545c5e08734..957dd9c6aab93 100644
--- a/clang-tools-extra/include-cleaner/tool/IncludeCleaner.cpp
+++ b/clang-tools-extra/include-cleaner/tool/IncludeCleaner.cpp
@@ -47,6 +47,15 @@ cl::opt<std::string> HTMLReportPath{
class HTMLReportAction : public clang::ASTFrontendAction {
RecordedAST AST;
+ RecordedPP PP;
+ PragmaIncludes PI;
+
+ void ExecuteAction() override {
+ auto &P = getCompilerInstance().getPreprocessor();
+ P.addPPCallbacks(PP.record(P));
+ PI.record(getCompilerInstance());
+ ASTFrontendAction::ExecuteAction();
+ }
std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI,
StringRef File) override {
@@ -62,7 +71,7 @@ class HTMLReportAction : public clang::ASTFrontendAction {
exit(1);
}
writeHTMLReport(AST.Ctx->getSourceManager().getMainFileID(), AST.Roots,
- *AST.Ctx, OS);
+ PP.MacroReferences, *AST.Ctx, &PI, OS);
}
};
diff --git a/clang-tools-extra/include-cleaner/unittests/AnalysisTest.cpp b/clang-tools-extra/include-cleaner/unittests/AnalysisTest.cpp
index 6d9237c6b7d79..5e3866469862c 100644
--- a/clang-tools-extra/include-cleaner/unittests/AnalysisTest.cpp
+++ b/clang-tools-extra/include-cleaner/unittests/AnalysisTest.cpp
@@ -72,7 +72,7 @@ TEST(WalkUsed, Basic) {
auto &SM = AST.sourceManager();
llvm::DenseMap<size_t, std::vector<Header>> OffsetToProviders;
- walkUsed(TopLevelDecls, /*MacroRefs=*/{}, PI, SM,
+ walkUsed(TopLevelDecls, /*MacroRefs=*/{}, &PI, SM,
[&](const SymbolReference &Ref, llvm::ArrayRef<Header> Providers) {
auto [FID, Offset] = SM.getDecomposedLoc(Ref.RefLocation);
EXPECT_EQ(FID, SM.getMainFileID());
@@ -113,11 +113,10 @@ TEST(WalkUsed, MacroRefs) {
Symbol Answer =
Macro{&Idents.get("ANSWER"), SM.getComposedLoc(HdrID, Hdr.point())};
llvm::DenseMap<size_t, std::vector<Header>> OffsetToProviders;
- PragmaIncludes PI;
walkUsed(/*ASTRoots=*/{}, /*MacroRefs=*/
{SymbolReference{SM.getComposedLoc(SM.getMainFileID(), Main.point()),
Answer, RefType::Explicit}},
- PI, SM,
+ /*PI=*/nullptr, SM,
[&](const SymbolReference &Ref, llvm::ArrayRef<Header> Providers) {
auto [FID, Offset] = SM.getDecomposedLoc(Ref.RefLocation);
EXPECT_EQ(FID, SM.getMainFileID());
diff --git a/clang-tools-extra/include-cleaner/unittests/FindHeadersTest.cpp b/clang-tools-extra/include-cleaner/unittests/FindHeadersTest.cpp
index 02854e65fbcbe..c0da609907408 100644
--- a/clang-tools-extra/include-cleaner/unittests/FindHeadersTest.cpp
+++ b/clang-tools-extra/include-cleaner/unittests/FindHeadersTest.cpp
@@ -61,17 +61,17 @@ TEST(FindIncludeHeaders, IWYU) {
/*Line=*/1, /*Col=*/1);
};
- EXPECT_THAT(findHeaders(SourceLocFromFile("header1.h"), SM, PI),
+ EXPECT_THAT(findHeaders(SourceLocFromFile("header1.h"), SM, &PI),
UnorderedElementsAre(Header("\"path/public.h\"")));
- EXPECT_THAT(findHeaders(SourceLocFromFile("detail1.h"), SM, PI),
+ EXPECT_THAT(findHeaders(SourceLocFromFile("detail1.h"), SM, &PI),
UnorderedElementsAre(Header(FM.getFile("header2.h").get()),
Header(FM.getFile("detail1.h").get())));
- EXPECT_THAT(findHeaders(SourceLocFromFile("detail2.h"), SM, PI),
+ EXPECT_THAT(findHeaders(SourceLocFromFile("detail2.h"), SM, &PI),
UnorderedElementsAre(Header(FM.getFile("header2.h").get()),
Header(FM.getFile("detail2.h").get())));
- EXPECT_THAT(findHeaders(SourceLocFromFile("normal.h"), SM, PI),
+ EXPECT_THAT(findHeaders(SourceLocFromFile("normal.h"), SM, &PI),
UnorderedElementsAre(Header(FM.getFile("normal.h").get())));
}
More information about the cfe-commits
mailing list