summaryrefslogtreecommitdiff
path: root/compilerplugins
diff options
context:
space:
mode:
authorLuboš Luňák <l.lunak@suse.cz>2013-05-06 16:33:16 +0200
committerLuboš Luňák <l.lunak@suse.cz>2013-05-06 16:51:45 +0200
commitd870271c23b997c922ddf2672df8f69fd199eef7 (patch)
tree29ba558443c2338c04f461346b412198903f0ef4 /compilerplugins
parente2e2cc61144cb22227eebfadff0ea24b51ccfbd0 (diff)
compiler plugin for RTL_CONSTASCII_USTRINGPARAM removal
Change-Id: Ibc487aa78d9eba3f936b4f4cc0298adfaef60d5c
Diffstat (limited to 'compilerplugins')
-rw-r--r--compilerplugins/clang/rtlconstasciimacro.cxx140
1 files changed, 140 insertions, 0 deletions
diff --git a/compilerplugins/clang/rtlconstasciimacro.cxx b/compilerplugins/clang/rtlconstasciimacro.cxx
new file mode 100644
index 000000000000..f1a9d0256c96
--- /dev/null
+++ b/compilerplugins/clang/rtlconstasciimacro.cxx
@@ -0,0 +1,140 @@
+/*
+ * 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.
+ *
+ */
+
+/*
+This is a rewriter.
+
+Remove uses of the macro RTL_CONSTASCII_USTRINGPARAM. One run is for one
+specific use (see below), modify source to remove other uses.
+*/
+
+#include "plugin.hxx"
+
+#include <clang/Lex/Preprocessor.h>
+
+namespace loplugin
+{
+
+class RtlConstAsciiMacro
+ : public RecursiveASTVisitor< RtlConstAsciiMacro >
+ , public PPCallbacks
+ , public RewritePlugin
+ {
+ public:
+ explicit RtlConstAsciiMacro( CompilerInstance& compiler, Rewriter& rewriter );
+ virtual void run();
+ bool VisitCXXConstructExpr( CXXConstructExpr* expr );
+ bool VisitCXXTemporaryObjectExpr( CXXTemporaryObjectExpr* expr );
+ bool VisitStringLiteral( const StringLiteral* literal );
+ virtual void MacroExpands( const Token& macro, const MacroInfo* info, SourceRange range );
+ private:
+ map< SourceLocation, SourceLocation > expansions; // start location -> end location
+ bool searchingForString;
+ bool suitableString;
+ };
+
+RtlConstAsciiMacro::RtlConstAsciiMacro( CompilerInstance& compiler, Rewriter& rewriter )
+ : RewritePlugin( compiler, rewriter )
+ , searchingForString( false )
+ {
+ compiler.getPreprocessor().addPPCallbacks( this );
+ }
+
+void RtlConstAsciiMacro::run()
+ {
+ TraverseDecl( compiler.getASTContext().getTranslationUnitDecl());
+ }
+
+
+void RtlConstAsciiMacro::MacroExpands( const Token& macro, const MacroInfo*, SourceRange range )
+ {
+ if( macro.getIdentifierInfo()->getName() != "RTL_CONSTASCII_USTRINGPARAM" )
+ return;
+ expansions[ range.getBegin() ] = range.getEnd();
+ }
+
+/* Remove use with the following ctor:
+ OUString( const sal_Char * value, sal_Int32 length,
+ rtl_TextEncoding encoding,
+ sal_uInt32 convertFlags = OSTRING_TO_OUSTRING_CVTFLAGS )
+ This means searching for CXXConstructExpr.
+ For removal when used with functions it should check e.g. for CallExpr.
+*/
+bool RtlConstAsciiMacro::VisitCXXConstructExpr( CXXConstructExpr* expr )
+ {
+ if( ignoreLocation( expr ))
+ return true;
+ if( expr->getNumArgs() != 4 )
+ return true;
+ // The last argument should be the default one when the macro is used.
+ if( dyn_cast< CXXDefaultArgExpr >( expr->getArg( 3 )) == NULL )
+ return true;
+ if( expr->getConstructor()->getQualifiedNameAsString() != "rtl::OUString::OUString" )
+ return true;
+ const SourceManager& src = compiler.getSourceManager();
+ SourceLocation start = src.getExpansionLoc( expr->getArg( 0 )->getLocStart());
+ // Macro fills in the first 3 arguments, so they must all come from the same expansion.
+ if( start != src.getExpansionLoc( expr->getArg( 2 )->getLocEnd()))
+ return true;
+ if( expansions.find( start ) == expansions.end())
+ return true;
+ SourceLocation end = expansions[ start ];
+ // Remove the location, since sometimes the same code may be processed more than once
+ // (e.g. non-trivial default arguments).
+ expansions.erase( start );
+ // Check if the string argument to the macro is suitable.
+ searchingForString = true;
+ suitableString = false;
+ TraverseStmt( expr->getArg( 0 ));
+ searchingForString = false;
+ if( !suitableString )
+ return true;
+ // Seach for '(' (don't just remove a given length to handle possible whitespace).
+ const char* text = compiler.getSourceManager().getCharacterData( start );
+ const char* pos = text;
+ while( *pos != '(' )
+ ++pos;
+ ++pos;
+ if( text[ -1 ] == ' ' && *pos == ' ' )
+ ++pos; // do not leave two spaces
+ removeText( start, pos - text, RemoveLineIfEmpty );
+ const char* textend = compiler.getSourceManager().getCharacterData( end );
+ if( textend[ -1 ] == ' ' && textend[ 1 ] == ' ' )
+ removeText( end, 2, RemoveLineIfEmpty ); // Remove ') '.
+ else
+ removeText( end, 1, RemoveLineIfEmpty ); // Remove ')'.
+ return true;
+ }
+
+bool RtlConstAsciiMacro::VisitCXXTemporaryObjectExpr( CXXTemporaryObjectExpr* expr )
+ {
+ return VisitCXXConstructExpr( expr );
+ }
+
+bool RtlConstAsciiMacro::VisitStringLiteral( const StringLiteral* literal )
+ {
+ if( !searchingForString )
+ return true;
+ if( suitableString ) // two string literals?
+ {
+ report( DiagnosticsEngine::Warning, "cannot analyze RTL_CONSTASCII_USTRINGPARAM (plugin needs fixing)" )
+ << literal->getSourceRange();
+ return true;
+ }
+ if( !literal->isAscii()) // ignore
+ return true;
+ if( !literal->containsNonAsciiOrNull())
+ suitableString = true;
+ return true;
+ }
+
+static Plugin::Registration< RtlConstAsciiMacro > X( "rtlconstasciimacro" );
+
+} // namespace