fork(446) download
  1. //=== ===//
  2. //
  3. // The LLVM Compiler Infrastructure
  4. //
  5. // This file is distributed under the University of Illinois Open Source
  6. // License. See LICENSE.TXT for details.
  7. //
  8. //===----------------------------------------------------------------------===//
  9.  
  10. #include "clang/ASTMatchers/ASTMatchers.h"
  11. #include "clang/ASTMatchers/ASTMatchFinder.h"
  12. #include "clang/Basic/SourceManager.h"
  13. #include "clang/Frontend/FrontendActions.h"
  14. #include "clang/Lex/Lexer.h"
  15. #include "clang/Tooling/CompilationDatabase.h"
  16. #include "clang/Tooling/Refactoring.h"
  17. #include "clang/Tooling/Tooling.h"
  18. #include "llvm/ADT/OwningPtr.h"
  19. #include "llvm/ADT/Twine.h"
  20. #include "llvm/Support/CommandLine.h"
  21. #include "llvm/Support/MemoryBuffer.h"
  22. #include "llvm/Support/Path.h"
  23. #include "llvm/Support/raw_ostream.h"
  24. #include "llvm/Support/system_error.h"
  25.  
  26. #include <iostream>
  27.  
  28. using namespace std;
  29.  
  30. using namespace clang;
  31. using namespace clang::ast_matchers;
  32. using namespace llvm;
  33. using clang::tooling::newFrontendActionFactory;
  34. using clang::tooling::Replacement;
  35. using clang::tooling::CompilationDatabase;
  36.  
  37. // FIXME: Pull out helper methods in here into more fitting places.
  38.  
  39. // Returns the text that makes up 'node' in the source.
  40. // Returns an empty string if the text cannot be found.
  41. template <typename T>
  42. static std::string getText(const SourceManager &SourceManager, const T &Node)
  43. {
  44. SourceLocation StartSpellingLocatino = SourceManager.getSpellingLoc(Node.getLocStart());
  45. SourceLocation EndSpellingLocation = SourceManager.getSpellingLoc(Node.getLocEnd());
  46. if(!StartSpellingLocatino.isValid() || !EndSpellingLocation.isValid())
  47. {
  48. return std::string();
  49. }
  50. bool Invalid = true;
  51. const char *Text =
  52. SourceManager.getCharacterData(StartSpellingLocatino, &Invalid);
  53. if(Invalid)
  54. {
  55. return std::string();
  56. }
  57. std::pair<FileID, unsigned> Start = SourceManager.getDecomposedLoc(StartSpellingLocatino);
  58. std::pair<FileID, unsigned> End = SourceManager.getDecomposedLoc(Lexer::getLocForEndOfToken(
  59. EndSpellingLocation, 0, SourceManager, LangOptions()));
  60. if(Start.first != End.first)
  61. {
  62. // Start and end are in different files.
  63. return std::string();
  64. }
  65. if(End.second < Start.second)
  66. {
  67. // Shuffling text with macros may cause this.
  68. return std::string();
  69. }
  70. return std::string(Text, End.second - Start.second);
  71. }
  72.  
  73. namespace
  74. {
  75.  
  76. void printCallPredicates(const CallExpr *Call, const string &indent = " ")
  77. {
  78. string new_indent = indent + " ";
  79. cout << indent << "Call" << endl << indent << "(" << endl << new_indent;
  80. cout << "ArgumentCountIs(" << Call->getNumArgs() << ")";
  81. if(Call->getDirectCallee())
  82. {
  83. cout << ",Callee(Function(HasName(\"" << Call->getDirectCallee()->getQualifiedNameAsString() << "\")))";
  84. for(unsigned i = 0; i != Call->getNumArgs(); ++i)
  85. {
  86. if(const CallExpr *callExpr = dyn_cast<CallExpr>(Call->getArg(i)))
  87. {
  88. cout << ",HasArgument(" << i << "," << endl;
  89. printCallPredicates(callExpr, new_indent);
  90. cout << ")";
  91. }
  92. }
  93. }
  94. cout << endl << indent << ")";
  95. }
  96.  
  97. class PrintMatchers : public ast_matchers::MatchFinder::MatchCallback
  98. {
  99. public:
  100. virtual void run(const ast_matchers::MatchFinder::MatchResult &Result)
  101. {
  102. const CallExpr *Call = Result.Nodes.getStmtAs<CallExpr>("call");
  103. cout << "Code: " << getText(*Result.SourceManager, *Call) << endl << "Matcher:" << endl;
  104. printCallPredicates(Call);
  105. cout << endl << endl;
  106. }
  107. };
  108.  
  109.  
  110. class PrintCall : public ast_matchers::MatchFinder::MatchCallback
  111. {
  112. public:
  113. virtual void run(const ast_matchers::MatchFinder::MatchResult &Result)
  114. {
  115. const CallExpr *Call = Result.Nodes.getStmtAs<CallExpr>("call");
  116. cout << "--------> Matched Call:\t" << getText(*Result.SourceManager, *Call) << endl << endl;
  117. }
  118. };
  119.  
  120. } // end namespace
  121.  
  122. cl::opt<std::string> BuildPath(
  123. cl::Positional,
  124. cl::desc("<build-path>"));
  125.  
  126. cl::list<std::string> SourcePaths(
  127. cl::Positional,
  128. cl::desc("<source0> [... <sourceN>]"),
  129. cl::OneOrMore);
  130.  
  131. int main(int argc, char **argv)
  132. {
  133. cl::ParseCommandLineOptions(argc, argv);
  134. std::string ErrorMessage;
  135. llvm::OwningPtr<CompilationDatabase> Compilations(CompilationDatabase::loadFromDirectory(BuildPath, ErrorMessage));
  136. if(!Compilations)
  137. {
  138. llvm::report_fatal_error(ErrorMessage);
  139. }
  140. tooling::RefactoringTool Tool(*Compilations, SourcePaths);
  141. ast_matchers::MatchFinder Finder;
  142.  
  143. // Generate and print matchers for calls
  144. PrintMatchers print_matchers;
  145. Finder.addMatcher(Id("call", Call(True())), &print_matchers);
  146.  
  147. PrintCall matcher_stream_outputs;
  148. // Autogenerated matcher for: std::cout << 1.0 << "1" << std::endl;
  149. Finder.addMatcher(Id("call",
  150. Call
  151. (
  152. ArgumentCountIs(2),Callee(Function(HasName("std::basic_ostream<char, std::char_traits<char> >::operator<<"))),HasArgument(0,
  153. Call
  154. (
  155. ArgumentCountIs(2),Callee(Function(HasName("std::operator<<"))),HasArgument(0,
  156. Call
  157. (
  158. ArgumentCountIs(2),Callee(Function(HasName("std::basic_ostream<char, std::char_traits<char> >::operator<<")))
  159. ))
  160. ))
  161. )
  162. ), &matcher_stream_outputs);
  163.  
  164. PrintCall matcher_c_str;
  165. // Autogenerated matcher for: std::string("1").c_str();
  166. Finder.addMatcher(Id("call",
  167. Call
  168. (
  169. ArgumentCountIs(0),Callee(Function(HasName("std::basic_string<char, std::char_traits<char>, std::allocator<char> >::c_str")))
  170. )
  171. ), &matcher_c_str);
  172.  
  173. /*PrintCall callback;
  174.   Finder.addMatcher(
  175.   Id("call", Call(True())),
  176.   &callback);*/
  177. return Tool.run(newFrontendActionFactory(&Finder));
  178. }
  179.  
  180.  
Not running #stdin #stdout 0s 0KB
stdin
Standard input is empty
stdout
Standard output is empty