Commit 74f5384f authored by Kevin Modzelewski's avatar Kevin Modzelewski

Create a simple clange-based linter

First job: check for cases where we call isSubclass() when it would
be faster to call Py*_Check

Probably overkill for this.  Pretty cool though that it found a
case that would have been impossible to spot textually, where there
was an implicit this-> member access.
parent f0efd51b
......@@ -1049,22 +1049,29 @@ update_section_ordering: pyston_release
# TESTING:
_plugins/clang_capi.so: plugins/clang_capi.cpp $(BUILD_SYSTEM_DEPS)
@# $(CXX) $< -o $@ -c -I/usr/lib/llvm-3.5/include -std=c++11 -D__STDC_CONSTANT_MACROS -D__STDC_LIMIT_MACROS
$(CXX) $< -o $@ -std=c++11 $(LLVM_CXXFLAGS) -I$(LLVM_SRC)/tools/clang/include -I$(LLVM_BUILD)/tools/clang/include -shared
plugins/clang_capi.o: plugins/clang_capi.cpp $(BUILD_SYSTEM_DEPS)
@# $(CXX) $< -o $@ -c -I/usr/lib/llvm-3.5/include -std=c++11 -D__STDC_CONSTANT_MACROS -D__STDC_LIMIT_MACROS
$(CXX) $< -o $@ -std=c++11 $(LLVM_CXXFLAGS) -O0 -I$(LLVM_SRC)/tools/clang/include -I$(LLVM_BUILD)/tools/clang/include -c
plugins/clang_capi: plugins/clang_capi.o $(BUILD_SYSTEM_DEPS)
@# $(CXX) $< -o $@ -c -I/usr/lib/llvm-3.5/include -std=c++11 -D__STDC_CONSTANT_MACROS -D__STDC_LIMIT_MACROS
$(CXX) $< -o $@ -L$(LLVM_BUILD)/Release/lib -lclangASTMatchers -lclangRewrite -lclangFrontend -lclangDriver -lclangTooling -lclangParse -lclangSema -lclangAnalysis -lclangAST -lclangEdit -lclangLex -lclangBasic -lclangSerialization $(shell $(LLVM_BUILD)/Release+Asserts/bin/llvm-config --ldflags --system-libs --libs all)
plugins/clang_capi.so: plugins/clang_capi.o $(BUILD_SYSTEM_DEPS)
@# $(CXX) $< -o $@ -c -I/usr/lib/llvm-3.5/include -std=c++11 -D__STDC_CONSTANT_MACROS -D__STDC_LIMIT_MACROS
$(CXX) $< -o $@ -shared
.PHONY: plugin_test
plugin_test: plugins/clang_capi.so
$(CLANG_CXX) -Xclang -load -Xclang plugins/clang_capi.so -Xclang -add-plugin -Xclang print-fns test/test.cpp -c -S -o -
plugins/clang_linter.o: plugins/clang_linter.cpp $(BUILD_SYSTEM_DEPS)
ninja -C $(CMAKE_DIR_DBG) llvm/bin/llvm-config clangASTMatchers clangTooling LLVMLTO LLVMDebugInfoPDB LLVMLineEditor LLVMInterpreter LLVMOrcJIT
$(CXX) $< -o $@ -std=c++11 $(shell $(LLVM_BIN_DBG)/llvm-config --cxxflags) -fno-rtti -O0 -I$(LLVM_SRC)/tools/clang/include -I$(LLVM_INC_DBG)/tools/clang/include -c
plugins/clang_linter.so: plugins/clang_linter.o
$(CXX) $< -o $@ -shared -lclangASTMatchers -lclangTooling $(shell $(LLVM_BIN_DBG)/llvm-config --ldflags)
# $(CXX) $< -o $@ -lclangASTMatchers -lclangRewrite -lclangFrontend -lclangDriver -lclangTooling -lclangParse -lclangSema -lclangAnalysis -lclangAST -lclangEdit -lclangLex -lclangBasic -lclangSerialization $(shell $(LLVM_BIN_DBG)/llvm-config --ldflags --system-libs --libs all)
plugins/clang_linter: plugins/clang_linter.o $(BUILD_SYSTEM_DEPS)
$(CXX) $< -o $@ -lclangASTMatchers -lclangRewrite -lclangFrontend -lclangDriver -lclangTooling -lclangParse -lclangSema -lclangAnalysis -lclangAST -lclangEdit -lclangLex -lclangBasic -lclangSerialization $(shell $(LLVM_BIN_DBG)/llvm-config --ldflags --system-libs --libs all)
.PHONY: tool_test
tool_test: plugins/clang_capi
plugins/clang_capi test/test.cpp --
tool_test: plugins/clang_linter.o
plugins/clang_linter test/test.cpp -- $(shell $(LLVM_BIN_DBG)/llvm-config --cxxflags) -I/usr/lib/llvm-3.5/include
.PHONY: superlint
superlint: plugins/clang_linter.so
for fn in $(MAIN_SRCS); do $(CLANG_CXX) -Xclang -load -Xclang plugins/clang_linter.so -Xclang -plugin -Xclang pyston-linter $$fn -c -Isrc/ -Ifrom_cpython/Include -Ibuild/Debug/from_cpython/Include $(shell $(LLVM_BIN_DBG)/llvm-config --cxxflags) -no-pedantic -Wno-unused-variable -DNVALGRIND -Wno-invalid-offsetof -Wno-mismatched-tags -Wno-unused-function -Wno-unused-private-field -Wno-sign-compare || break; done
.PHONY: lint_%
lint_%: %.cpp plugins/clang_linter.so
$(ECHO) Linting $<
$(VERB) $(CLANG_CXX) -Xclang -load -Xclang plugins/clang_linter.so -Xclang -plugin -Xclang pyston-linter src/runtime/float.cpp $< -c -Isrc/ -Ifrom_cpython/Include -Ibuild/Debug/from_cpython/Include $(shell $(LLVM_BIN_DBG)/llvm-config --cxxflags) $(COMMON_CXXFLAGS) -no-pedantic -Wno-unused-variable -DNVALGRIND -Wno-invalid-offsetof -Wno-mismatched-tags -Wno-unused-function -Wno-unused-private-field -Wno-sign-compare -DLLVMREV=$(LLVM_REVISION) -Ibuild_deps/lz4/lib -DBINARY_SUFFIX= -DBINARY_STRIPPED_SUFFIX=_stripped -Ibuild_deps/libpypa/src/ -Wno-covered-switch-default -Ibuild/Debug/libunwind/include -Wno-extern-c-compat -Wno-unused-local-typedef -Wno-inconsistent-missing-override
.PHONY: clang_lint
clang_lint: $(foreach FN,$(MAIN_SRCS),$(dir $(FN))lint_$(notdir $(FN:.cpp=)))
// Originally from https://github.com/eliben/llvm-clang-samples/blob/master/src_clang/tooling_sample.cpp with the following header. Modifications copyright Dropbox, Inc.
//
//------------------------------------------------------------------------------
// Tooling sample. Demonstrates:
//
// * How to write a simple source tool using libTooling.
// * How to use RecursiveASTVisitor to find interesting AST nodes.
// * How to use the Rewriter API to rewrite the source code.
//
// Eli Bendersky (eliben@gmail.com)
// This code is in the public domain
//------------------------------------------------------------------------------
#include <sstream>
#include <string>
#include "clang/AST/AST.h"
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/RecursiveASTVisitor.h"
#include "clang/ASTMatchers/ASTMatchers.h"
#include "clang/ASTMatchers/ASTMatchFinder.h"
#include "clang/Frontend/ASTConsumers.h"
#include "clang/Frontend/FrontendActions.h"
#include "clang/Frontend/FrontendPluginRegistry.h"
#include "clang/Frontend/CompilerInstance.h"
#include "clang/Tooling/CommonOptionsParser.h"
#include "clang/Tooling/Tooling.h"
#include "clang/Rewrite/Core/Rewriter.h"
#include "llvm/Support/raw_ostream.h"
using namespace llvm;
using namespace clang;
using namespace clang::driver;
using namespace clang::tooling;
using namespace clang::ast_matchers;
auto matcher = callExpr(
callee(functionDecl(hasName("pyston::isSubclass"))),
hasArgument(0, memberExpr(member(fieldDecl(hasName("cls"))))),
hasArgument(1, declRefExpr(to(namedDecl(matchesName("(int|long|list|tuple|string|unicode|dict|baseexc|type)_cls")))).bind("parent_cls"))
).bind("call");
MatchFinder Finder;
DiagnosticsEngine* diagnostics;
// Not sure why the build wants us to add this:
extern "C" void AnnotateHappensAfter(const char* file, int line, const volatile void *cv) {}
std::set<SourceLocation> reported;
class Replacer : public MatchFinder::MatchCallback {
public:
virtual void run (const MatchFinder::MatchResult &Result) {
const CallExpr* ME = Result.Nodes.getNodeAs<clang::CallExpr>("call");
//errs() << "matched!\n";
//ME->dump();
//Result.Nodes.getNodeAs<clang::DeclRefExpr>("parent_cls")->dump();
unsigned diag_id = diagnostics->getCustomDiagID(
DiagnosticsEngine::Error, "perf issue: use PyFoo_Check instead of isSubclass(obj->cls, foo_cls)");
auto source = ME->getSourceRange().getBegin();
if (!reported.count(source)) {
reported.insert(source);
diagnostics->Report(source, diag_id);
}
}
};
Replacer replacer;
class MyFrontendAction : public PluginASTAction {
public:
MyFrontendAction() {}
bool ParseArgs(const CompilerInstance &CI, const std::vector<std::string> &args) override {
diagnostics = &CI.getDiagnostics();
return true;
}
std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance& CI, StringRef file) override {
Finder.addMatcher(matcher, &replacer);
return Finder.newASTConsumer();
}
};
static FrontendPluginRegistry::Add<MyFrontendAction> X("pyston-linter", "run some Pyston-specific lint checks");
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment