diff options
author | Luboš Luňák <l.lunak@suse.cz> | 2012-10-15 15:36:25 +0200 |
---|---|---|
committer | Luboš Luňák <l.lunak@suse.cz> | 2012-10-15 15:40:33 +0200 |
commit | 0349c738da5970d9f0fc10d7cf4d7b766ce10e13 (patch) | |
tree | 572fa7304614ae5cac51938d45823114655e145e | |
parent | 41d6a0ea2d2d3c8daa758771bf956036d84cbe1a (diff) |
support for compiler rewriters
Change-Id: I12e98ac9fc49ef2007914324006a396d183b778c
-rw-r--r-- | compilerplugins/Makefile-clang.mk | 12 | ||||
-rw-r--r-- | compilerplugins/README | 20 | ||||
-rw-r--r-- | compilerplugins/clang/bodynotinblock.cxx | 2 | ||||
-rw-r--r-- | compilerplugins/clang/bodynotinblock.hxx | 2 | ||||
-rw-r--r-- | compilerplugins/clang/lclstaticfix.cxx | 58 | ||||
-rw-r--r-- | compilerplugins/clang/lclstaticfix.hxx | 34 | ||||
-rw-r--r-- | compilerplugins/clang/plugin.cxx (renamed from compilerplugins/clang/compileplugin.cxx) | 61 | ||||
-rw-r--r-- | compilerplugins/clang/plugin.hxx (renamed from compilerplugins/clang/compileplugin.hxx) | 14 | ||||
-rw-r--r-- | compilerplugins/clang/sallogareas.cxx | 2 | ||||
-rw-r--r-- | compilerplugins/clang/sallogareas.hxx | 2 | ||||
-rw-r--r-- | compilerplugins/clang/unusedvariablecheck.cxx | 2 | ||||
-rw-r--r-- | compilerplugins/clang/unusedvariablecheck.hxx | 2 | ||||
-rw-r--r-- | solenv/gbuild/LinkTarget.mk | 25 | ||||
-rw-r--r-- | solenv/gbuild/platform/com_GCC_class.mk | 32 | ||||
-rw-r--r-- | solenv/gbuild/platform/com_GCC_defs.mk | 6 |
15 files changed, 250 insertions, 24 deletions
diff --git a/compilerplugins/Makefile-clang.mk b/compilerplugins/Makefile-clang.mk index f9bec4147084..f18390668983 100644 --- a/compilerplugins/Makefile-clang.mk +++ b/compilerplugins/Makefile-clang.mk @@ -9,8 +9,10 @@ # Make sure variables in this Makefile do not conflict with other variables (e.g. from gbuild). # The list of source files. -CLANGSRC=compileplugin.cxx \ +CLANGSRC= \ + plugin.cxx \ bodynotinblock.cxx \ + lclstaticfix.cxx \ sallogareas.cxx \ unusedvariablecheck.cxx \ @@ -40,7 +42,7 @@ CLANGINDIR=$(SRCDIR)/compilerplugins/clang # plugin will cause cache misses with ccache. CLANGOUTDIR=$(SRCDIR)/compilerplugins/obj -compilerplugins: $(CLANGOUTDIR) $(CLANGOUTDIR)/compileplugin.so +compilerplugins: $(CLANGOUTDIR) $(CLANGOUTDIR)/plugin.so compilerplugins-clean: rm -rf $(CLANGOUTDIR) @@ -57,13 +59,13 @@ $(3): $(2) $(SRCDIR)/compilerplugins/Makefile-clang.mk $(CLANGOUTDIR)/clang-time -include $(CLANGOUTDIR)/$(1).d -$(CLANGOUTDIR)/compileplugin.so: $(3) -$(CLANGOUTDIR)/compileplugin.so: CLANGOBJS += $(3) +$(CLANGOUTDIR)/plugin.so: $(3) +$(CLANGOUTDIR)/plugin.so: CLANGOBJS += $(3) endef $(foreach src, $(CLANGSRC), $(eval $(call clangbuildsrc,$(src),$(CLANGINDIR)/$(src),$(CLANGOUTDIR)/$(src:.cxx=.o)))) -$(CLANGOUTDIR)/compileplugin.so: $(CLANGOBJS) +$(CLANGOUTDIR)/plugin.so: $(CLANGOBJS) @echo [build LNK] $(subst $(SRCDIR)/,,$@) $(CXX) -shared $(CLANGOBJS) -o $@ diff --git a/compilerplugins/README b/compilerplugins/README index 2344efbf0f76..1261a34b1487 100644 --- a/compilerplugins/README +++ b/compilerplugins/README @@ -1,5 +1,6 @@ Compiler plugins. + == Overview == This directory contains code for compiler plugins. These are used to perform @@ -8,6 +9,7 @@ also to perform mass code refactoring. Currently only the Clang compiler is supported (http://clang.llvm.org). + == Usage == Compiler plugins are enabled automatically by --enable-dbgutil if Clang headers @@ -16,11 +18,17 @@ are found or explicitly using --enable-compiler-plugins. == Functionality == -=== Compile plugin === +There are two kinds of modules: +- compile checks - these are run during normal compilation +- rewriters - these must be run manually and modify source files + -The compile plugin is used during normal compilation to perform additional checks. +=== Compile checks === + +Used during normal compilation to perform additional checks. All warnings and errors are marked '[loplugin]' in the message. + ==== Unused variable check ==== - unused parameter 'foo' [loplugin] @@ -28,6 +36,7 @@ All warnings and errors are marked '[loplugin]' in the message. Additional check for unused variables. + ==== Body of if/while/for not in {} ==== - statement aligned as second statement in if/while/for body but not in a statement block [loplugin] @@ -40,6 +49,7 @@ Warn about the following construct: Here either both statements should be inside {} or the second statement in indented wrong. + ==== Sal log areas ==== - unknown log area 'foo' (check or extend sal/inc/sal/log-areas.dox) [loplugin] @@ -49,6 +59,12 @@ report if the area is not listed there. The fix is either use a proper area or a if appropriate. +=== Rewriters === + +Rewriters analyse and possibly modify given source files. +Usage: make COMPILER_PLUGIN_TOOL=<rewriter_name> +Modifications will be written to files <source_file>.new . + == Code documentation / howtos == TBD diff --git a/compilerplugins/clang/bodynotinblock.cxx b/compilerplugins/clang/bodynotinblock.cxx index f13eb9392357..b6572bfc8a7a 100644 --- a/compilerplugins/clang/bodynotinblock.cxx +++ b/compilerplugins/clang/bodynotinblock.cxx @@ -16,6 +16,8 @@ namespace loplugin { /* +This is a compile check. + Check for two statements that are both indented to look like a body of if/while/for but are not inside a compound statement and thus the second one is unrelated. */ diff --git a/compilerplugins/clang/bodynotinblock.hxx b/compilerplugins/clang/bodynotinblock.hxx index 0d3425213a30..304bbf0a0480 100644 --- a/compilerplugins/clang/bodynotinblock.hxx +++ b/compilerplugins/clang/bodynotinblock.hxx @@ -11,7 +11,7 @@ #ifndef BODYNOTINBLOCK_H #define BODYNOTINBLOCK_H -#include "compileplugin.hxx" +#include "plugin.hxx" namespace loplugin { diff --git a/compilerplugins/clang/lclstaticfix.cxx b/compilerplugins/clang/lclstaticfix.cxx new file mode 100644 index 000000000000..c6b61363e134 --- /dev/null +++ b/compilerplugins/clang/lclstaticfix.cxx @@ -0,0 +1,58 @@ +/* + * This file is part of the LibreOffice project. + * + * Based on LLVM/Clang. + * + * This file is distributed under the University of Illinois Open Source + * License. See LICENSE.TXT for details. + * + */ + +#include "lclstaticfix.hxx" + +#include <clang/Basic/SourceManager.h> + +/* +This is a rewriter. + +Check all lcl_ functions and prepend static if needed. +*/ + +namespace loplugin +{ + +LclStaticFix::LclStaticFix( ASTContext& context, Rewriter& rewriter ) + : Plugin( context ), rewriter( rewriter ) + { + } + +void LclStaticFix::run() + { + TraverseDecl( context.getTranslationUnitDecl()); + } + +bool LclStaticFix::VisitFunctionDecl( FunctionDecl* declaration ) + { + // TODO also LO header files? or a subdir? + // Only the .cxx file can be normally edited ... ? + if( !context.getSourceManager().isFromMainFile( declaration->getLocStart())) + return true; + if( declaration->isCXXClassMember()) + return true; + if( declaration->getStorageClass() == SC_Static ) + return true; + string name = declaration->getQualifiedNameAsString(); + if( name.find( "::" ) != string::npos ) + return true; + if( name.compare( 0, 4, "lcl_" ) != 0 ) + return true; + if( rewriter.InsertText( declaration->getLocStart(), "static " )) + { // the logic is backwards, true here meant it failed, so report + report( DiagnosticsEngine::Warning, + "cannot fix lcl_ function (result of macro expansion?) [loplugin]", + declaration->getLocStart()); + } + return true; + } + +} // namespace diff --git a/compilerplugins/clang/lclstaticfix.hxx b/compilerplugins/clang/lclstaticfix.hxx new file mode 100644 index 000000000000..be89b4622620 --- /dev/null +++ b/compilerplugins/clang/lclstaticfix.hxx @@ -0,0 +1,34 @@ +/* + * This file is part of the LibreOffice project. + * + * Based on LLVM/Clang. + * + * This file is distributed under the University of Illinois Open Source + * License. See LICENSE.TXT for details. + * + */ + +#ifndef LCLSTATICFIX_H +#define LCLSTATICFIX_H + +#include "plugin.hxx" + +namespace loplugin +{ + +class LclStaticFix + : public RecursiveASTVisitor< LclStaticFix > + , public Plugin + { + public: + explicit LclStaticFix( ASTContext& context, Rewriter& rewriter ); + void run(); + bool VisitFunctionDecl( FunctionDecl* declaration ); + private: + Rewriter& rewriter; + }; + +} // namespace + +#endif // POSTFIXINCREMENTFIX_H + diff --git a/compilerplugins/clang/compileplugin.cxx b/compilerplugins/clang/plugin.cxx index 0bb378a73d95..115193c14137 100644 --- a/compilerplugins/clang/compileplugin.cxx +++ b/compilerplugins/clang/plugin.cxx @@ -8,16 +8,18 @@ * */ -#include "compileplugin.hxx" +#include "plugin.hxx" #include <clang/AST/ASTConsumer.h> #include <clang/AST/ASTContext.h> +#include <clang/Basic/FileManager.h> #include <clang/Frontend/CompilerInstance.h> #include <clang/Frontend/FrontendAction.h> #include <clang/Frontend/FrontendPluginRegistry.h> #include <clang/Rewrite/Rewriter.h> #include "bodynotinblock.hxx" +#include "lclstaticfix.hxx" #include "sallogareas.hxx" #include "unusedvariablecheck.hxx" @@ -57,9 +59,11 @@ class PluginHandler : public ASTConsumer { public: - explicit PluginHandler( ASTContext& context ) + explicit PluginHandler( ASTContext& context, const vector< string >& args ) : rewriter( context.getSourceManager(), context.getLangOpts()) + , args( args ) , bodyNotInBlock( context ) + , lclStaticFix( context, rewriter ) , salLogAreas( context ) , unusedVariableCheck( context ) { @@ -68,17 +72,49 @@ class PluginHandler { if( context.getDiagnostics().hasErrorOccurred()) return; - bodyNotInBlock.run(); - salLogAreas.run(); - unusedVariableCheck.run(); - // TODO also LO header files? or a subdir? - if( const RewriteBuffer* buf = rewriter.getRewriteBufferFor( context.getSourceManager().getMainFileID())) - buf->write( llvm::outs()); - // TODO else write out the original file? + if( isArg( "lclstaticfix" )) + lclStaticFix.run(); + else if( args.empty()) + { + bodyNotInBlock.run(); + salLogAreas.run(); + unusedVariableCheck.run(); + } + else + { + DiagnosticsEngine& diag = context.getDiagnostics(); + diag.Report( diag.getCustomDiagID( DiagnosticsEngine::Fatal, + "unknown plugin tool %0 [loplugin]" )) << args.front(); + } + for( Rewriter::buffer_iterator it = rewriter.buffer_begin(); + it != rewriter.buffer_end(); + ++it ) + { + const FileEntry* e = context.getSourceManager().getFileEntryForID( it->first ); + string filename = std::string( e->getName()) + ".new"; + string error; + // TODO If there will be actually plugins also modifying headers, + // race conditions should be avoided here. + raw_fd_ostream ostream( filename.c_str(), error ); + DiagnosticsEngine& diag = context.getDiagnostics(); + if( !error.empty()) + diag.Report( diag.getCustomDiagID( DiagnosticsEngine::Error, + "cannot write modified source to %0 (%1) [loplugin]" )) << filename << error; + else + diag.Report( diag.getCustomDiagID( DiagnosticsEngine::Note, + "modified source %0 [loplugin]" )) << filename; + it->second.write( ostream ); + } } private: + bool isArg( const char* arg ) const + { + return find( args.begin(), args.end(), arg ) != args.end(); + } Rewriter rewriter; + vector< string > args; BodyNotInBlock bodyNotInBlock; + LclStaticFix lclStaticFix; SalLogAreas salLogAreas; UnusedVariableCheck unusedVariableCheck; }; @@ -92,12 +128,15 @@ class LibreOfficeAction public: virtual ASTConsumer* CreateASTConsumer( CompilerInstance& Compiler, StringRef InFile ) { - return new PluginHandler( Compiler.getASTContext()); + return new PluginHandler( Compiler.getASTContext(), _args ); } - virtual bool ParseArgs( const CompilerInstance& CI, const std::vector< std::string >& args ) + virtual bool ParseArgs( const CompilerInstance& CI, const vector< string >& args ) { + _args = args; return true; } + private: + vector< string > _args; }; } // namespace diff --git a/compilerplugins/clang/compileplugin.hxx b/compilerplugins/clang/plugin.hxx index a413501fea95..6d273eda3c3e 100644 --- a/compilerplugins/clang/compileplugin.hxx +++ b/compilerplugins/clang/plugin.hxx @@ -8,10 +8,11 @@ * */ -#ifndef COMPILEPLUGIN_H -#define COMPILEPLUGIN_H +#ifndef PLUGIN_H +#define PLUGIN_H #include <clang/AST/RecursiveASTVisitor.h> +#include <clang/Rewrite/Rewriter.h> using namespace clang; using namespace llvm; @@ -32,6 +33,15 @@ class Plugin ASTContext& context; }; +class RewritePlugin + : public Plugin + { + public: + explicit RewritePlugin( ASTContext& context, Rewriter& rewriter ); + protected: + Rewriter& rewriter; + }; + inline bool Plugin::ignoreLocation( const Decl* decl ) { diff --git a/compilerplugins/clang/sallogareas.cxx b/compilerplugins/clang/sallogareas.cxx index f1a524ca5164..1dd99b9b727a 100644 --- a/compilerplugins/clang/sallogareas.cxx +++ b/compilerplugins/clang/sallogareas.cxx @@ -18,6 +18,8 @@ namespace loplugin { /* +This is a compile check. + Check that areas used in SAL_LOG/SAL_WARN are listed in sal/inc/sal/log-areas.dox . */ diff --git a/compilerplugins/clang/sallogareas.hxx b/compilerplugins/clang/sallogareas.hxx index f17b8aa1ace4..72f0e756d633 100644 --- a/compilerplugins/clang/sallogareas.hxx +++ b/compilerplugins/clang/sallogareas.hxx @@ -13,7 +13,7 @@ #include <set> -#include "compileplugin.hxx" +#include "plugin.hxx" namespace loplugin { diff --git a/compilerplugins/clang/unusedvariablecheck.cxx b/compilerplugins/clang/unusedvariablecheck.cxx index 340cd9ef863b..7e3bb53c5ba4 100644 --- a/compilerplugins/clang/unusedvariablecheck.cxx +++ b/compilerplugins/clang/unusedvariablecheck.cxx @@ -16,6 +16,8 @@ namespace loplugin { /* +This is a compile check. + Check for unused classes where the compiler cannot decide (e.g. because of non-trivial or extern ctors) if a variable is unused if only its ctor/dtor are called and nothing else. For example std::vector is a class where diff --git a/compilerplugins/clang/unusedvariablecheck.hxx b/compilerplugins/clang/unusedvariablecheck.hxx index 3099eec39522..7bf1cdd15ddd 100644 --- a/compilerplugins/clang/unusedvariablecheck.hxx +++ b/compilerplugins/clang/unusedvariablecheck.hxx @@ -11,7 +11,7 @@ #ifndef UNUSEDVARIABLECHECK_H #define UNUSEDVARIABLECHECK_H -#include "compileplugin.hxx" +#include "plugin.hxx" namespace loplugin { diff --git a/solenv/gbuild/LinkTarget.mk b/solenv/gbuild/LinkTarget.mk index 617fc562bb2e..00c218697c11 100644 --- a/solenv/gbuild/LinkTarget.mk +++ b/solenv/gbuild/LinkTarget.mk @@ -114,6 +114,9 @@ gb_Object__command_dep = \ $(call gb_Output_error,gb_Object__command_dep is only for gb_FULLDEPS) endif +# This one only exists to force .c/.cxx "rebuilds" when running a compiler tool. +.PHONY: force_compiler_tool_run +force_compiler_tool_run: # CObject class @@ -121,8 +124,13 @@ gb_CObject_get_source = $(1)/$(2).c # defined by platform # gb_CObject__command +ifneq ($(COMPILER_PLUGIN_TOOL),) +$(call gb_CObject_get_target,%) : $(call gb_CObject_get_source,$(SRCDIR),%) force_compiler_tool_run + $(call gb_CObject__tool_command,$*,$<) +else $(call gb_CObject_get_target,%) : $(call gb_CObject_get_source,$(SRCDIR),%) $(call gb_CObject__command,$@,$*,$<,$(call gb_CObject_get_dep_target,$*)) +endif ifeq ($(gb_FULLDEPS),$(true)) $(call gb_CObject_get_dep_target,%) : @@ -138,8 +146,13 @@ gb_CxxObject_get_source = $(1)/$(2).cxx # defined by platform # gb_CxxObject__command +ifneq ($(COMPILER_PLUGIN_TOOL),) +$(call gb_CxxObject_get_target,%) : $(call gb_CxxObject_get_source,$(SRCDIR),%) force_compiler_tool_run + $(call gb_CxxObject__tool_command,$*,$<) +else $(call gb_CxxObject_get_target,%) : $(call gb_CxxObject_get_source,$(SRCDIR),%) $(call gb_CxxObject__command,$@,$*,$<,$(call gb_CxxObject_get_dep_target,$*)) +endif ifeq ($(gb_FULLDEPS),$(true)) $(call gb_CxxObject_get_dep_target,%) : @@ -252,6 +265,11 @@ gb_ObjCxxObject_get_source = $(1)/$(2).mm # defined by platform # gb_ObjCxxObject__command +ifneq ($(COMPILER_PLUGIN_TOOL),) +$(call gb_ObjCxxObject_get_target,%) : $(call gb_ObjCxxObject_get_source,$(SRCDIR),%) force_compiler_tool_run + $(call gb_ObjCxxObject__tool_command,$*,$<) +else + $(call gb_ObjCxxObject_get_target,%) : $(call gb_ObjCxxObject_get_source,$(SRCDIR),%) $(call gb_ObjCxxObject__command,$@,$*,$<,$(call gb_ObjCxxObject_get_dep_target,$*)) @@ -261,6 +279,7 @@ $(call gb_ObjCxxObject_get_dep_target,%) : $(call gb_Object__command_dep,$@,$(call gb_ObjCxxObject_get_target,$*))) endif +endif # ObjCObject class @@ -270,6 +289,11 @@ gb_ObjCObject_get_source = $(1)/$(2).m # defined by platform # gb_ObjCObject__command +ifneq ($(COMPILER_PLUGIN_TOOL),) +$(call gb_ObjCObject_get_target,%) : $(call gb_ObjCObject_get_source,$(SRCDIR),%) force_compiler_tool_run + $(call gb_ObjCObject__tool_command,$*,$<) +else + $(call gb_ObjCObject_get_target,%) : $(call gb_ObjCObject_get_source,$(SRCDIR),%) $(call gb_ObjCObject__command,$@,$*,$<,$(call gb_ObjCObject_get_dep_target,$*)) @@ -279,6 +303,7 @@ $(call gb_ObjCObject_get_dep_target,%) : $(call gb_Object__command_dep,$@,$(call gb_ObjCObject_get_target,$*))) endif +endif # AsmObject class diff --git a/solenv/gbuild/platform/com_GCC_class.mk b/solenv/gbuild/platform/com_GCC_class.mk index 761a4050e3cb..1a88a36c42f1 100644 --- a/solenv/gbuild/platform/com_GCC_class.mk +++ b/solenv/gbuild/platform/com_GCC_class.mk @@ -72,6 +72,22 @@ $(call gb_Helper_abbreviate_dirs,\ ) endef +# Used to run a compiler plugin tool. +# $(call gb_CObject__tool_command,relative-source,source) +define gb_CObject__tool_command +$(call gb_Output_announce,$(1).c,$(true),C ,3) +$(call gb_Helper_abbreviate_dirs,\ + ICECC=no \ + $(gb_CC) \ + $(DEFS) \ + $(T_CFLAGS) \ + -c $(2) \ + -I$(dir $(2)) \ + $(INCLUDE) \ + $(gb_COMPILER_PLUGINS) \ + ) +endef + # CxxObject class # $(call gb_CxxObject__command,object,relative-source,source,dep-file) @@ -96,6 +112,22 @@ $(call gb_Helper_abbreviate_dirs,\ ) endef +# Used to run a compiler plugin tool. +# $(call gb_CxxObject__tool_command,relative-source,source) +define gb_CxxObject__tool_command +$(call gb_Output_announce,$(1).cxx,$(true),CXX,3) +$(call gb_Helper_abbreviate_dirs,\ + ICECC=no \ + $(gb_CXX) \ + $(DEFS) \ + $(T_CXXFLAGS) \ + -c $(2) \ + -I$(dir $(2)) \ + $(INCLUDE_STL) $(INCLUDE) \ + $(gb_COMPILER_PLUGINS) \ + ) +endef + define gb_SrsPartTarget__command_dep $(call gb_Helper_abbreviate_dirs,\ mkdir -p $(dir $(call gb_SrsPartTarget_get_dep_target,$(1))) && cd $(SRCDIR) && \ diff --git a/solenv/gbuild/platform/com_GCC_defs.mk b/solenv/gbuild/platform/com_GCC_defs.mk index fd93af253bfc..a3d26722ef57 100644 --- a/solenv/gbuild/platform/com_GCC_defs.mk +++ b/solenv/gbuild/platform/com_GCC_defs.mk @@ -154,7 +154,11 @@ gb_LinkTarget_INCLUDE := $(filter-out %/stl, $(subst -I. , ,$(SOLARINC))) gb_LinkTarget_INCLUDE_STL := $(filter %/stl, $(subst -I. , ,$(SOLARINC))) ifeq ($(COM_GCC_IS_CLANG),TRUE) -gb_COMPILER_PLUGINS :=-Xclang -load -Xclang $(SRCDIR)/compilerplugins/obj/compileplugin.so -Xclang -add-plugin -Xclang loplugin +ifeq ($(COMPILER_PLUGIN_TOOL),) +gb_COMPILER_PLUGINS := -Xclang -load -Xclang $(SRCDIR)/compilerplugins/obj/plugin.so -Xclang -add-plugin -Xclang loplugin +else +gb_COMPILER_PLUGINS := -Xclang -load -Xclang $(SRCDIR)/compilerplugins/obj/plugin.so -Xclang -plugin -Xclang loplugin -Xclang -plugin-arg-loplugin -Xclang $(COMPILER_PLUGIN_TOOL) +endif gb_COMPILER_PLUGINS_SETUP := ICECC_EXTRAFILES=$(SRCDIR)/sal/inc/sal/log-areas.dox else gb_COMPILER_PLUGINS := |