From 6029589032a85cf800b1868026c76268561b7834 Mon Sep 17 00:00:00 2001 From: bloodstalker Date: Fri, 27 Mar 2020 20:35:18 +0430 Subject: you now get the option of replacing the cgrep diagconsumer with the normal one provided by clang. also the cgrep diagconsumer now prints out errors and only leaves out warnings and fixits. README update. man update. added llvm11 to travis. --- .travis.yml | 18 ++++++++++++ README.md | 76 +++++++++++++++++++++++++++++++++++++++------------ cgrep.cpp | 43 ++++++++++++++++++++--------- cgrep.roff | 6 ++++ compile_commands.json | 4 +-- pch.hpp | 1 + 6 files changed, 116 insertions(+), 32 deletions(-) diff --git a/.travis.yml b/.travis.yml index 609322f..be78ce6 100644 --- a/.travis.yml +++ b/.travis.yml @@ -134,3 +134,21 @@ matrix: - make CXX=clang-10 LLVM_CONF=llvm-config-10 after_success: bash run.sh + - dist: bionic + name: llvm11 + sudo: required + language: cpp + before_script: + - sudo add-apt-repository ppa:ubuntu-toolchain-r/test -y + - sudo apt-get update -y + - sudo apt-get install libstdc++-7-dev -y + - sudo wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | sudo apt-key add - + - sudo add-apt-repository "deb http://apt.llvm.org/bionic/ llvm-toolchain-bionic-10 main" + - sudo apt-get update + - sudo apt-get install clang-11 llvm-11-dev libclang-common-11-dev libclang-11-dev libboost-system-dev libboost-filesystem-dev -y + - git submodule init + - git submodule update + script: + - make CXX=clang-11 LLVM_CONF=llvm-config-11 + after_success: + bash run.sh diff --git a/README.md b/README.md index 7907da6..bdeb0f2 100644 --- a/README.md +++ b/README.md @@ -7,10 +7,54 @@ # cgrep -`grep` for C-family source files. +cgrep is `grep` for C-family source files. + +You can write something like this: + +```bash +cgrep --regex [a-z]* --func -A 1 -B 1 myawesomecode.cpp +``` + +and it will match your regex against all function declarations, and will output the result, plus one line before and after the context. + +`cgrep` is implemented using Clang's libtooling libraries. + +### Features + +* It's basically Clang regexing it's way through your C-family source-code. You have all the context you can ever need. +* Can output whether to print the declaration of a match even if the match itself is not a declaration along with the matched result. +* Can output matches in a script-friendly format which could be used in turn by a secondary script. + +### Will cgrep try to implement all of the grep switches? +The answer is no. The main distinction is that `cgrep` is only meant to work on C-family source files not text files. Most of `grep`'s switches don't apply to the usecase or provide almost no benefits at all.
+That being said, I might have missd something so you can always make suggestions in the form of a new issue. + +### Will cgrep support a new switch that matches X? +If it makes sense sure, but I want to be careful with what cgrep implements. If everything gets implemented, that is, cgrep implements every possible switch(well, a subset of "all"), we end up with an inferior version of `clang-query` that would be too slow to be of any use to anyone. So please keep in mind that I will have to draw the line somewhere. ## Building +You can get the source files from the [release](https://github.com/bloodstalker/cgrep/releases) page or a release branch usually named `rcx`.
+The Release Candidate branches are the release branches. Master is the dev branch.
+Currently the master branch requires `libloost-filesystem`, which will most probably change in the future.
+ +### Fedora +`sudo dnf install clang-devel llvm-devel llvm-static` + +### Ubuntu +`sudo apt install clang-X llvm-X-dev libclang-common-X-dev libclang-X-dev`
+Replace X with the LLVM version of your choice. + +### Debian +`sudo apt install clang-X llvm-X-dev libclang-common-X-dev libclang-X-dev`
+Replace X with the LLVM version of your choice. + +### Arch +You can get cgrep from AUR. Thanks to [schra](https://github.com/schra). + +### Cygwin +You will need `libclang-devel, libllvm-devel, clang, libiconv-devel`. + Assuming you have the llvm/clang libraries (the build file will read your llvm options using `llvm-config` so make sure it's in path), just run: ```bash @@ -23,12 +67,11 @@ make After the build is finished you can choose to run `make install`. It will simply symlink cgrep into `/usr/local/bin`. -If you have installed LLVM but don't have `llvm-config`, you are missing the dev package for LLVM. -`cgrep` supports LLVM 5,6,7,8 and 9. For 10 the latest tested trunk version is: 374971. +If you have installed LLVM but don't have `llvm-config`, you are missing the dev package for LLVM.
+`cgrep` supports LLVM 5,6,7,8,9,10 and 11.
The makefile assumes clang is called `clang` and llvm-config is called `llvm-config`. On some distros, the names might not be the same. In those cases use `CXX` and `LLVM_CONF` to pass the values to the makefile like so: - ```bash -make CXX=clang-9.0 LLVM_CONF=llvm-config-9.0 +make CXX=clang-9 LLVM_CONF=llvm-config-9 ``` For windows builds, cygwin builds are supported. Get llvm and clang along with their sources and build like usual. If you run into problems while bulding on cygwin, you can take a look at the `appveyor.yml` file under the repository root. @@ -42,27 +85,29 @@ cgrep -A 1 -B 1 --func --declrefexpr --regex n[aA]m --nocolor --nodecl ./myaweso ``` In order for cgrep to work, you need to have a compilation database, tools like `cmake` can generate one for you.
-You can, by all means, run cgrep without a compilation databse but whether that works or not really depends on your source file. Can you build your source file with clang without passing it any options? +You can, by all means, run cgrep without a compilation database but whether that works or not really depends on your source file. Can you build your source file with clang without passing it any options? If the answer to that is yes, then you can just run cgrep without a compilation databse like so:
```bash cgrep -A 1 -B 1 --func --declrefexpr --regex n[aA]m --nocolor --nodecl ./myawesomecode.cpp -- ``` +the `--` at the end is an explicit way of saying that you will not be providing a compialtion database. Newer versions of clang will try to still go through with the compilation even if there is no compilaiton database found. Otherwise you need a compilation database.
Please do note that the regex will pass through both C++ and the regex engine, so if you would want to escape `\`, the regex you pass as the command line arg would be `\\\\` instead of the normal `\\`.
-If your build tool doesn't do that, you can just use [bear](https://github.com/rizsotto/Bear) or [scan-build](https://github.com/rizsotto/scan-build). -You can also skip the compilation database altogether passing cgrep `--` after the input file name which means you have chosen not to pass it anything. -You can pass the options by hand since cgrep is a Clang instance so it recognizes every option clang has. +If your build tool doesn't do that, you can just use [bear](https://github.com/rizsotto/Bear) or [scan-build](https://github.com/rizsotto/scan-build).
+You can also skip the compilation database altogether passing cgrep `--` after the input file name which means you have chosen not to pass it anything.
+You can pass the options by hand using `--extra-arg=` since cgrep is a clang instance so it recognizes every option clang has. +As a general rule, if you're not going to pass cgrep a compilation database, it's always better to explicitly let cgrep know using `--`. Not doing so can result in instances when cgrep behaves in a way that you might not expect it.
-cgrep uses ANSI escape sequences for colors so your terminal should support those. In case your terminal does not support ANSI escape sequences, you can silence those using the `--nocolor` option. +cgrep uses ANSI escape sequences for colors so your terminal should support those. In case your terminal does not support ANSI escape sequences or you don't want thos for any other reason, you can silence those using the `--nocolor` option. By default, cgrep will print out the declaration location for a match. In case you don't want those in the output, you can pass cgrep the `--nodecl` switch. -You can use `--extra-arg==--std=` to tell cgrep which C-family language the source file is supposed to be in. +You can use `--extra-arg=--std=` to tell cgrep which C-family language the source file is supposed to be in. ## Options -Here's an option list, though it might not be necessarily up-to-date. +Here's an option list, though it's usually not up-to-date.
For an up-to-date list, you can run `cgrep --help` or look at the man page. ```bash @@ -96,15 +141,12 @@ For an up-to-date list, you can run `cgrep --help` or look at the man page. `cgrep` is a clang tool, so it will accept all valid clang command line options. -## Example -You can run the coverage report, `make covrep`, to see some examples. Before running make sure to generate the compilation databases for `cgrep.cpp` and `./test/main.cpp`. The paths need to be right for your system. Please note that even though cgrep's source file is small, the actual code itself isn't. cgrep is clang. So cgrep will be relatively slow in the examples since its running on a Very big codebase. - ## Known Issues -`cgrep` will not print out warnings or errors related to the source code so please make sure that clang can successfully build your file before running cgrep on it. +`cgrep`, replaces the clang diagnosticConsumer with a simple one that only tells you there are erros during the compilation. You can get the normal clang output using the `--clangdiag` switch. The decision was made to declutter the output generated by cgrep. ## License -cgrep is licensed under GPL-3.0. +cgrep is licensed under GPL-3.0. Eveything else is licensed under it's own respective license. [![FOSSA Status](https://app.fossa.io/api/projects/git%2Bgithub.com%2Fbloodstalker%2Fcgrep.svg?type=large)](https://app.fossa.io/projects/git%2Bgithub.com%2Fbloodstalker%2Fcgrep?ref=badge_large) diff --git a/cgrep.cpp b/cgrep.cpp index 8ce5fe7..ed83c5d 100644 --- a/cgrep.cpp +++ b/cgrep.cpp @@ -7,7 +7,6 @@ * */ /***********************************************************************************************/ /*included modules*/ -#include "./cfe-extra/cfe_extra.h" #include "./pch.hpp" /***********************************************************************************************/ /*used namespaces*/ @@ -16,7 +15,6 @@ using namespace clang; using namespace clang::ast_matchers; using namespace clang::driver; using namespace clang::tooling; -// using namespace boost::filesystem; /***********************************************************************************************/ namespace { static llvm::cl::OptionCategory CGrepCat("cgrep options"); @@ -58,6 +56,9 @@ cl::opt CO_UNION("union", cl::desc("Match unions."), cl::init(false), cl::opt CO_MACRO("macro", cl::desc("Match macro definitions."), cl::init(false), cl::cat(CGrepCat), cl::Optional); // done +cl::opt CO_CLANGDIAG("clangdiag", cl::desc("use clang's diagnostic consumer instead of the one that cgrep provide."), + cl::init(false), cl::cat(CGrepCat), + cl::Optional); // done cl::opt CO_HEADER("header", cl::desc("Match headers in header inclusions."), cl::init(false), cl::cat(CGrepCat), @@ -776,12 +777,29 @@ private: /***********************************************************************************************/ /// @brief A Clang Diagnostic Consumer that does nothing since we don't want /// clang to print out diag info. -class BlankDiagConsumer : public clang::DiagnosticConsumer { +class CgrepDiagConsumer : public clang::DiagnosticConsumer { public: - BlankDiagConsumer() = default; - virtual ~BlankDiagConsumer() {} + CgrepDiagConsumer() = default; + virtual ~CgrepDiagConsumer() {} virtual void HandleDiagnostic(DiagnosticsEngine::Level DiagLevel, - const Diagnostic &Info) override {} + const Diagnostic &Info) override { + if ((clang::DiagnosticsEngine::Level::Error == DiagLevel) + || (clang::DiagnosticsEngine::Level::Fatal == DiagLevel)) { + SmallVector OutStr; + Info.FormatDiagnostic(OutStr); + std::cout << "Error:"; + for (auto &iter : OutStr) std::cout << iter; + ArrayRef SourceRanges = Info.getRanges(); + for (auto &iter : SourceRanges) { + if (Info.hasSourceManager()) { + std::cout << iter.getBegin().printToString(Info.getSourceManager()) << + ":" << iter.getEnd().printToString(Info.getSourceManager()) << "\n"; + } + } + ArrayRef FixItHints [[maybe_unused]] = Info.getFixItHints(); + std::cout << "\n"; + } + } }; /***********************************************************************************************/ class CgrepASTConsumer : public ASTConsumer { @@ -790,7 +808,7 @@ public: : HandlerForVar(R), HandlerForClass(R), HandlerForCalledFunc(R), HandlerForCXXMethod(R), HandlerForField(R), HandlerForStruct(R), HandlerForUnion(R), HandlerForNamedDecl(R), HandlerForDeclRefExpr(R), - HandlerForCallExpr(R), HandlerForCXXCallExpr(R), + HandlerForCallExpr(R), HandlerForCXXCallExpr(R), HandlerForRecordField(R) { if (CO_FUNCTION || CO_ALL) { Matcher.addMatcher(functionDecl().bind("funcdecl"), @@ -887,8 +905,10 @@ public: CI.getPreprocessor().addPPCallbacks( std::make_unique(&CI.getSourceManager(), &TheRewriter)); #endif - DiagnosticsEngine &DE = CI.getPreprocessor().getDiagnostics(); - DE.setClient(BDCProto, false); + if (!CO_CLANGDIAG) { + DiagnosticsEngine &DE = CI.getPreprocessor().getDiagnostics(); + DE.setClient(BDCProto, false); + } TheRewriter.setSourceMgr(CI.getSourceManager(), CI.getLangOpts()); #if __clang_major__ <= 9 return llvm::make_unique(TheRewriter); @@ -899,7 +919,7 @@ public: } private: - BlankDiagConsumer *BDCProto = new BlankDiagConsumer; + CgrepDiagConsumer *BDCProto = new CgrepDiagConsumer; Rewriter TheRewriter; }; /***********************************************************************************************/ @@ -908,9 +928,6 @@ int main(int argc, const char **argv) { CommonOptionsParser op(argc, argv, CGrepCat); ClangTool Tool(op.getCompilations(), op.getSourcePathList()); int ret = Tool.run(newFrontendActionFactory().get()); -#if 0 - listDirs(CO_RECURSIVE); -#endif return ret; } /***********************************************************************************************/ diff --git a/cgrep.roff b/cgrep.roff index f2793e7..908c344 100644 --- a/cgrep.roff +++ b/cgrep.roff @@ -119,6 +119,12 @@ Match member function declarations. \fB--cfield\fP Match C field declations. +.TP +\fB--clangdiag\fP +Enables the normal diagnostics and fixits that you are used to see from clang. +By defualt this option is set to false. cgrep will use its own dignosticConsumer +when this option is set to false. + .TP \fB--nameddecl\fP Matches all named declarations. diff --git a/compile_commands.json b/compile_commands.json index 9c2f5ec..b74aadf 100644 --- a/compile_commands.json +++ b/compile_commands.json @@ -1,7 +1,7 @@ [ { "command": "c++ -c -include-pch pch.hpp.gch -fpic -I/home/bloodstalker/extra/llvm-clang-4/llvm/include -I/home/bloodstalker/extra/llvm-clang-4/build/include -std=c++14 -fno-exceptions -D_GNU_SOURCE -D_DEBUG -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS -I/home/bloodstalker/extra/llvm-clang-4/llvm/tools/clang/include -I/home/bloodstalker/extra/llvm-clang-4/build/tools/clang/include -std=c++17 -fexceptions -o cgrep.o cgrep.cpp", - "directory": "/home/bloodstalker/devi/hell2/cgrep", - "file": "/home/bloodstalker/devi/hell2/cgrep/cgrep.cpp" + "directory": "/home/bloodstalker/extra/cgrep", + "file": "/home/bloodstalker/extra/cgrep/cgrep.cpp" } ] \ No newline at end of file diff --git a/pch.hpp b/pch.hpp index dcebacf..7f1c485 100644 --- a/pch.hpp +++ b/pch.hpp @@ -19,3 +19,4 @@ #include #include #include +#include "./cfe-extra/cfe_extra.h" -- cgit v1.2.3