[Libreoffice-commits] .: 11 commits - compilerplugins/clang compilerplugins/.gitignore compilerplugins/Makefile compilerplugins/Makefile-clang.mk compilerplugins/Makefile.mk compilerplugins/README config_host.mk.in configure.in Makefile.top sal/inc solenv/gbuild soltools/cpp soltools/mkdepend vcl/inc

Libreoffice Gerrit user logerrit at kemper.freedesktop.org
Tue Oct 9 08:26:24 PDT 2012


 Makefile.top                                  |    6 -
 compilerplugins/.gitignore                    |    1 
 compilerplugins/Makefile                      |   23 ++++
 compilerplugins/Makefile-clang.mk             |   63 +++++++++++
 compilerplugins/Makefile.mk                   |   32 ++++++
 compilerplugins/README                        |   46 ++++++++
 compilerplugins/clang/bodynotinblock.cxx      |  138 ++++++++++++++++++++++++++
 compilerplugins/clang/bodynotinblock.hxx      |   35 ++++++
 compilerplugins/clang/compileplugin.cxx       |  100 ++++++++++++++++++
 compilerplugins/clang/compileplugin.hxx       |   47 ++++++++
 compilerplugins/clang/unusedvariablecheck.cxx |   98 ++++++++++++++++++
 compilerplugins/clang/unusedvariablecheck.hxx |   31 +++++
 config_host.mk.in                             |    1 
 configure.in                                  |   39 +++++++
 sal/inc/rtl/strbuf.hxx                        |    2 
 sal/inc/rtl/string.hxx                        |    2 
 sal/inc/rtl/ustrbuf.hxx                       |    2 
 sal/inc/rtl/ustring.hxx                       |    2 
 sal/inc/sal/types.h                           |   20 +++
 solenv/gbuild/platform/com_GCC_class.mk       |    2 
 solenv/gbuild/platform/com_GCC_defs.mk        |    6 +
 soltools/cpp/_macro.c                         |    2 
 soltools/mkdepend/cppsetup.c                  |    8 -
 soltools/mkdepend/ifparser.c                  |    8 -
 soltools/mkdepend/main.c                      |   28 ++---
 soltools/mkdepend/parse.c                     |   14 +-
 vcl/inc/vcl/keycod.hxx                        |    4 
 27 files changed, 721 insertions(+), 39 deletions(-)

New commits:
commit d19067683df48fd6a31dbe82da69f14f7680bf0b
Author: Luboš Luňák <l.lunak at suse.cz>
Date:   Tue Oct 9 17:09:48 2012 +0200

    fix incorrect formatting
    
    Change-Id: Ibe865e189db747a9d61268ad02b097002cb44654

diff --git a/vcl/inc/vcl/keycod.hxx b/vcl/inc/vcl/keycod.hxx
index a29b308..0d22720 100644
--- a/vcl/inc/vcl/keycod.hxx
+++ b/vcl/inc/vcl/keycod.hxx
@@ -101,8 +101,8 @@ inline KeyCode::KeyCode( sal_uInt16 nKey, sal_Bool bShift, sal_Bool bMod1, sal_B
         nCode |= KEY_MOD1;
     if( bMod2 )
         nCode |= KEY_MOD2;
-        if( bMod3 )
-                nCode |= KEY_MOD3;
+    if( bMod3 )
+        nCode |= KEY_MOD3;
     eFunc = KEYFUNC_DONTKNOW;
 }
 
commit f0eb45df5e3f59991102b2228a62d15baa397b59
Author: Luboš Luňák <l.lunak at suse.cz>
Date:   Tue Oct 9 17:01:14 2012 +0200

    fix some lousy formatting that triggers warnings from the compiler plugin
    
    Change-Id: I94cafba5363f24d608add6878c72f230f45fdb87

diff --git a/soltools/cpp/_macro.c b/soltools/cpp/_macro.c
index 7490597..251a1f6 100644
--- a/soltools/cpp/_macro.c
+++ b/soltools/cpp/_macro.c
@@ -664,7 +664,7 @@ Tokenrow *
 
         // Change by np 31.10.2001, #93725 - begin
         if ( tp->wslen > 0 )
-        *sp++ = ' ';
+            *sp++ = ' ';
         // change end.
 
         for (i = 0, cp = tp->t; (unsigned int)i < tp->len; i++)
diff --git a/soltools/mkdepend/cppsetup.c b/soltools/mkdepend/cppsetup.c
index 6a4d2b8..f4cdaa5 100644
--- a/soltools/mkdepend/cppsetup.c
+++ b/soltools/mkdepend/cppsetup.c
@@ -161,7 +161,7 @@ _lookup_variable (var, len)
     char tmpbuf[MAXNAMELEN + 1];
 
     if (len > MAXNAMELEN)
-    return 0;
+        return 0;
 
     strncpy (tmpbuf, var, len);
     tmpbuf[len] = '\0';
@@ -177,9 +177,9 @@ _my_eval_defined (ip, var, len)
 {
     (void)ip;
     if (_lookup_variable (var, len))
-    return 1;
+        return 1;
     else
-    return 0;
+        return 0;
 }
 
 #define isvarfirstletter(ccc) (isalpha(ccc) || (ccc) == '_')
@@ -196,7 +196,7 @@ _my_eval_variable (ip, var, len)
 
     s = _lookup_variable (var, len);
     if (!s)
-    return 0;
+        return 0;
     do {
     var = s;
     if (!isvarfirstletter(*var))
diff --git a/soltools/mkdepend/ifparser.c b/soltools/mkdepend/ifparser.c
index abfb92c..6518b1e 100644
--- a/soltools/mkdepend/ifparser.c
+++ b/soltools/mkdepend/ifparser.c
@@ -82,7 +82,7 @@ parse_variable (g, cp, varp)
     SKIPSPACE (cp);
 
     if (!isvarfirstletter (*cp))
-    return CALLFUNC(g, handle_error) (g, cp, "variable name");
+        return CALLFUNC(g, handle_error) (g, cp, "variable name");
 
     *varp = cp;
     /* EMPTY */
@@ -100,7 +100,7 @@ parse_number (g, cp, valp)
     SKIPSPACE (cp);
 
     if (!isdigit(*cp))
-    return CALLFUNC(g, handle_error) (g, cp, "number");
+        return CALLFUNC(g, handle_error) (g, cp, "number");
 
 #ifdef WIN32
     {
@@ -128,7 +128,7 @@ parse_value (g, cp, valp)
 
     SKIPSPACE (cp);
     if (!*cp)
-    return cp;
+        return cp;
 
     switch (*cp) {
       case '(':
@@ -178,7 +178,7 @@ parse_value (g, cp, valp)
         len = (int)(cp - var);
         SKIPSPACE (cp);
         if (paren && *cp != ')')
-        return CALLFUNC(g, handle_error) (g, cp, ")");
+            return CALLFUNC(g, handle_error) (g, cp, ")");
         *valp = (*(g->funcs.eval_defined)) (g, var, len);
         return cp + paren;      /* skip the right paren */
     }
diff --git a/soltools/mkdepend/main.c b/soltools/mkdepend/main.c
index f9dc0f7..5beb8fd 100644
--- a/soltools/mkdepend/main.c
+++ b/soltools/mkdepend/main.c
@@ -195,18 +195,18 @@ int main(argc, argv)
 
         nargc = 1;
         if ((afd = open(argv[1]+1, O_RDONLY)) < 0)
-        fatalerr("cannot open \"%s\"\n", argv[1]+1);
+            fatalerr("cannot open \"%s\"\n", argv[1]+1);
         fstat(afd, &ast);
         args = (char *)malloc(ast.st_size + 1);
         if ((ast.st_size = read(afd, args, (size_t) ast.st_size)) < 0)
-        fatalerr("failed to read %s\n", argv[1]+1);
+            fatalerr("failed to read %s\n", argv[1]+1);
         args[ast.st_size] = '\0';
         close(afd);
         for (p = args; *p; p++) {
         if (quotechar) {
-            if (quotechar == '\\' ||
-            (*p == quotechar && p[-1] != '\\'))
-            quotechar = '\0';
+            if (quotechar == '\\'
+                || (*p == quotechar && p[-1] != '\\'))
+                quotechar = '\0';
             continue;
         }
         switch (*p) {
@@ -219,18 +219,18 @@ int main(argc, argv)
         case '\n':
             *p = '\0';
             if (p > args && p[-1])
-            nargc++;
+                nargc++;
             break;
         }
         }
         if (p[-1])
-        nargc++;
+            nargc++;
         nargv = (char **)malloc(nargc * sizeof(char *));
         nargv[0] = argv[0];
         argc = 1;
         for (p = args; argc < nargc; p += strlen(p) + 1)
-        if (*p) nargv[argc++] = p;
-        argv = nargv;
+            if (*p) nargv[argc++] = p;
+                argv = nargv;
     }
     for(argc--, argv++; argc; argc--, argv++) {
             /* if looking for endmarker then check before parsing */
@@ -364,16 +364,16 @@ int main(argc, argv)
         *incp++ = PREINCDIR;
 #endif
         if (incp >= includedirs + MAXDIRS)
-        fatalerr("Too many -I flags.\n");
+            fatalerr("Too many -I flags.\n");
         *incp++ = INCLUDEDIR;
 #ifdef POSTINCDIR
         if (incp >= includedirs + MAXDIRS)
-        fatalerr("Too many -I flags.\n");
+            fatalerr("Too many -I flags.\n");
         *incp++ = POSTINCDIR;
 #endif
     } else if (*defincdir) {
         if (incp >= includedirs + MAXDIRS)
-        fatalerr("Too many -I flags.\n");
+            fatalerr("Too many -I flags.\n");
         *incp++ = defincdir;
     }
 
@@ -709,8 +709,8 @@ void redirect(line, makefile)
     }
     if (!found) {
         if (verbose)
-        warning("Adding new delimiting line \"%s\" and dependencies...\n",
-            line);
+            warning("Adding new delimiting line \"%s\" and dependencies...\n",
+                line);
         puts(line); /* same as fputs(fdout); but with newline */
     } else if (append) {
         while (fgets(buf, BUFSIZ, fdin)) {
diff --git a/soltools/mkdepend/parse.c b/soltools/mkdepend/parse.c
index 939155a..0914fbc 100644
--- a/soltools/mkdepend/parse.c
+++ b/soltools/mkdepend/parse.c
@@ -70,11 +70,9 @@ int find_includes(struct filepointer *filep, struct inclist *file, struct inclis
             if (type == ELSE)
                 find_includes(filep, file,
                       file_red, recursion+1, recfailOK, incCollection, symbols);
-            else
-            if (type == ELIF)
+            else if (type == ELIF)
                 goto doif;
-            else
-            if ((type == ELIFFALSE) || (type == ELIFGUESSFALSE))
+            else if ((type == ELIFFALSE) || (type == ELIFGUESSFALSE))
                 goto doiffalse;
             break;
         case IFDEF:
@@ -398,14 +396,14 @@ void define( def, symbols )
     /* Separate symbol name and its value */
     val = def;
     while (isalnum(*val) || *val == '_')
-    val++;
+        val++;
     if (*val)
-    *val++ = '\0';
+        *val++ = '\0';
     while (*val == ' ' || *val == '\t')
-    val++;
+        val++;
 
     if (!*val)
-    val = "1";
+        val = "1";
     hash_define( def, val, symbols );
 }
 
commit 7c4d3ea6ba4d42b4dda5148a00c8c411b5d7703d
Author: Luboš Luňák <l.lunak at suse.cz>
Date:   Tue Oct 9 16:55:15 2012 +0200

    don't check next statement after if body if there's also an else part
    
    Change-Id: I04265acd821187f529562691f35ede93b84368fa

diff --git a/compilerplugins/clang/bodynotinblock.cxx b/compilerplugins/clang/bodynotinblock.cxx
index 9c047c5..f13eb93 100644
--- a/compilerplugins/clang/bodynotinblock.cxx
+++ b/compilerplugins/clang/bodynotinblock.cxx
@@ -54,7 +54,7 @@ void BodyNotInBlock::traverseStatement( const Stmt* stmt, StmtParents& parents )
             parents.push_back( *it );
             if( const IfStmt* ifstmt = dyn_cast< IfStmt >( *it ))
                 {
-                checkBody( ifstmt->getThen(), parents, 0 );
+                checkBody( ifstmt->getThen(), parents, 0, ifstmt->getElse() != NULL );
                 checkBody( ifstmt->getElse(), parents, 0 );
                 }
             else if( const WhileStmt* whilestmt = dyn_cast< WhileStmt >( *it ))
@@ -70,7 +70,7 @@ void BodyNotInBlock::traverseStatement( const Stmt* stmt, StmtParents& parents )
     parents.pop_back();
     }
 
-void BodyNotInBlock::checkBody( const Stmt* body, const StmtParents& parents, int stmtType )
+void BodyNotInBlock::checkBody( const Stmt* body, const StmtParents& parents, int stmtType, bool dontGoUp )
     {
     if( body == NULL || parents.size() < 2 )
         return;
@@ -127,6 +127,11 @@ void BodyNotInBlock::checkBody( const Stmt* body, const StmtParents& parents, in
         // make it visible the two statements are not in the same body.
         if( dyn_cast< CompoundStmt >( parents[ parent_pos ] ))
             return;
+        // If the body to be checked is a body of an if statement that has also
+        // an else part, don't go up, the else is after the body and should make
+        // it clear the body does not continue there.
+        if( dontGoUp )
+            return;
         }
     }
 
diff --git a/compilerplugins/clang/bodynotinblock.hxx b/compilerplugins/clang/bodynotinblock.hxx
index 9846d7a..a2c47e6 100644
--- a/compilerplugins/clang/bodynotinblock.hxx
+++ b/compilerplugins/clang/bodynotinblock.hxx
@@ -27,7 +27,7 @@ class BodyNotInBlock
     private:
         typedef std::vector< const Stmt* > StmtParents;
         void traverseStatement( const Stmt* stmt, StmtParents& parents );
-        void checkBody( const Stmt* body, const StmtParents& parents, int stmtType );
+        void checkBody( const Stmt* body, const StmtParents& parents, int stmtType, bool dontGoUp = false );
     };
 
 } // namespace
commit 4d3c6a04995a19209c3a66b92fddbb50c92418b7
Author: Luboš Luňák <l.lunak at suse.cz>
Date:   Tue Oct 9 16:48:48 2012 +0200

    ignore macro expansion completely for now
    
    Change-Id: Ie37b83fef1279a0a953de27941e3b342437c81d1

diff --git a/compilerplugins/clang/bodynotinblock.cxx b/compilerplugins/clang/bodynotinblock.cxx
index 9e59896..9c047c5 100644
--- a/compilerplugins/clang/bodynotinblock.cxx
+++ b/compilerplugins/clang/bodynotinblock.cxx
@@ -74,6 +74,13 @@ void BodyNotInBlock::checkBody( const Stmt* body, const StmtParents& parents, in
     {
     if( body == NULL || parents.size() < 2 )
         return;
+    // TODO: If the if/while/for comes from a macro expansion, ignore it completely for
+    // now. The code below could assume everything is in the same place (and thus also column)
+    // and give a false warning. Moreover some macros are rather lousily written and would
+    // result in poor formatting. To be evaluated later, maybe this could be handled
+    // including macro expansion.
+    if( parents.back()->getLocStart().isMacroID())
+        return;
     if( dyn_cast< CompoundStmt >( body ))
         return; // if body is a compound statement, then it is in {}
     // Find the next statement (in source position) after 'body'.
@@ -93,13 +100,6 @@ void BodyNotInBlock::checkBody( const Stmt* body, const StmtParents& parents, in
                     ++it; // skip empty ones (missing 'else' bodies for example)
                 if( it != parents[ parent_pos ]->child_end())
                     {
-                    // TODO: If both statements come from macro expansions, they may be
-                    // below evaluated to be in the same place (because they may be
-                    // the result of expansion of the same macro). Analysing this including
-                    // macro expansions would be probably more complicated, so just
-                    // ignore that in order to avoid false positives.
-                    if( body->getLocStart().isMacroID() && (*it)->getLocStart().isMacroID())
-                        return;
                     bool invalid1, invalid2;
                     unsigned bodyColumn = context.getSourceManager()
                         .getPresumedColumnNumber( body->getLocStart(), &invalid1 );
commit 7cd19a8f10881028bfaf4217e586955f1d435c31
Author: Luboš Luňák <l.lunak at suse.cz>
Date:   Tue Oct 9 16:39:49 2012 +0200

    do not analyse system headers in the compiler plugin
    
    Change-Id: Ica1e233b45cc778bfdc86cfd608ada7fc261c6c2

diff --git a/compilerplugins/clang/bodynotinblock.cxx b/compilerplugins/clang/bodynotinblock.cxx
index ce19a5f..9e59896 100644
--- a/compilerplugins/clang/bodynotinblock.cxx
+++ b/compilerplugins/clang/bodynotinblock.cxx
@@ -32,8 +32,7 @@ void BodyNotInBlock::run()
 
 bool BodyNotInBlock::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/compilerplugins/clang/compileplugin.cxx b/compilerplugins/clang/compileplugin.cxx
index e5d34a3..a61a3ba 100644
--- a/compilerplugins/clang/compileplugin.cxx
+++ b/compilerplugins/clang/compileplugin.cxx
@@ -43,6 +43,11 @@ DiagnosticBuilder Plugin::report( DiagnosticsEngine::Level level, StringRef mess
     return diag.Report( loc, diag.getCustomDiagID( level, message ));
     }
 
+bool Plugin::ignoreLocation( SourceLocation loc )
+    {
+    return context.getSourceManager().isInSystemHeader( context.getSourceManager().getExpansionLoc( loc ));
+    }
+
 /**
  Class that manages all LO modules.
 */
diff --git a/compilerplugins/clang/compileplugin.hxx b/compilerplugins/clang/compileplugin.hxx
index edf3a5e..a02b360 100644
--- a/compilerplugins/clang/compileplugin.hxx
+++ b/compilerplugins/clang/compileplugin.hxx
@@ -24,9 +24,24 @@ class Plugin
         explicit Plugin( ASTContext& context );
     protected:
         DiagnosticBuilder report( DiagnosticsEngine::Level level, StringRef message, SourceLocation loc );
+        bool ignoreLocation( SourceLocation loc );
+        bool ignoreLocation( const Decl* decl );
+        bool ignoreLocation( const Stmt* stmt );
         ASTContext& context;
     };
 
+inline
+bool Plugin::ignoreLocation( const Decl* decl )
+    {
+    return ignoreLocation( decl->getLocStart());
+    }
+
+inline
+bool Plugin::ignoreLocation( const Stmt* stmt )
+    {
+    return ignoreLocation( stmt->getLocStart());
+    }
+
 } // namespace
 
 #endif // COMPILEPLUGIN_H
diff --git a/compilerplugins/clang/unusedvariablecheck.cxx b/compilerplugins/clang/unusedvariablecheck.cxx
index a9e47b2..f291632 100644
--- a/compilerplugins/clang/unusedvariablecheck.cxx
+++ b/compilerplugins/clang/unusedvariablecheck.cxx
@@ -40,8 +40,7 @@ void UnusedVariableCheck::run()
 
 bool UnusedVariableCheck::VisitNamedDecl( NamedDecl* declaration )
     {
-    // TODO also LO header files? or a subdir?
-    if( !context.getSourceManager().isFromMainFile( declaration->getLocStart()))
+    if( ignoreLocation( declaration ))
         return true;
     if( !isa< VarDecl >( declaration ))
         return true;
commit 4d05099806fc6116fbd7abe992d7f2f31210dd4c
Author: Luboš Luňák <l.lunak at suse.cz>
Date:   Tue Oct 9 16:28:13 2012 +0200

    do not force compiler plugin warnings to errors with -Werror, for now
    
    Change-Id: I87585fce44e803513d5345709d9723075b9429a1

diff --git a/compilerplugins/clang/compileplugin.cxx b/compilerplugins/clang/compileplugin.cxx
index 99ab272..e5d34a3 100644
--- a/compilerplugins/clang/compileplugin.cxx
+++ b/compilerplugins/clang/compileplugin.cxx
@@ -32,12 +32,14 @@ Plugin::Plugin( ASTContext& context )
 
 DiagnosticBuilder Plugin::report( DiagnosticsEngine::Level level, StringRef message, SourceLocation loc )
     {
-    // Do some mappings (e.g. for -Werror) that clang does not do for custom messages for some reason.
     DiagnosticsEngine& diag = context.getDiagnostics();
+#if 0
+    // Do some mappings (e.g. for -Werror) that clang does not do for custom messages for some reason.
     if( level == DiagnosticsEngine::Warning && diag.getWarningsAsErrors())
         level = DiagnosticsEngine::Error;
     if( level == DiagnosticsEngine::Error && diag.getErrorsAsFatal())
         level = DiagnosticsEngine::Fatal;
+#endif
     return diag.Report( loc, diag.getCustomDiagID( level, message ));
     }
 
commit 4fc56b9d4cd12cca51d7696e0776de5aa8f822cd
Author: Luboš Luňák <l.lunak at suse.cz>
Date:   Tue Oct 9 16:27:25 2012 +0200

    move some code to a common base
    
    Change-Id: Ife306c69054dfcc20b1339b88a4e14e5333ced71

diff --git a/compilerplugins/clang/bodynotinblock.cxx b/compilerplugins/clang/bodynotinblock.cxx
index 9f5bf0e..ce19a5f 100644
--- a/compilerplugins/clang/bodynotinblock.cxx
+++ b/compilerplugins/clang/bodynotinblock.cxx
@@ -12,8 +12,6 @@
 
 #include <clang/Basic/SourceManager.h>
 
-using namespace clang;
-
 namespace loplugin
 {
 
@@ -23,19 +21,8 @@ but are not inside a compound statement and thus the second one is unrelated.
 */
 
 BodyNotInBlock::BodyNotInBlock( ASTContext& context )
-    : context( context )
-    {
-    }
-
-DiagnosticBuilder BodyNotInBlock::report( DiagnosticsEngine::Level level, StringRef message, SourceLocation loc )
+    : Plugin( context )
     {
-    // Do some mappings (e.g. for -Werror) that clang does not do for custom messages for some reason.
-    DiagnosticsEngine& diag = context.getDiagnostics();
-    if( level == DiagnosticsEngine::Warning && diag.getWarningsAsErrors())
-        level = DiagnosticsEngine::Error;
-    if( level == DiagnosticsEngine::Error && diag.getErrorsAsFatal())
-        level = DiagnosticsEngine::Fatal;
-    return diag.Report( loc, diag.getCustomDiagID( level, message ));
     }
 
 void BodyNotInBlock::run()
diff --git a/compilerplugins/clang/bodynotinblock.hxx b/compilerplugins/clang/bodynotinblock.hxx
index dba82a6..9846d7a 100644
--- a/compilerplugins/clang/bodynotinblock.hxx
+++ b/compilerplugins/clang/bodynotinblock.hxx
@@ -11,27 +11,23 @@
 #ifndef BODYNOTINBLOCK_H
 #define BODYNOTINBLOCK_H
 
-#include <clang/AST/RecursiveASTVisitor.h>
-
-using namespace clang;
+#include "compileplugin.hxx"
 
 namespace loplugin
 {
 
-typedef std::vector< const Stmt* > StmtParents;
-
 class BodyNotInBlock
     : public RecursiveASTVisitor< BodyNotInBlock >
+    , public Plugin
     {
     public:
         explicit BodyNotInBlock( ASTContext& context );
         void run();
         bool VisitFunctionDecl( FunctionDecl* declaration );
     private:
+        typedef std::vector< const Stmt* > StmtParents;
         void traverseStatement( const Stmt* stmt, StmtParents& parents );
         void checkBody( const Stmt* body, const StmtParents& parents, int stmtType );
-        DiagnosticBuilder report( DiagnosticsEngine::Level level, StringRef message, SourceLocation loc );
-        ASTContext& context;
     };
 
 } // namespace
diff --git a/compilerplugins/clang/compileplugin.cxx b/compilerplugins/clang/compileplugin.cxx
index d2e32c0..99ab272 100644
--- a/compilerplugins/clang/compileplugin.cxx
+++ b/compilerplugins/clang/compileplugin.cxx
@@ -25,6 +25,22 @@ using namespace clang;
 namespace loplugin
 {
 
+Plugin::Plugin( ASTContext& context )
+    : context( context )
+    {
+    }
+
+DiagnosticBuilder Plugin::report( DiagnosticsEngine::Level level, StringRef message, SourceLocation loc )
+    {
+    // Do some mappings (e.g. for -Werror) that clang does not do for custom messages for some reason.
+    DiagnosticsEngine& diag = context.getDiagnostics();
+    if( level == DiagnosticsEngine::Warning && diag.getWarningsAsErrors())
+        level = DiagnosticsEngine::Error;
+    if( level == DiagnosticsEngine::Error && diag.getErrorsAsFatal())
+        level = DiagnosticsEngine::Fatal;
+    return diag.Report( loc, diag.getCustomDiagID( level, message ));
+    }
+
 /**
  Class that manages all LO modules.
 */
diff --git a/compilerplugins/clang/compileplugin.hxx b/compilerplugins/clang/compileplugin.hxx
index f7d5182..edf3a5e 100644
--- a/compilerplugins/clang/compileplugin.hxx
+++ b/compilerplugins/clang/compileplugin.hxx
@@ -11,4 +11,22 @@
 #ifndef COMPILEPLUGIN_H
 #define COMPILEPLUGIN_H
 
+#include <clang/AST/RecursiveASTVisitor.h>
+
+using namespace clang;
+
+namespace loplugin
+{
+
+class Plugin
+    {
+    public:
+        explicit Plugin( ASTContext& context );
+    protected:
+        DiagnosticBuilder report( DiagnosticsEngine::Level level, StringRef message, SourceLocation loc );
+        ASTContext& context;
+    };
+
+} // namespace
+
 #endif // COMPILEPLUGIN_H
diff --git a/compilerplugins/clang/unusedvariablecheck.cxx b/compilerplugins/clang/unusedvariablecheck.cxx
index 029e637..a9e47b2 100644
--- a/compilerplugins/clang/unusedvariablecheck.cxx
+++ b/compilerplugins/clang/unusedvariablecheck.cxx
@@ -12,8 +12,6 @@
 
 #include <clang/Basic/SourceManager.h>
 
-using namespace clang;
-
 namespace loplugin
 {
 
@@ -31,7 +29,7 @@ that cannot be edited there is a manual list below.
 */
 
 UnusedVariableCheck::UnusedVariableCheck( ASTContext& context )
-    : context( context )
+    : Plugin( context )
     {
     }
 
@@ -40,17 +38,6 @@ void UnusedVariableCheck::run()
     TraverseDecl( context.getTranslationUnitDecl());
     }
 
-DiagnosticBuilder UnusedVariableCheck::report( DiagnosticsEngine::Level level, StringRef message, SourceLocation loc )
-    {
-    // Do some mappings (e.g. for -Werror) that clang does not do for custom messages for some reason.
-    DiagnosticsEngine& diag = context.getDiagnostics();
-    if( level == DiagnosticsEngine::Warning && diag.getWarningsAsErrors())
-        level = DiagnosticsEngine::Error;
-    if( level == DiagnosticsEngine::Error && diag.getErrorsAsFatal())
-        level = DiagnosticsEngine::Fatal;
-    return diag.Report( loc, diag.getCustomDiagID( level, message ));
-    }
-
 bool UnusedVariableCheck::VisitNamedDecl( NamedDecl* declaration )
     {
     // TODO also LO header files? or a subdir?
diff --git a/compilerplugins/clang/unusedvariablecheck.hxx b/compilerplugins/clang/unusedvariablecheck.hxx
index c49532a..21e0eab 100644
--- a/compilerplugins/clang/unusedvariablecheck.hxx
+++ b/compilerplugins/clang/unusedvariablecheck.hxx
@@ -11,23 +11,19 @@
 #ifndef UNUSEDVARIABLECHECK_H
 #define UNUSEDVARIABLECHECK_H
 
-#include <clang/AST/RecursiveASTVisitor.h>
-
-using namespace clang;
+#include "compileplugin.hxx"
 
 namespace loplugin
 {
 
 class UnusedVariableCheck
     : public RecursiveASTVisitor< UnusedVariableCheck >
+    , public Plugin
     {
     public:
         explicit UnusedVariableCheck( ASTContext& context );
         void run();
         bool VisitNamedDecl( NamedDecl* declaration );
-    private:
-        DiagnosticBuilder report( DiagnosticsEngine::Level level, StringRef message, SourceLocation loc );
-        ASTContext& context;
     };
 
 } // namespace
commit d4aa136e975b150add5f32013ea37aa68e9ccb57
Author: Luboš Luňák <l.lunak at suse.cz>
Date:   Tue Oct 9 16:21:33 2012 +0200

    compiler plugin check for if/while/true bodies with possibly {} missing
    
    Change-Id: Ia84c70006b0b8a039b6fea27f3c5cde796f25d03

diff --git a/compilerplugins/Makefile-clang.mk b/compilerplugins/Makefile-clang.mk
index 9b37fb9..ca95f11 100644
--- a/compilerplugins/Makefile-clang.mk
+++ b/compilerplugins/Makefile-clang.mk
@@ -9,7 +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 unusedvariablecheck.cxx
+CLANGSRC=compileplugin.cxx \
+    bodynotinblock.cxx \
+    unusedvariablecheck.cxx \
+
 
 # You may occassionally want to override some of these
 
diff --git a/compilerplugins/README b/compilerplugins/README
index 2430d40..50c7505 100644
--- a/compilerplugins/README
+++ b/compilerplugins/README
@@ -28,6 +28,18 @@ 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]
+
+Warn about the following construct:
+
+    if( a != 0 )
+        b = 2;
+        c = 3;
+        
+Here either both statements should be inside {} or the second statement in indented wrong.
+
 
 == Code documentation / howtos ==
 
diff --git a/compilerplugins/clang/bodynotinblock.cxx b/compilerplugins/clang/bodynotinblock.cxx
new file mode 100644
index 0000000..9f5bf0e
--- /dev/null
+++ b/compilerplugins/clang/bodynotinblock.cxx
@@ -0,0 +1,147 @@
+/*
+ * 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 "bodynotinblock.hxx"
+
+#include <clang/Basic/SourceManager.h>
+
+using namespace clang;
+
+namespace loplugin
+{
+
+/*
+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.
+*/
+
+BodyNotInBlock::BodyNotInBlock( ASTContext& context )
+    : context( context )
+    {
+    }
+
+DiagnosticBuilder BodyNotInBlock::report( DiagnosticsEngine::Level level, StringRef message, SourceLocation loc )
+    {
+    // Do some mappings (e.g. for -Werror) that clang does not do for custom messages for some reason.
+    DiagnosticsEngine& diag = context.getDiagnostics();
+    if( level == DiagnosticsEngine::Warning && diag.getWarningsAsErrors())
+        level = DiagnosticsEngine::Error;
+    if( level == DiagnosticsEngine::Error && diag.getErrorsAsFatal())
+        level = DiagnosticsEngine::Fatal;
+    return diag.Report( loc, diag.getCustomDiagID( level, message ));
+    }
+
+void BodyNotInBlock::run()
+    {
+    TraverseDecl( context.getTranslationUnitDecl());
+    }
+
+bool BodyNotInBlock::VisitFunctionDecl( FunctionDecl* declaration )
+    {
+    // TODO also LO header files? or a subdir?
+    if( !context.getSourceManager().isFromMainFile( declaration->getLocStart()))
+        return true;
+    if( !declaration->doesThisDeclarationHaveABody())
+        return true;
+    StmtParents parents;
+    traverseStatement( declaration->getBody(), parents );
+    return true;
+    }
+
+void BodyNotInBlock::traverseStatement( const Stmt* stmt, StmtParents& parents )
+    {
+    parents.push_back( stmt );
+    for( ConstStmtIterator it = stmt->child_begin();
+         it != stmt->child_end();
+         ++it )
+        {
+        if( *it != NULL ) // some children can be apparently NULL
+            {
+            traverseStatement( *it, parents ); // substatements first
+            parents.push_back( *it );
+            if( const IfStmt* ifstmt = dyn_cast< IfStmt >( *it ))
+                {
+                checkBody( ifstmt->getThen(), parents, 0 );
+                checkBody( ifstmt->getElse(), parents, 0 );
+                }
+            else if( const WhileStmt* whilestmt = dyn_cast< WhileStmt >( *it ))
+                checkBody( whilestmt->getBody(), parents, 1 );
+            else if( const ForStmt* forstmt = dyn_cast< ForStmt >( *it ))
+                checkBody( forstmt->getBody(), parents, 2 );
+            else if( const CXXForRangeStmt* forstmt = dyn_cast< CXXForRangeStmt >( *it ))
+                checkBody( forstmt->getBody(), parents, 2 );
+            parents.pop_back();
+            }
+        }
+    assert( parents.back() == stmt );
+    parents.pop_back();
+    }
+
+void BodyNotInBlock::checkBody( const Stmt* body, const StmtParents& parents, int stmtType )
+    {
+    if( body == NULL || parents.size() < 2 )
+        return;
+    if( dyn_cast< CompoundStmt >( body ))
+        return; // if body is a compound statement, then it is in {}
+    // Find the next statement (in source position) after 'body'.
+    for( int parent_pos = parents.size() - 2; // start from grandparent
+         parent_pos >= 0;
+         --parent_pos )
+        {
+        for( ConstStmtIterator it = parents[ parent_pos ]->child_begin();
+             it != parents[ parent_pos ]->child_end();
+             )
+            {
+            if( *it == parents[ parent_pos + 1 ] ) // found grand(grand...)parent
+                {
+                // get next statement after our (grand...)parent
+                ++it;
+                while( it != parents[ parent_pos ]->child_end() && *it == NULL )
+                    ++it; // skip empty ones (missing 'else' bodies for example)
+                if( it != parents[ parent_pos ]->child_end())
+                    {
+                    // TODO: If both statements come from macro expansions, they may be
+                    // below evaluated to be in the same place (because they may be
+                    // the result of expansion of the same macro). Analysing this including
+                    // macro expansions would be probably more complicated, so just
+                    // ignore that in order to avoid false positives.
+                    if( body->getLocStart().isMacroID() && (*it)->getLocStart().isMacroID())
+                        return;
+                    bool invalid1, invalid2;
+                    unsigned bodyColumn = context.getSourceManager()
+                        .getPresumedColumnNumber( body->getLocStart(), &invalid1 );
+                    unsigned nextStatementColumn = context.getSourceManager()
+                        .getPresumedColumnNumber( (*it)->getLocStart(), &invalid2 );
+                    if( invalid1 || invalid2 )
+                        return;
+                    if( bodyColumn == nextStatementColumn )
+                        {
+                        report( DiagnosticsEngine::Warning,
+                            "statement aligned as second statement in %select{if|while|for}0 body but not in a statement block [loplugin]",
+                            (*it)->getLocStart()) << stmtType;
+                        report( DiagnosticsEngine::Note,
+                            "%select{if|while|for}0 body statement is here [loplugin]",
+                            body->getLocStart()) << stmtType;
+                        }
+                    return;
+                    }
+                // else we need to go higher to find the next statement
+                }
+            else
+                ++it;
+            }
+        // If going up would mean leaving a {} block, stop, because the } should
+        // make it visible the two statements are not in the same body.
+        if( dyn_cast< CompoundStmt >( parents[ parent_pos ] ))
+            return;
+        }
+    }
+
+} // namespace
diff --git a/compilerplugins/clang/bodynotinblock.hxx b/compilerplugins/clang/bodynotinblock.hxx
new file mode 100644
index 0000000..dba82a6
--- /dev/null
+++ b/compilerplugins/clang/bodynotinblock.hxx
@@ -0,0 +1,39 @@
+/*
+ * 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 BODYNOTINBLOCK_H
+#define BODYNOTINBLOCK_H
+
+#include <clang/AST/RecursiveASTVisitor.h>
+
+using namespace clang;
+
+namespace loplugin
+{
+
+typedef std::vector< const Stmt* > StmtParents;
+
+class BodyNotInBlock
+    : public RecursiveASTVisitor< BodyNotInBlock >
+    {
+    public:
+        explicit BodyNotInBlock( ASTContext& context );
+        void run();
+        bool VisitFunctionDecl( FunctionDecl* declaration );
+    private:
+        void traverseStatement( const Stmt* stmt, StmtParents& parents );
+        void checkBody( const Stmt* body, const StmtParents& parents, int stmtType );
+        DiagnosticBuilder report( DiagnosticsEngine::Level level, StringRef message, SourceLocation loc );
+        ASTContext& context;
+    };
+
+} // namespace
+
+#endif // BODYNOTINBLOCK_H
diff --git a/compilerplugins/clang/compileplugin.cxx b/compilerplugins/clang/compileplugin.cxx
index 2b16475..d2e32c0 100644
--- a/compilerplugins/clang/compileplugin.cxx
+++ b/compilerplugins/clang/compileplugin.cxx
@@ -17,6 +17,7 @@
 #include <clang/Frontend/FrontendPluginRegistry.h>
 #include <clang/Rewrite/Rewriter.h>
 
+#include "bodynotinblock.hxx"
 #include "unusedvariablecheck.hxx"
 
 using namespace clang;
@@ -33,6 +34,7 @@ class PluginHandler
     public:
         explicit PluginHandler( ASTContext& context )
             : rewriter( context.getSourceManager(), context.getLangOpts())
+            , bodyNotInBlock( context )
             , unusedVariableCheck( context )
             {
             }
@@ -40,6 +42,7 @@ class PluginHandler
             {
             if( context.getDiagnostics().hasErrorOccurred())
                 return;
+            bodyNotInBlock.run();
             unusedVariableCheck.run();
             // TODO also LO header files? or a subdir?
            if( const RewriteBuffer* buf = rewriter.getRewriteBufferFor( context.getSourceManager().getMainFileID()))
@@ -48,6 +51,7 @@ class PluginHandler
             }
     private:
         Rewriter rewriter;
+        BodyNotInBlock bodyNotInBlock;
         UnusedVariableCheck unusedVariableCheck;
     };
 
commit 76757ebd98df1e08d00282cb96312b5be7690d16
Author: Luboš Luňák <l.lunak at suse.cz>
Date:   Tue Oct 9 15:17:13 2012 +0200

    mark our string classes as SAL_WARN_UNUSED
    
    Change-Id: I420229dea6c5b3e45cec5989897bb31654851e32

diff --git a/sal/inc/rtl/strbuf.hxx b/sal/inc/rtl/strbuf.hxx
index 62c1799..51bb05f 100644
--- a/sal/inc/rtl/strbuf.hxx
+++ b/sal/inc/rtl/strbuf.hxx
@@ -97,7 +97,7 @@ namespace rtl
     buffer array. If the internal buffer overflows, it is
     automatically made larger.
  */
-class OStringBuffer
+class SAL_WARN_UNUSED OStringBuffer
 {
 public:
     /**
diff --git a/sal/inc/rtl/string.hxx b/sal/inc/rtl/string.hxx
index d58999b..a135d4e 100644
--- a/sal/inc/rtl/string.hxx
+++ b/sal/inc/rtl/string.hxx
@@ -91,7 +91,7 @@ namespace rtl
   use this class.
 */
 
-class OString
+class SAL_WARN_UNUSED OString
 {
 public:
     /// @cond INTERNAL
diff --git a/sal/inc/rtl/ustrbuf.hxx b/sal/inc/rtl/ustrbuf.hxx
index a11dff1..426d129 100644
--- a/sal/inc/rtl/ustrbuf.hxx
+++ b/sal/inc/rtl/ustrbuf.hxx
@@ -92,7 +92,7 @@ namespace rtl
     buffer array. If the internal buffer overflows, it is
     automatically made larger.
  */
-class OUStringBuffer
+class SAL_WARN_UNUSED OUStringBuffer
 {
 public:
     /**
diff --git a/sal/inc/rtl/ustring.hxx b/sal/inc/rtl/ustring.hxx
index e12a4b0..9756801 100644
--- a/sal/inc/rtl/ustring.hxx
+++ b/sal/inc/rtl/ustring.hxx
@@ -90,7 +90,7 @@ namespace rtl
   use this class.
 */
 
-class OUString
+class SAL_WARN_UNUSED OUString
 {
 public:
     /// @cond INTERNAL
commit 13e39545eac66b628f9ef3c89cc03d2003e5d317
Author: Luboš Luňák <l.lunak at suse.cz>
Date:   Tue Oct 9 14:50:19 2012 +0200

    compiler check for unused variables
    
    This is for variables that the compiler itself cannot figure out
    (e.g. non-trivial ctors). The classes need to be marked manually.
    
    Change-Id: I0109972e11e20578b1adc32065f701a871ee21aa

diff --git a/compilerplugins/Makefile-clang.mk b/compilerplugins/Makefile-clang.mk
index 1797e42..9b37fb9 100644
--- a/compilerplugins/Makefile-clang.mk
+++ b/compilerplugins/Makefile-clang.mk
@@ -9,7 +9,7 @@
 # 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=compileplugin.cxx unusedvariablecheck.cxx
 
 # You may occassionally want to override some of these
 
diff --git a/compilerplugins/README b/compilerplugins/README
index 98ac70c..2430d40 100644
--- a/compilerplugins/README
+++ b/compilerplugins/README
@@ -21,6 +21,13 @@ are found or explicitly using --enable-compiler-plugins.
 The compile plugin is 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]
+- unused variable 'foo' [loplugin]
+
+Additional check for unused variables.
+
 
 == Code documentation / howtos ==
 
diff --git a/compilerplugins/clang/compileplugin.cxx b/compilerplugins/clang/compileplugin.cxx
index fb2632e..2b16475 100644
--- a/compilerplugins/clang/compileplugin.cxx
+++ b/compilerplugins/clang/compileplugin.cxx
@@ -17,6 +17,8 @@
 #include <clang/Frontend/FrontendPluginRegistry.h>
 #include <clang/Rewrite/Rewriter.h>
 
+#include "unusedvariablecheck.hxx"
+
 using namespace clang;
 
 namespace loplugin
@@ -31,12 +33,14 @@ class PluginHandler
     public:
         explicit PluginHandler( ASTContext& context )
             : rewriter( context.getSourceManager(), context.getLangOpts())
+            , unusedVariableCheck( context )
             {
             }
         virtual void HandleTranslationUnit( ASTContext& context )
             {
             if( context.getDiagnostics().hasErrorOccurred())
                 return;
+            unusedVariableCheck.run();
             // TODO also LO header files? or a subdir?
            if( const RewriteBuffer* buf = rewriter.getRewriteBufferFor( context.getSourceManager().getMainFileID()))
                 buf->write( llvm::outs());
@@ -44,6 +48,7 @@ class PluginHandler
             }
     private:
         Rewriter rewriter;
+        UnusedVariableCheck unusedVariableCheck;
     };
 
 /**
diff --git a/compilerplugins/clang/unusedvariablecheck.cxx b/compilerplugins/clang/unusedvariablecheck.cxx
new file mode 100644
index 0000000..029e637
--- /dev/null
+++ b/compilerplugins/clang/unusedvariablecheck.cxx
@@ -0,0 +1,112 @@
+/*
+ * 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 "unusedvariablecheck.hxx"
+
+#include <clang/Basic/SourceManager.h>
+
+using namespace clang;
+
+namespace loplugin
+{
+
+/*
+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
+the ctor may call further functions, but an unused std::string variable
+does nothing. On the other hand, std::auto_ptr instances are used
+for their dtors and so are not unused even if not otherwise accessed.
+
+Classes which are safe to be warned about need to be marked using
+SAL_WARN_UNUSED (see e.g. OUString). For external classes such as std::vector
+that cannot be edited there is a manual list below.
+*/
+
+UnusedVariableCheck::UnusedVariableCheck( ASTContext& context )
+    : context( context )
+    {
+    }
+
+void UnusedVariableCheck::run()
+    {
+    TraverseDecl( context.getTranslationUnitDecl());
+    }
+
+DiagnosticBuilder UnusedVariableCheck::report( DiagnosticsEngine::Level level, StringRef message, SourceLocation loc )
+    {
+    // Do some mappings (e.g. for -Werror) that clang does not do for custom messages for some reason.
+    DiagnosticsEngine& diag = context.getDiagnostics();
+    if( level == DiagnosticsEngine::Warning && diag.getWarningsAsErrors())
+        level = DiagnosticsEngine::Error;
+    if( level == DiagnosticsEngine::Error && diag.getErrorsAsFatal())
+        level = DiagnosticsEngine::Fatal;
+    return diag.Report( loc, diag.getCustomDiagID( level, message ));
+    }
+
+bool UnusedVariableCheck::VisitNamedDecl( NamedDecl* declaration )
+    {
+    // TODO also LO header files? or a subdir?
+    if( !context.getSourceManager().isFromMainFile( declaration->getLocStart()))
+        return true;
+    if( !isa< VarDecl >( declaration ))
+        return true;
+    const VarDecl* var = cast< VarDecl >( declaration );
+    if( var->isReferenced() || var->isUsed())
+        return true;
+    if( CXXRecordDecl* type = var->getType()->getAsCXXRecordDecl())
+        {
+        bool warn_unused = false;
+        if( type->hasAttrs())
+            {
+            // Clang currently has no support for custom attributes, but
+            // the annotate attribute comes close, so check for __attribute__((annotate("lo_warn_unused")))
+            for( specific_attr_iterator<AnnotateAttr> i = type->specific_attr_begin<AnnotateAttr>(),
+                    e = type->specific_attr_end<AnnotateAttr>();
+                 i != e;
+                 ++i )
+                {
+                if( (*i)->getAnnotation() == "lo_warn_unused" )
+                    {
+                    warn_unused = true;
+                    break;
+                    }
+                }
+            }
+        if( !warn_unused )
+            {
+            std::string n = type->getQualifiedNameAsString();
+            // Check some common non-LO types.
+            if( n == "std::string" || n == "std::basic_string"
+                || n == "std::list" || n == "std::__debug::list"
+                || n == "std::vector" || n == "std::__debug::vector" )
+                warn_unused = true;
+            }
+        if( warn_unused )
+            {
+            if( const ParmVarDecl* param = dyn_cast< ParmVarDecl >( var ))
+                {
+                // If this declaration does not have a body, then the parameter is indeed not used,
+                // so ignore.
+                if( const FunctionDecl* func = dyn_cast< FunctionDecl >( param->getParentFunctionOrMethod()))
+                    if( !func->doesThisDeclarationHaveABody())
+                        return true;
+                report( DiagnosticsEngine::Warning, "unused parameter %0 [loplugin]",
+                    var->getLocStart()) << var->getDeclName();
+                }
+            else
+                report( DiagnosticsEngine::Warning, "unused variable %0 [loplugin]",
+                    var->getLocStart()) << var->getDeclName();
+            }
+        }
+    return true;
+    }
+
+} // namespace
diff --git a/compilerplugins/clang/unusedvariablecheck.hxx b/compilerplugins/clang/unusedvariablecheck.hxx
new file mode 100644
index 0000000..c49532a
--- /dev/null
+++ b/compilerplugins/clang/unusedvariablecheck.hxx
@@ -0,0 +1,35 @@
+/*
+ * 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 UNUSEDVARIABLECHECK_H
+#define UNUSEDVARIABLECHECK_H
+
+#include <clang/AST/RecursiveASTVisitor.h>
+
+using namespace clang;
+
+namespace loplugin
+{
+
+class UnusedVariableCheck
+    : public RecursiveASTVisitor< UnusedVariableCheck >
+    {
+    public:
+        explicit UnusedVariableCheck( ASTContext& context );
+        void run();
+        bool VisitNamedDecl( NamedDecl* declaration );
+    private:
+        DiagnosticBuilder report( DiagnosticsEngine::Level level, StringRef message, SourceLocation loc );
+        ASTContext& context;
+    };
+
+} // namespace
+
+#endif // UNUSEDVARIABLECHECK_H
diff --git a/sal/inc/sal/types.h b/sal/inc/sal/types.h
index f97ecc7..0baf3d1 100644
--- a/sal/inc/sal/types.h
+++ b/sal/inc/sal/types.h
@@ -489,6 +489,26 @@ template< typename T1, typename T2 > inline T1 static_int_cast(T2 n) {
 #endif
 #endif
 
+/**
+
+ Annotate classes where a compiler should warn if an instance is unused.
+
+ The compiler cannot warn about unused instances if they have non-trivial
+ or external constructors or destructors. Classes marked with SAL_WARN_UNUSED
+ will be warned about.
+
+ Currently implemented by a Clang compiler plugin.
+
+ @since LibreOffice 3.7
+
+*/
+
+#if defined __clang__
+#define SAL_WARN_UNUSED __attribute__((annotate("lo_warn_unused")))
+#else
+#define SAL_WARN_UNUSED
+#endif
+
 #endif /*_SAL_TYPES_H_ */
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
commit 02a8d36ebf3d54784903f2899eafe010bedf2f4c
Author: Luboš Luňák <l.lunak at suse.cz>
Date:   Fri Oct 5 18:17:13 2012 +0200

    initial support for clang compiler plugins
    
    The plugin is intentionally built using a custom Makefile,
    because it's used by gbuild, so I don't want to build the plugin
    using gbuild too. It is also intentionally not placed under workdir/,
    as that is cleaned by 'make clean', the plugin is cleaned only
    by 'make distclean', so that cleaning it doesn't cause ccache misses.
    No actual functionality in the plugin itself yet.
    
    Change-Id: Ic05eba8d6260eec123c9e699eb5385abfe1b832f

diff --git a/Makefile.top b/Makefile.top
index e5bd89d..d8bde50 100644
--- a/Makefile.top
+++ b/Makefile.top
@@ -351,10 +351,12 @@ ifeq ($(CROSS_COMPILING),YES)
 	rm -rf $(SRCDIR)/*/$(INPATH_FOR_BUILD)
 endif
 
+include $(SRCDIR)/compilerplugins/Makefile.mk
+
 #
 # Distclean
 #
-distclean : clean
+distclean : clean compilerplugins-clean
 ifeq ($(BUILD_DMAKE),YES)
 	(if [ -f dmake/Makefile ] ; then $(GNUMAKE) -j $(GMAKE_PARALLELISM) -C dmake distclean; fi) && \
 	rm -f solenv/*/bin/dmake*
@@ -393,7 +395,7 @@ endif
 #
 bootstrap: $(WORKDIR)/bootstrap
 
-$(WORKDIR)/bootstrap: solenv/bin/concat-deps.c
+$(WORKDIR)/bootstrap: solenv/bin/concat-deps.c compilerplugins
 	@cd $(SRCDIR) && ./bootstrap
 	@mkdir -p $(dir $@) && touch $@
 
diff --git a/compilerplugins/.gitignore b/compilerplugins/.gitignore
new file mode 100644
index 0000000..b672fde
--- /dev/null
+++ b/compilerplugins/.gitignore
@@ -0,0 +1 @@
+obj
diff --git a/compilerplugins/Makefile b/compilerplugins/Makefile
new file mode 100644
index 0000000..4281c12
--- /dev/null
+++ b/compilerplugins/Makefile
@@ -0,0 +1,23 @@
+# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*-
+#
+# This file is part of the LibreOffice project.
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+
+ifeq ($(SOLARENV),)
+ifeq ($(gb_Side),)
+gb_Side:=host
+endif
+include $(dir $(realpath $(lastword $(MAKEFILE_LIST))))../config_$(gb_Side).mk
+endif
+
+include $(SRCDIR)/compilerplugins/Makefile.mk
+
+all: build
+build: compilerplugins
+clean: compilerplugins-clean
+
+# vim: set noet sw=4 ts=4:
diff --git a/compilerplugins/Makefile-clang.mk b/compilerplugins/Makefile-clang.mk
new file mode 100644
index 0000000..1797e42
--- /dev/null
+++ b/compilerplugins/Makefile-clang.mk
@@ -0,0 +1,60 @@
+#
+# This file is part of the LibreOffice project.
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+
+# Make sure variables in this Makefile do not conflict with other variables (e.g. from gbuild).
+
+# The list of source files.
+CLANGSRC=compileplugin.cxx
+
+# You may occassionally want to override some of these
+
+# Compile flags ('make CLANGCXXFLAGS=-g' if you need to debug the plugin)
+CLANGCXXFLAGS=-O2 -Wall -g
+# The prefix where Clang resides, override to where Clang resides if using a source build.
+CLANGDIR=/usr
+# The build directory (different from CLANGDIR if using a Clang out-of-source build)
+CLANGBUILD=/usr
+
+# The uninteresting rest.
+
+# Clang headers require these.
+CLANGDEFS=-D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS -fno-rtti
+# All include locations needed.
+CLANGINCLUDES=-I$(CLANGDIR)/include -I$(CLANGDIR)/tools/clang/include -I$(CLANGBUILD)/include -I$(CLANGBUILD)/tools/clang/include
+
+CLANGINDIR=$(SRCDIR)/compilerplugins/clang
+# Cannot use $(WORKDIR), the plugin should survive even 'make clean', otherwise the rebuilt
+# plugin will cause cache misses with ccache.
+CLANGOUTDIR=$(SRCDIR)/compilerplugins/obj
+
+compilerplugins: $(CLANGOUTDIR) $(CLANGOUTDIR)/compileplugin.so
+
+compilerplugins-clean:
+	rm -rf $(CLANGOUTDIR)
+
+$(CLANGOUTDIR):
+	mkdir -p $(CLANGOUTDIR)
+
+CLANGOBJS=
+
+define clangbuildsrc
+$(3): $(2) $(SRCDIR)/compilerplugins/Makefile-clang.mk
+	$(CXX) $(CLANGCXXFLAGS) $(CLANGDEFS) $(CLANGINCLUDES) $(2) -fPIC -c -o $(3) -MMD -MT $(3) -MP -MF $(CLANGOUTDIR)/$(1).d
+
+-include $(CLANGOUTDIR)/$(1).d
+
+$(CLANGOUTDIR)/compileplugin.so: $(3)
+$(CLANGOUTDIR)/compileplugin.so: CLANGOBJS += $(3)
+endef
+
+$(foreach src, $(CLANGSRC), $(eval $(call clangbuildsrc,$(src),$(CLANGINDIR)/$(src),$(CLANGOUTDIR)/$(src:.cxx=.o))))
+
+$(CLANGOUTDIR)/compileplugin.so: $(CLANGOBJS)
+	$(CXX) -shared $(CLANGOBJS) -o $@
+
+# vim: set noet sw=4 ts=4:
diff --git a/compilerplugins/Makefile.mk b/compilerplugins/Makefile.mk
new file mode 100644
index 0000000..c3b5290
--- /dev/null
+++ b/compilerplugins/Makefile.mk
@@ -0,0 +1,32 @@
+# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*-
+#
+# This file is part of the LibreOffice project.
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+
+.PHONY: compilerplugins compilerplugins-clean
+
+ifeq ($(COMPILER_PLUGINS),)
+
+# no support
+
+compilerplugins:
+compilerplugins-clean:
+compilerplugins.clean:
+
+else
+
+ifeq ($(COM_GCC_IS_CLANG),TRUE)
+
+include $(SRCDIR)/compilerplugins/Makefile-clang.mk
+
+compilerplugins.clean: compilerplugins-clean
+
+endif
+
+endif
+
+# vim: set noet sw=4 ts=4:
diff --git a/compilerplugins/README b/compilerplugins/README
new file mode 100644
index 0000000..98ac70c
--- /dev/null
+++ b/compilerplugins/README
@@ -0,0 +1,27 @@
+Compiler plugins.
+
+== Overview ==
+
+This directory contains code for compiler plugins. These are used to perform
+additional actions during compilation (such as additional warnings) and
+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
+are found or explicitly using --enable-compiler-plugins.
+
+
+== Functionality ==
+
+=== Compile plugin ===
+
+The compile plugin is used during normal compilation to perform additional checks.
+All warnings and errors are marked '[loplugin]' in the message.
+
+
+== Code documentation / howtos ==
+
+TBD
diff --git a/compilerplugins/clang/compileplugin.cxx b/compilerplugins/clang/compileplugin.cxx
new file mode 100644
index 0000000..fb2632e
--- /dev/null
+++ b/compilerplugins/clang/compileplugin.cxx
@@ -0,0 +1,68 @@
+/*
+ * 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 "compileplugin.hxx"
+
+#include <clang/AST/ASTConsumer.h>
+#include <clang/AST/ASTContext.h>
+#include <clang/Frontend/CompilerInstance.h>
+#include <clang/Frontend/FrontendAction.h>
+#include <clang/Frontend/FrontendPluginRegistry.h>
+#include <clang/Rewrite/Rewriter.h>
+
+using namespace clang;
+
+namespace loplugin
+{
+
+/**
+ Class that manages all LO modules.
+*/
+class PluginHandler
+    : public ASTConsumer
+    {
+    public:
+        explicit PluginHandler( ASTContext& context )
+            : rewriter( context.getSourceManager(), context.getLangOpts())
+            {
+            }
+        virtual void HandleTranslationUnit( ASTContext& context )
+            {
+            if( context.getDiagnostics().hasErrorOccurred())
+                return;
+            // 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?
+            }
+    private:
+        Rewriter rewriter;
+    };
+
+/**
+ The Clang plugin class, just forwards to PluginHandler.
+*/
+class LibreOfficeAction
+    : public PluginASTAction
+    {
+    public:
+        virtual ASTConsumer* CreateASTConsumer( CompilerInstance& Compiler, StringRef InFile )
+            {
+            return new PluginHandler( Compiler.getASTContext());
+            }
+        virtual bool ParseArgs( const CompilerInstance& CI, const std::vector< std::string >& args )
+            {
+            return true;
+            }
+    };
+
+} // namespace
+
+static FrontendPluginRegistry::Add< loplugin::LibreOfficeAction > X( "loplugin", "LibreOffice compile check plugin" );
diff --git a/compilerplugins/clang/compileplugin.hxx b/compilerplugins/clang/compileplugin.hxx
new file mode 100644
index 0000000..f7d5182
--- /dev/null
+++ b/compilerplugins/clang/compileplugin.hxx
@@ -0,0 +1,14 @@
+/*
+ * 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 COMPILEPLUGIN_H
+#define COMPILEPLUGIN_H
+
+#endif // COMPILEPLUGIN_H
diff --git a/config_host.mk.in b/config_host.mk.in
index 605d701..5c0dcf2 100644
--- a/config_host.mk.in
+++ b/config_host.mk.in
@@ -71,6 +71,7 @@ export COMMONS_HTTPCLIENT_JAR=@COMMONS_HTTPCLIENT_JAR@
 export COMMONS_LANG_JAR=@COMMONS_LANG_JAR@
 export COMMONS_LOGGING_JAR=@COMMONS_LOGGING_JAR@
 export COMPATH=@COMPATH@
+export COMPILER_PLUGINS=@COMPILER_PLUGINS@
 export COMP_ENV=@OUTPATH@
 export COM_FOR_BUILD=@COM_FOR_BUILD@
 export CPPUNIT_CFLAGS=@CPPUNIT_CFLAGS@
diff --git a/configure.in b/configure.in
index 5d37a66..8b29eb3 100644
--- a/configure.in
+++ b/configure.in
@@ -791,6 +791,11 @@ AC_ARG_ENABLE(dbgutil,
          It is not possible to mix object files or libraries from a
          --enable-dbgutil and a --disable-dbgutil build.]))
 
+AC_ARG_ENABLE(compiler-plugins,
+    AS_HELP_STRING([--enable-compiler-plugins],
+        [Enable compiler plugins that will perform additional checks during
+         building. Enabled automatically by --enable-dbgutil.]))
+
 AC_ARG_ENABLE(linkoo,
     AS_HELP_STRING([--disable-linkoo],
         [Disable linkoo for the smoketest installation.]))
@@ -5024,6 +5029,40 @@ fi
 AC_SUBST([VALGRIND_CFLAGS])
 
 dnl ===================================================================
+dnl Compiler plugins
+dnl ===================================================================
+
+COMPILER_PLUGINS=
+# currently only Clang
+if test "$COM_GCC_IS_CLANG" = "TRUE"; then
+    if test -n "$enable_compiler_plugins"; then
+        compiler_plugins="$enable_compiler_plugins"
+    elif test -n "$enable_dbgutil" -a "$enable_dbgutil" != "no"; then
+        compiler_plugins=test
+    else
+        compiler_plugins=no
+    fi
+    if test "$compiler_plugins" != "no"; then
+        AC_LANG_PUSH([C++])
+        save_CPPFLAGS=$CPPFLAGS
+        CPPFLAGS="$CPPFLAGS -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS"
+        AC_CHECK_HEADER(clang/AST/RecursiveASTVisitor.h,
+            [COMPILER_PLUGINS=TRUE],
+            [
+            if test "$compiler_plugins" = "yes"; then
+                AC_MSG_ERROR([Cannot find Clang headers to build compiler plugins.])
+            else
+                AC_MSG_WARN([Cannot find Clang headers to build compiler plugins, plugins disabled])
+                add_warning "Cannot find Clang headers to build compiler plugins, plugins disabled."
+            fi
+            ])
+        CPPFLAGS=$save_CPPFLAGS
+        AC_LANG_POP([C++])
+    fi
+fi
+AC_SUBST(COMPILER_PLUGINS)
+
+dnl ===================================================================
 dnl Set the MinGW sys-root
 dnl ===================================================================
 if test "$WITH_MINGW" = "yes"; then
diff --git a/solenv/gbuild/platform/com_GCC_class.mk b/solenv/gbuild/platform/com_GCC_class.mk
index 630eed7..aa00267 100644
--- a/solenv/gbuild/platform/com_GCC_class.mk
+++ b/solenv/gbuild/platform/com_GCC_class.mk
@@ -60,6 +60,7 @@ $(call gb_Helper_abbreviate_dirs,\
 		$(if $(filter Library,$(TARGETTYPE)),$(gb_Library_LTOFLAGS)) \
 		$(if $(VISIBILITY),,$(gb_VISIBILITY_FLAGS)) \
 		$(if $(WARNINGS_NOT_ERRORS),,$(gb_CFLAGS_WERROR)) \
+		$(if $(COMPILER_PLUGINS),$(gb_COMPILER_PLUGINS)) \
 		$(T_CFLAGS) \
 		-c $(3) \
 		-o $(1) \
@@ -82,6 +83,7 @@ $(call gb_Helper_abbreviate_dirs,\
 		$(if $(filter Library,$(TARGETTYPE)),$(gb_Library_LTOFLAGS)) \
 		$(if $(VISIBILITY),,$(gb_VISIBILITY_FLAGS)) \
 		$(if $(WARNINGS_NOT_ERRORS),,$(gb_CXXFLAGS_WERROR)) \
+		$(if $(COMPILER_PLUGINS),$(gb_COMPILER_PLUGINS)) \
 		$(T_CXXFLAGS) \
 		-c $(3) \
 		-o $(1) \
diff --git a/solenv/gbuild/platform/com_GCC_defs.mk b/solenv/gbuild/platform/com_GCC_defs.mk
index 1e349f0..0cc32b5 100644
--- a/solenv/gbuild/platform/com_GCC_defs.mk
+++ b/solenv/gbuild/platform/com_GCC_defs.mk
@@ -153,6 +153,12 @@ gb_DEBUG_CXXFLAGS := $(FNO_DEFAULT_INLINE)
 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
+else
+gb_COMPILER_PLUGINS :=
+endif
+
 # Executable class
 
 gb_Executable_EXT_for_build :=


More information about the Libreoffice-commits mailing list