diff --git a/clang-tools-extra/clang-query/Query.h b/clang-tools-extra/clang-query/Query.h --- a/clang-tools-extra/clang-query/Query.h +++ b/clang-tools-extra/clang-query/Query.h @@ -18,7 +18,7 @@ namespace clang { namespace query { -enum OutputKind { OK_Diag, OK_Print, OK_DetailedAST }; +enum OutputKind { OK_Diag, OK_Print, OK_DetailedAST, OK_SrcLoc }; enum QueryKind { QK_Invalid, diff --git a/clang-tools-extra/clang-query/Query.cpp b/clang-tools-extra/clang-query/Query.cpp --- a/clang-tools-extra/clang-query/Query.cpp +++ b/clang-tools-extra/clang-query/Query.cpp @@ -12,6 +12,7 @@ #include "clang/ASTMatchers/ASTMatchFinder.h" #include "clang/Frontend/ASTUnit.h" #include "clang/Frontend/TextDiagnostic.h" +#include "clang/Tooling/NodeLocationIntrospection.h" #include "llvm/Support/raw_ostream.h" using namespace clang::ast_matchers; @@ -68,6 +69,8 @@ "Diagnostic location for bound nodes.\n" " detailed-ast " "Detailed AST output for bound nodes.\n" + " srcloc " + "Source locations and ranges for bound nodes.\n" " dump " "Detailed AST output for bound nodes (alias of detailed-ast).\n\n"; return true; @@ -88,6 +91,105 @@ } }; +void dumpLocations(llvm::raw_ostream &OS, ast_type_traits::DynTypedNode node, + ASTContext &Ctx, const DiagnosticsEngine &Diags, + SourceManager const &SM) { + auto locs = clang::tooling::NodeLocationIntrospection::GetLocations(node); + + for (auto it = locs.LocationAccessors.begin(); + it != locs.LocationAccessors.end(); ++it) { + if (!it->first.isValid()) + continue; + + TextDiagnostic TD(OS, Ctx.getLangOpts(), &Diags.getDiagnosticOptions()); + TD.emitDiagnostic(FullSourceLoc(it->first, SM), DiagnosticsEngine::Note, + "SourceLocations here", None, None); + + auto commonLoc = it->first; + auto scout = it; + while (scout->first == commonLoc) { + OS << " * " + << "\"" + it->second + "()\"\n"; + if (scout == locs.LocationAccessors.end()) + break; + ++scout; + if (scout->first == commonLoc) { + ++it; + } + } + OS << '\n'; + } + + for (auto it = locs.RangeAccessors.begin(); it != locs.RangeAccessors.end(); + ++it) { + + if (!it->first.getBegin().isValid()) + continue; + + if (SM.getPresumedLineNumber(it->first.getBegin()) != + SM.getPresumedLineNumber(it->first.getEnd())) + continue; + + TextDiagnostic TD(OS, Ctx.getLangOpts(), &Diags.getDiagnosticOptions()); + TD.emitDiagnostic(FullSourceLoc(it->first.getBegin(), SM), + DiagnosticsEngine::Note, + "SourceRanges here " + it->first.printToString(SM), + CharSourceRange::getTokenRange(it->first), None); + + auto commonLoc = it->first; + auto scout = it; + while (scout->first == commonLoc) { + OS << " * " + << "\"" + it->second + "()\"\n"; + if (scout == locs.RangeAccessors.end()) + break; + ++scout; + if (scout->first == commonLoc) { + ++it; + } + } + } + for (auto it = locs.RangeAccessors.begin(); it != locs.RangeAccessors.end(); + ++it) { + + if (!it->first.getBegin().isValid()) + continue; + + if (SM.getPresumedLineNumber(it->first.getBegin()) == + SM.getPresumedLineNumber(it->first.getEnd())) + continue; + + TextDiagnostic TD(OS, Ctx.getLangOpts(), &Diags.getDiagnosticOptions()); + TD.emitDiagnostic( + FullSourceLoc(it->first.getBegin(), SM), DiagnosticsEngine::Note, + "SourceRange " + it->first.printToString(SM) + " starting here...", + CharSourceRange::getTokenRange(it->first), None); + + auto colNum = SM.getPresumedColumnNumber(it->first.getEnd()); + auto lastLineLoc = it->first.getEnd().getLocWithOffset(-(colNum - 1)); + + TD.emitDiagnostic(FullSourceLoc(it->first.getEnd(), SM), + DiagnosticsEngine::Note, "... ending here", + CharSourceRange::getTokenRange( + SourceRange(lastLineLoc, it->first.getEnd())), + None); + + auto commonLoc = it->first; + auto scout = it; + while (scout->first == commonLoc) { + OS << " * " + << "\"" + it->second + "()\"\n"; + if (scout == locs.RangeAccessors.end()) + break; + ++scout; + if (scout->first == commonLoc) { + ++it; + } + } + } + OS << "\n"; +} + } // namespace bool MatchQuery::run(llvm::raw_ostream &OS, QuerySession &QS) const { @@ -108,8 +210,10 @@ return false; } - AST->getASTContext().getParentMapContext().setTraversalKind(QS.TK); - Finder.matchAST(AST->getASTContext()); + auto &Ctx = AST->getASTContext(); + const auto &SM = Ctx.getSourceManager(); + Ctx.getParentMapContext().setTraversalKind(QS.TK); + Finder.matchAST(Ctx); if (QS.PrintMatcher) { SmallVector Lines; @@ -155,13 +259,18 @@ } if (QS.DetailedASTOutput) { OS << "Binding for \"" << BI->first << "\":\n"; - const ASTContext &Ctx = AST->getASTContext(); - const SourceManager &SM = Ctx.getSourceManager(); ASTDumper Dumper(OS, Ctx, SM.getDiagnostics().getShowColors()); Dumper.SetTraversalKind(QS.TK); Dumper.Visit(BI->second); OS << "\n"; } + if (QS.SrcLocOutput) { + OS << "\n \"" << BI->first << "\" Source locations\n"; + OS << " " << std::string(19 + BI->first.size(), '-') << '\n'; + + dumpLocations(OS, BI->second, Ctx, AST->getDiagnostics(), SM); + OS << "\n"; + } } if (MI->getMap().empty()) diff --git a/clang-tools-extra/clang-query/QueryParser.cpp b/clang-tools-extra/clang-query/QueryParser.cpp --- a/clang-tools-extra/clang-query/QueryParser.cpp +++ b/clang-tools-extra/clang-query/QueryParser.cpp @@ -108,6 +108,7 @@ .Case("diag", OK_Diag) .Case("print", OK_Print) .Case("detailed-ast", OK_DetailedAST) + .Case("srcloc", OK_SrcLoc) .Case("dump", OK_DetailedAST) .Default(~0u); if (OutKind == ~0u) { @@ -123,6 +124,8 @@ return new QueryType(&QuerySession::DiagOutput); case OK_Print: return new QueryType(&QuerySession::PrintOutput); + case OK_SrcLoc: + return new QueryType(&QuerySession::SrcLocOutput); } llvm_unreachable("Invalid output kind"); diff --git a/clang-tools-extra/clang-query/QuerySession.h b/clang-tools-extra/clang-query/QuerySession.h --- a/clang-tools-extra/clang-query/QuerySession.h +++ b/clang-tools-extra/clang-query/QuerySession.h @@ -25,14 +25,15 @@ public: QuerySession(llvm::ArrayRef> ASTs) : ASTs(ASTs), PrintOutput(false), DiagOutput(true), - DetailedASTOutput(false), BindRoot(true), PrintMatcher(false), - Terminate(false), TK(ast_type_traits::TK_AsIs) {} + DetailedASTOutput(false), SrcLocOutput(false), BindRoot(true), + PrintMatcher(false), Terminate(false), TK(ast_type_traits::TK_AsIs) {} llvm::ArrayRef> ASTs; bool PrintOutput; bool DiagOutput; bool DetailedASTOutput; + bool SrcLocOutput; bool BindRoot; bool PrintMatcher;