[Libreoffice-commits] .: 4 commits - compilerplugins/clang compilerplugins/Makefile-clang.mk config/config_clang.h.in configure.ac

Libreoffice Gerrit user logerrit at kemper.freedesktop.org
Fri Jan 4 06:28:23 PST 2013


 compilerplugins/Makefile-clang.mk                 |    1 
 compilerplugins/clang/lclstaticfix.cxx            |    4 
 compilerplugins/clang/plugin.cxx                  |  110 +++++++++++++++++++---
 compilerplugins/clang/plugin.hxx                  |   28 +++++
 compilerplugins/clang/postfixincrementfix.cxx     |    3 
 compilerplugins/clang/removeforwardstringdecl.cxx |   76 +++++++++++++++
 compilerplugins/clang/removeforwardstringdecl.hxx |   34 ++++++
 config/config_clang.h.in                          |    3 
 configure.ac                                      |    3 
 9 files changed, 241 insertions(+), 21 deletions(-)

New commits:
commit d5ea81b87b8a19b23007691c8b14e6787ecb0290
Author: Luboš Luňák <l.lunak at suse.cz>
Date:   Thu Jan 3 22:57:46 2013 +0100

    handle case of SRCDIR == BUILDDIR
    
    Change-Id: I9daea65dc28ab13776a7c4319e5d5811515fe160

diff --git a/compilerplugins/clang/plugin.cxx b/compilerplugins/clang/plugin.cxx
index 348386f..d6bc910 100644
--- a/compilerplugins/clang/plugin.cxx
+++ b/compilerplugins/clang/plugin.cxx
@@ -253,7 +253,7 @@ class PluginHandler
                 else if( strncmp( e->getName(), WORKDIR, strlen( WORKDIR )) == 0 )
                     diag.Report( diag.getCustomDiagID( DiagnosticsEngine::Warning,
                         "modified source in workdir/ : %0 [loplugin]" )) << e->getName();
-                else if( strncmp( e->getName(), BUILDDIR, strlen( BUILDDIR )) == 0 )
+                else if( strcmp( SRCDIR, BUILDDIR ) != 0 && strncmp( e->getName(), BUILDDIR, strlen( BUILDDIR )) == 0 )
                     diag.Report( diag.getCustomDiagID( DiagnosticsEngine::Warning,
                         "modified source in build dir : %0 [loplugin]" )) << e->getName();
                 else if( strncmp( e->getName(), SRCDIR, strlen( SRCDIR )) == 0 )
commit 258aca9924d9e47737d750356d45227126dcf6a7
Author: Luboš Luňák <l.lunak at suse.cz>
Date:   Thu Jan 3 20:23:51 2013 +0100

    rewriter plugin for removing forward rtl string declarations
    
    Change-Id: I12bf38985ae62756973c05aacf762ae3c405ac9b

diff --git a/compilerplugins/Makefile-clang.mk b/compilerplugins/Makefile-clang.mk
index 6031fe1..e652e44 100644
--- a/compilerplugins/Makefile-clang.mk
+++ b/compilerplugins/Makefile-clang.mk
@@ -14,6 +14,7 @@ CLANGSRC= \
     bodynotinblock.cxx \
     lclstaticfix.cxx \
     postfixincrementfix.cxx \
+    removeforwardstringdecl.cxx \
     sallogareas.cxx \
     unusedvariablecheck.cxx \
 
diff --git a/compilerplugins/clang/plugin.cxx b/compilerplugins/clang/plugin.cxx
index 22bac0c..348386f 100644
--- a/compilerplugins/clang/plugin.cxx
+++ b/compilerplugins/clang/plugin.cxx
@@ -22,6 +22,7 @@
 #include "bodynotinblock.hxx"
 #include "lclstaticfix.hxx"
 #include "postfixincrementfix.hxx"
+#include "removeforwardstringdecl.hxx"
 #include "sallogareas.hxx"
 #include "unusedvariablecheck.hxx"
 
@@ -192,6 +193,7 @@ class PluginHandler
             , bodyNotInBlock( context )
             , lclStaticFix( context, rewriter )
             , postfixIncrementFix( context, rewriter )
+            , removeForwardStringDecl( context, rewriter )
             , salLogAreas( context )
             , unusedVariableCheck( context )
             {
@@ -204,6 +206,8 @@ class PluginHandler
                 lclStaticFix.run();
             else if( isArg( "postfixincrementfix" ))
                 postfixIncrementFix.run();
+            else if( isArg( "removeforwardstringdecl" ))
+                removeForwardStringDecl.run();
             else if( args.empty())
                 {
                 bodyNotInBlock.run();
@@ -292,6 +296,7 @@ class PluginHandler
         BodyNotInBlock bodyNotInBlock;
         LclStaticFix lclStaticFix;
         PostfixIncrementFix postfixIncrementFix;
+        RemoveForwardStringDecl removeForwardStringDecl;
         SalLogAreas salLogAreas;
         UnusedVariableCheck unusedVariableCheck;
     };
diff --git a/compilerplugins/clang/removeforwardstringdecl.cxx b/compilerplugins/clang/removeforwardstringdecl.cxx
new file mode 100644
index 0000000..45891d5
--- /dev/null
+++ b/compilerplugins/clang/removeforwardstringdecl.cxx
@@ -0,0 +1,76 @@
+/*
+ * 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 "removeforwardstringdecl.hxx"
+
+#include <clang/AST/ASTContext.h>
+#include <clang/Basic/SourceManager.h>
+
+/*
+This is a rewriter.
+
+Remove all forward declarations of rtl strings. I.e. 'namespace rtl { class OUString; }' etc.
+*/
+
+namespace loplugin
+{
+
+RemoveForwardStringDecl::RemoveForwardStringDecl( ASTContext& context, Rewriter& rewriter )
+    : RewritePlugin( context, rewriter )
+    {
+    }
+
+void RemoveForwardStringDecl::run()
+    {
+    TraverseDecl( context.getTranslationUnitDecl());
+    }
+
+bool RemoveForwardStringDecl::VisitNamespaceDecl( NamespaceDecl* declaration )
+    {
+    if( ignoreLocation( declaration ))
+        return true;
+    if( declaration->getQualifiedNameAsString() != "rtl" )
+        return true;
+    bool canRemove = true;
+    for( NamespaceDecl::decl_iterator it = declaration->decls_begin();
+         it != declaration->decls_end();
+         ++it )
+        {
+        if( *it != NULL )
+            {
+            if( !tryRemoveStringForwardDecl( *it ))
+                canRemove = false;
+            }
+        }
+    if( canRemove ) // contained only forward decls that we removed
+        removeText( declaration->getSourceRange(), RemoveLineIfEmpty );
+    return true;
+    }
+
+bool RemoveForwardStringDecl::tryRemoveStringForwardDecl( const Decl* decl )
+    {
+    const CXXRecordDecl* classdecl = dyn_cast< CXXRecordDecl >( decl );
+    if( classdecl == NULL )
+        return false;
+    if( !classdecl->isFreeStanding() || classdecl->isCompleteDefinition())
+        return false; // not a simple forward declaration
+    if( classdecl->getName() == "OString" || classdecl->getName() == "OUString"
+        || classdecl->getName() == "OStringBuffer" || classdecl->getName() == "OUStringBuffer"
+        || classdecl->getName() == "OStringHash" || classdecl->getName() == "OUStringHash"
+        || classdecl->getName() == "OStringLiteral" || classdecl->getName() == "OUStringLiteral" )
+        {
+        removeText( SourceRange( classdecl->getOuterLocStart(), classdecl->getLocEnd()),
+            RemoveLineIfEmpty | RemoveWholeStatement );
+        return true;
+        }
+    return false;
+    }
+
+} // namespace
diff --git a/compilerplugins/clang/removeforwardstringdecl.hxx b/compilerplugins/clang/removeforwardstringdecl.hxx
new file mode 100644
index 0000000..7f40e37
--- /dev/null
+++ b/compilerplugins/clang/removeforwardstringdecl.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 REMOVEFORWARDSTRINGDECL_H
+#define REMOVEFORWARDSTRINGDECL_H
+
+#include "plugin.hxx"
+
+namespace loplugin
+{
+
+class RemoveForwardStringDecl
+    : public RecursiveASTVisitor< RemoveForwardStringDecl >
+    , public RewritePlugin
+    {
+    public:
+        explicit RemoveForwardStringDecl( ASTContext& context, Rewriter& rewriter );
+        void run();
+        bool VisitNamespaceDecl( NamespaceDecl* declaration );
+    private:
+        bool tryRemoveStringForwardDecl( const Decl* decl );
+    };
+
+} // namespace
+
+#endif // REMOVEFORWARDSTRINGDECL_H
+
commit c26e655264f03bb8bc484130ab2f539a9f831f16
Author: Luboš Luňák <l.lunak at suse.cz>
Date:   Thu Dec 20 23:08:52 2012 +0100

    support for removing a statement as a whole
    
    Change-Id: Icb7b017a0c76a6169f0f629bb40bf97449c75837

diff --git a/compilerplugins/clang/plugin.cxx b/compilerplugins/clang/plugin.cxx
index 6535e1a..22bac0c 100644
--- a/compilerplugins/clang/plugin.cxx
+++ b/compilerplugins/clang/plugin.cxx
@@ -105,22 +105,47 @@ bool RewritePlugin::insertTextBefore( SourceLocation Loc, StringRef Str )
 
 bool RewritePlugin::removeText( SourceLocation Start, unsigned Length, RewriteOptions opts )
     {
-    if( rewriter.RemoveText( Start, Length, opts ))
-        return reportEditFailure( Start );
-    return true;
+    return removeText( SourceRange( Start, Start.getLocWithOffset( Length )), opts );
     }
 
-bool RewritePlugin::removeText( CharSourceRange range, RewriteOptions opts )
+bool RewritePlugin::removeText( SourceRange range, RewriteOptions opts )
     {
+    if( opts.RemoveWholeStatement )
+        {
+        if( !adjustForWholeStatement( &range ))
+            return reportEditFailure( range.getBegin());
+        }
     if( rewriter.RemoveText( range, opts ))
         return reportEditFailure( range.getBegin());
     return true;
     }
 
-bool RewritePlugin::removeText( SourceRange range, RewriteOptions opts )
+bool RewritePlugin::adjustForWholeStatement( SourceRange* range )
     {
-    if( rewriter.RemoveText( range, opts ))
-        return reportEditFailure( range.getBegin());
+    SourceManager& SM = rewriter.getSourceMgr();
+    SourceLocation fileStartLoc = SM.getLocForStartOfFile( SM.getFileID( range->getBegin()));
+    if( fileStartLoc.isInvalid())
+        return false;
+    bool invalid = false;
+    const char* fileBuf = SM.getCharacterData( fileStartLoc, &invalid );
+    if( invalid )
+        return false;
+    const char* startBuf = SM.getCharacterData( range->getBegin(), &invalid );
+    if( invalid )
+        return false;
+    const char* endBuf = SM.getCharacterData( range->getEnd(), &invalid );
+    if( invalid )
+        return false;
+    const char* startSpacePos = startBuf;
+    // do not skip \n here, RemoveLineIfEmpty can take care of that
+    --startSpacePos;
+    while( startSpacePos >= fileBuf && ( *startSpacePos == ' ' || *startSpacePos == '\t' ))
+        --startSpacePos;
+    const char* semiPos = strchr( endBuf, ';' );
+    if( semiPos == NULL )
+        return false;
+    *range = SourceRange( range->getBegin().getLocWithOffset( startSpacePos - startBuf + 1 ),
+        range->getEnd().getLocWithOffset( semiPos - endBuf + 1 ));
     return true;
     }
 
diff --git a/compilerplugins/clang/plugin.hxx b/compilerplugins/clang/plugin.hxx
index 2a587ad..b9409b2 100644
--- a/compilerplugins/clang/plugin.hxx
+++ b/compilerplugins/clang/plugin.hxx
@@ -44,18 +44,39 @@ class RewritePlugin
     public:
         explicit RewritePlugin( ASTContext& context, Rewriter& rewriter );
     protected:
-        typedef Rewriter::RewriteOptions RewriteOptions;
+        // This enum allows passing just 'RemoveLineIfEmpty' to functions below.
+        enum RemoveLineIfEmpty_t { RemoveLineIfEmpty };
+        // Use this to remove the declaration/statement as a whole, i.e. all whitespace before the statement
+        // and the trailing semicolor (is not part of the AST element range itself).
+        // The trailing semicolon must be present.
+        enum RemoveWholeStatement_t { RemoveWholeStatement };
+        enum RemoveLineIfEmptyAndWholeStatement_t { RemoveLineIfEmptyAndWholeStatement };
+        // syntactic sugar to be able to write 'RemoveLineIfEmpty | RemoveWholeStatement'
+        friend RemoveLineIfEmptyAndWholeStatement_t operator|( RemoveLineIfEmpty_t, RemoveWholeStatement_t )
+            { return RemoveLineIfEmptyAndWholeStatement; }
+        struct RewriteOptions
+            : public Rewriter::RewriteOptions
+            {
+            RewriteOptions() : RemoveWholeStatement( false ) {} // default
+            RewriteOptions( RemoveLineIfEmpty_t ) : RemoveWholeStatement( false ) { RemoveLineIfEmpty = true; }
+            RewriteOptions( RemoveWholeStatement_t ) : RemoveWholeStatement( true ) {}
+            RewriteOptions( RemoveLineIfEmptyAndWholeStatement_t ) : RemoveWholeStatement( true ) { RemoveLineIfEmpty = true; }
+            bool RemoveWholeStatement;
+            };
         // These following insert/remove/replaceText functions map to functions
-        // in clang::Rewriter, with two differences:
+        // in clang::Rewriter, with these differences:
         // - they (more intuitively) return false on failure rather than true
         // - they report a warning when the change cannot be done
+        // - There is RemoveWholeStatement to also remove the trailing semicolon when removing (must be there)
+        //   and al preceding whitespace.
         bool insertText( SourceLocation Loc, StringRef Str,
             bool InsertAfter = true, bool indentNewLines = false );
         bool insertTextAfter( SourceLocation Loc, StringRef Str );
         bool insertTextAfterToken( SourceLocation Loc, StringRef Str );
         bool insertTextBefore( SourceLocation Loc, StringRef Str );
         bool removeText( SourceLocation Start, unsigned Length, RewriteOptions opts = RewriteOptions());
-        bool removeText( CharSourceRange range, RewriteOptions opts = RewriteOptions());
+        // CharSourceRange not supported, unless really needed, as it makes RemoveSemicolon more complicated
+        //bool removeText( CharSourceRange range, RewriteOptions opts = RewriteOptions());
         bool removeText( SourceRange range, RewriteOptions opts = RewriteOptions());
         bool replaceText( SourceLocation Start, unsigned OrigLength, StringRef NewStr );
         bool replaceText( SourceRange range, StringRef NewStr );
@@ -63,6 +84,7 @@ class RewritePlugin
         Rewriter& rewriter;
     private:
         bool reportEditFailure( SourceLocation loc );
+        bool adjustForWholeStatement( SourceRange* range );
     };
 
 inline
commit 217e3f2ea1e8983328364607f244daceeafca167
Author: Luboš Luňák <l.lunak at suse.cz>
Date:   Thu Jan 3 20:15:21 2013 +0100

    better handling of which files are processed by clang plugins
    
    Check that only LO's files are processed, as there's no point otherwise.
    Also warn about files in workdir/solver/builddir, as those are either
    generated or copies. Try to automatically match include files from
    solver to srcdir though, as that's where include files are usually
    included from :(.
    
    Change-Id: Ie8389e903f623a9d0e75015091acc0da78e76c3a

diff --git a/compilerplugins/clang/lclstaticfix.cxx b/compilerplugins/clang/lclstaticfix.cxx
index 9227af8..a5c765b 100644
--- a/compilerplugins/clang/lclstaticfix.cxx
+++ b/compilerplugins/clang/lclstaticfix.cxx
@@ -34,9 +34,7 @@ void LclStaticFix::run()
 
 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()))
+    if( ignoreLocation( declaration ))
         return true;
     if( declaration->isCXXClassMember())
         return true;
diff --git a/compilerplugins/clang/plugin.cxx b/compilerplugins/clang/plugin.cxx
index 62412e6..6535e1a 100644
--- a/compilerplugins/clang/plugin.cxx
+++ b/compilerplugins/clang/plugin.cxx
@@ -25,6 +25,8 @@
 #include "sallogareas.hxx"
 #include "unusedvariablecheck.hxx"
 
+#include <config_clang.h>
+
 namespace loplugin
 {
 
@@ -51,7 +53,19 @@ DiagnosticBuilder Plugin::report( DiagnosticsEngine::Level level, StringRef mess
 
 bool Plugin::ignoreLocation( SourceLocation loc )
     {
-    return context.getSourceManager().isInSystemHeader( context.getSourceManager().getExpansionLoc( loc ));
+    SourceLocation expansionLoc = context.getSourceManager().getExpansionLoc( loc );
+    if( context.getSourceManager().isInSystemHeader( expansionLoc ))
+        return true;
+    bool invalid;
+    const char* bufferName = context.getSourceManager().getBufferName( expansionLoc, &invalid );
+    if( invalid )
+        return true;
+    if( strncmp( bufferName, OUTDIR, strlen( OUTDIR )) == 0
+        || strncmp( bufferName, WORKDIR, strlen( WORKDIR )) == 0
+        || strncmp( bufferName, BUILDDIR, strlen( BUILDDIR )) == 0
+        || strncmp( bufferName, SRCDIR, strlen( SRCDIR )) == 0 )
+        return false; // ok
+    return true;
     }
 
 
@@ -182,24 +196,64 @@ class PluginHandler
                  ++it )
                 {
                 const FileEntry* e = context.getSourceManager().getFileEntryForID( it->first );
-                char* filename = new char[ strlen( e->getName()) + 100 ];
-                sprintf( filename, "%s.new.%d", e->getName(), getpid());
+                DiagnosticsEngine& diag = context.getDiagnostics();
+                /* Check where the file actually is, and warn about cases where modification
+                   most probably doesn't matter (generated files in workdir).
+                   The order here is important, as OUTDIR and WORKDIR are often in SRCDIR/BUILDDIR,
+                   and BUILDDIR is sometimes in SRCDIR. */
+                string modifyFile;
+                if( strncmp( e->getName(), OUTDIR, strlen( OUTDIR )) == 0 )
+                    {
+                    /* Try to find a matching file for a file in solver/ (include files
+                       are usually included from there rather than from the source dir) if possible. */
+                    if( strncmp( e->getName(), OUTDIR "/inc/", strlen( OUTDIR ) + strlen( "/inc/" )) == 0 )
+                        {
+                        string filename( e->getName());
+                        int modulePos = strlen( OUTDIR ) + strlen( "/inc/" );
+                        int moduleEnd = filename.find( '/', modulePos );
+                        if( moduleEnd != string::npos )
+                            {
+                            modifyFile = SRCDIR "/" + filename.substr( modulePos, moduleEnd - modulePos )
+                                + "/inc/" + filename.substr( modulePos );
+                            }
+                        }
+                    if( modifyFile.empty())
+                        diag.Report( diag.getCustomDiagID( DiagnosticsEngine::Warning,
+                            "modified source in solver/ : %0 [loplugin]" )) << e->getName();
+                    }
+                else if( strncmp( e->getName(), WORKDIR, strlen( WORKDIR )) == 0 )
+                    diag.Report( diag.getCustomDiagID( DiagnosticsEngine::Warning,
+                        "modified source in workdir/ : %0 [loplugin]" )) << e->getName();
+                else if( strncmp( e->getName(), BUILDDIR, strlen( BUILDDIR )) == 0 )
+                    diag.Report( diag.getCustomDiagID( DiagnosticsEngine::Warning,
+                        "modified source in build dir : %0 [loplugin]" )) << e->getName();
+                else if( strncmp( e->getName(), SRCDIR, strlen( SRCDIR )) == 0 )
+                    ; // ok
+                else
+                    {
+                    diag.Report( diag.getCustomDiagID( DiagnosticsEngine::Warning,
+                        "modified source in unknown location, not modifying : %0 [loplugin]" )) << e->getName();
+                    continue; // --->
+                    }
+                if( modifyFile.empty())
+                    modifyFile = e->getName();
+                char* filename = new char[ modifyFile.length() + 100 ];
+                sprintf( filename, "%s.new.%d", modifyFile.c_str(), getpid());
                 string error;
                 bool ok = false;
                 raw_fd_ostream ostream( filename, error );
-                DiagnosticsEngine& diag = context.getDiagnostics();
                 if( error.empty())
                     {
                     it->second.write( ostream );
                     ostream.close();
-                    if( !ostream.has_error() && rename( filename, e->getName()) == 0 )
+                    if( !ostream.has_error() && rename( filename, modifyFile.c_str()) == 0 )
                         ok = true;
                     }
                 ostream.clear_error();
                 unlink( filename );
                 if( !ok )
                     diag.Report( diag.getCustomDiagID( DiagnosticsEngine::Error,
-                        "cannot write modified source to %0 (%1) [loplugin]" )) << e->getName() << error;
+                        "cannot write modified source to %0 (%1) [loplugin]" )) << modifyFile << error;
                 delete[] filename;
                 }
             }
diff --git a/compilerplugins/clang/postfixincrementfix.cxx b/compilerplugins/clang/postfixincrementfix.cxx
index c5c17fb..bfaf77c 100644
--- a/compilerplugins/clang/postfixincrementfix.cxx
+++ b/compilerplugins/clang/postfixincrementfix.cxx
@@ -28,8 +28,7 @@ void PostfixIncrementFix::run()
 
 bool PostfixIncrementFix::VisitFunctionDecl( FunctionDecl* declaration )
     {
-    // TODO also LO header files? or a subdir?
-    if( !context.getSourceManager().isFromMainFile( declaration->getLocStart()))
+    if( ignoreLocation( declaration ))
         return true;
     if( !declaration->doesThisDeclarationHaveABody())
         return true;
diff --git a/config/config_clang.h.in b/config/config_clang.h.in
index 60ff5bf..9d87e7a 100644
--- a/config/config_clang.h.in
+++ b/config/config_clang.h.in
@@ -7,6 +7,9 @@ Settings related to Clang compiler plugins.
 #ifndef CONFIG_CLANG_H
 #define CONFIG_CLANG_H
 
+#undef BUILDDIR
+#undef OUTDIR
 #undef SRCDIR
+#undef WORKDIR
 
 #endif
diff --git a/configure.ac b/configure.ac
index 9f9527d67..bd5b074 100644
--- a/configure.ac
+++ b/configure.ac
@@ -107,6 +107,7 @@ AC_SUBST(BUILDDIR)
 AC_SUBST(EXEEXT_FOR_BUILD)
 AC_SUBST(x_Cygwin)
 AC_DEFINE_UNQUOTED(SRCDIR,"$SRC_ROOT")
+AC_DEFINE_UNQUOTED(BUILDDIR,"$BUILDDIR")
 
 if test "z$EUID" = "z0" -a "`uname -o 2>/dev/null`" = "Cygwin"; then
     AC_MSG_ERROR([You must build LibreOffice as a normal user - not using an administrative account])
@@ -4092,6 +4093,8 @@ AC_SUBST(P_SEP)
 AC_SUBST(SOLARVER)
 AC_SUBST(WORKDIR)
 AC_SUBST(PLATFORMID)
+AC_DEFINE_UNQUOTED(OUTDIR,"$OUTDIR")
+AC_DEFINE_UNQUOTED(WORKDIR,"$WORKDIR")
 
 dnl ===================================================================
 dnl Test which package format to use


More information about the Libreoffice-commits mailing list