[cfe-dev] Analysing a file with AST matcher tool takes significant more time than just compile the same file
Manuel Klimek
klimek at google.com
Thu Jul 16 02:33:56 PDT 2015
You'll want to use Lexer::getSourceText instead of trying to write your own
(trust me, it's hard ;), but otherwise your code looks innocent enough. Are
you compiling with at least -O2 and NDEBUG enabled?
On Thu, Jul 16, 2015 at 11:26 AM Han Wang <wanghan02 at gmail.com> wrote:
> #include <stdio.h>
> #include <string>
> #include <vector>
> #include <system_error>
> #include <type_traits>
> #include "clang/AST/AST.h"
> #include "clang/Frontend/TextDiagnosticPrinter.h"
> #include "clang/Tooling/CommonOptionsParser.h"
> #include "clang/ASTMatchers/ASTMatchers.h"
> #include "clang/ASTMatchers/ASTMatchFinder.h"
> #include "clang/Basic/SourceManager.h"
> #include "clang/Frontend/FrontendActions.h"
> #include "clang/Lex/Lexer.h"
> #include "clang/Tooling/CompilationDatabase.h"
> #include "clang/Tooling/Refactoring.h"
> #include "clang/Tooling/Tooling.h"
> #include "llvm/ADT/Twine.h"
> #include "llvm/Support/CommandLine.h"
> #include "llvm/Support/MemoryBuffer.h"
> #include "llvm/Support/Path.h"
> #include "llvm/Support/Signals.h"
> #include "llvm/Support/raw_ostream.h"
> #include "llvm/Support/TargetSelect.h"
>
> using namespace llvm;
> using clang::tooling::newFrontendActionFactory;
> using clang::tooling::Replacement;
> using clang::tooling::CompilationDatabase;
> using namespace clang;
> using namespace clang::ast_matchers;
> using namespace clang::driver;
> using namespace clang::tooling;
>
> static llvm::cl::OptionCategory ToolingSampleCategory("IsEmpty");
>
>
> // Returns the text that makes up 'node' in the source.
> // Returns an empty string if the text cannot be found.
> template <typename T>
> static std::string getText(const SourceManager &SourceManager, const T
> &Node) {
> SourceLocation StartSpellingLocation =
> SourceManager.getSpellingLoc(Node.getLocStart());
> SourceLocation EndSpellingLocation =
> SourceManager.getSpellingLoc(Node.getLocEnd());
> if (!StartSpellingLocation.isValid() || !EndSpellingLocation.isValid()) {
> return std::string();
> }
> bool Invalid = true;
> const char *Text =
> SourceManager.getCharacterData(StartSpellingLocation, &Invalid);
> if (Invalid) {
> return std::string();
> }
> std::pair<FileID, unsigned> Start =
> SourceManager.getDecomposedLoc(StartSpellingLocation);
> std::pair<FileID, unsigned> End =
> SourceManager.getDecomposedLoc(Lexer::getLocForEndOfToken(
> EndSpellingLocation, 0, SourceManager, LangOptions()));
> if (Start.first != End.first) {
> // Start and end are in different files.
> return std::string();
> }
> if (End.second < Start.second) {
> // Shuffling text with macros may cause this.
> return std::string();
> }
> return std::string(Text, End.second - Start.second);
> }
>
> class ColIsEmptyHandler: public MatchFinder::MatchCallback {
> public:
> ColIsEmptyHandler(Replacements *Replace): Replace(Replace) {};
> virtual void run(const MatchFinder::MatchResult &Result) {
> if (const CXXMemberCallExpr *callExpr =
> Result.Nodes.getNodeAs<clang::CXXMemberCallExpr>("Col::IsEmptyExpr")) {
> const std::string text = getText(*(Result.SourceManager),
> *callExpr);
> Replacement Rep(*(Result.SourceManager),
> CharSourceRange::getTokenRange(SourceRange(callExpr->getCallee()->getExprLoc())),
> "IsEmpty");
> Replace->insert(Rep);
> }
> }
> private:
> Replacements *Replace;
> };
>
> class ColIsEmptyInClassHandler: public MatchFinder::MatchCallback {
> public:
> ColIsEmptyInClassHandler(Replacements *Replace): Replace(Replace) {};
> virtual void run(const MatchFinder::MatchResult &Result) {
> if (const CXXMethodDecl *decl =
> Result.Nodes.getNodeAs<clang::CXXMethodDecl>("Col::IsEmptyInClass")) {
> const std::string text = getText(*(Result.SourceManager), *decl);
> Replacement Rep(*(Result.SourceManager),
> CharSourceRange::getTokenRange(SourceRange(decl->getNameInfo().getLoc())),
> "IsEmpty");
> Replace->insert(Rep);
> }
> }
> private:
> Replacements *Replace;
> };
>
> int main(int argc, const char **argv) {
> llvm::InitializeAllTargets();
> llvm::InitializeAllTargetMCs();
> llvm::InitializeAllAsmPrinters();
> llvm::InitializeAllAsmParsers();
> CommonOptionsParser op(argc, argv, ToolingSampleCategory);
> RefactoringTool Tool(op.getCompilations(), op.getSourcePathList());
> // Set up AST matcher callbacks.
> ColIsEmptyHandler HandlerForColIsEmpty(&Tool.getReplacements());
> ColIsEmptyInClassHandler
> HandlerForColIsEmptyInClass(&Tool.getReplacements());
> MatchFinder Finder;
> Finder.addMatcher(memberCallExpr(hasDeclaration(methodDecl(
> hasName("Empty"),
> ofClass(isSameOrDerivedFrom(hasName("Col")))))).bind("Col::IsEmptyExpr"),
> &HandlerForColIsEmpty);
> Finder.addMatcher(methodDecl(hasName("Empty"),
> ofClass(isSameOrDerivedFrom(hasName("Col")))).bind("Col::IsEmptyInClass"),
> &HandlerForColIsEmptyInClass);
> // Run the tool and collect a list of replacements.
> if (int Result =
> Tool.runAndSave(newFrontendActionFactory(&Finder).get())) {
> return Result;
> }
> llvm::outs() << "Replacements collected by the tool:\n";
> for (auto &r : Tool.getReplacements()) {
> llvm::outs() << r.toString() << "\n";
> }
> return 0;
> }
>
> On Thu, Jul 16, 2015 at 11:11 AM, Manuel Klimek <klimek at google.com> wrote:
>
>> Can you post the code for the matcher?
>>
>> On Thu, Jul 16, 2015 at 11:02 AM Han Wang <wanghan02 at gmail.com> wrote:
>>
>>> Hi,
>>>
>>> I'm using clang AST matcher tool on MAC to analyse complex files with
>>> many many headers included. It turns out that it takes more than 10 times
>>> longer than just compile the same file with clang. Is it normal or am I
>>> doing something wrong? Thanks!
>>>
>>> Best regards,
>>> Han
>>> _______________________________________________
>>> cfe-dev mailing list
>>> cfe-dev at cs.uiuc.edu
>>> http://lists.cs.uiuc.edu/mailman/listinfo/cfe-dev
>>>
>>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-dev/attachments/20150716/945949b9/attachment.html>
More information about the cfe-dev
mailing list