bump product version to 5.0.4.1
[LibreOffice.git] / compilerplugins / clang / store / postfixincrementfix.cxx
blobc4ad685918178802f7bd5d5ade6480da1abb16fd
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * Based on LLVM/Clang.
7 * This file is distributed under the University of Illinois Open Source
8 * License. See LICENSE.TXT for details.
12 #include "postfixincrementfix.hxx"
15 This is a rewriter.
17 Change all postfix ++ operators of non-trivial types to prefix if possible.
20 namespace loplugin
23 PostfixIncrementFix::PostfixIncrementFix( const InstantiationData& data )
24 : RewritePlugin( data )
28 void PostfixIncrementFix::run()
30 TraverseDecl( compiler.getASTContext().getTranslationUnitDecl());
33 bool PostfixIncrementFix::VisitCXXOperatorCallExpr( const CXXOperatorCallExpr* op )
35 if( ignoreLocation( op ))
36 return true;
37 // postfix ++ has two arguments (the operand and the hidden extra int)
38 if( op->getOperator() == OO_PlusPlus && op->getNumArgs() == 2 )
39 fixPostfixOperator( op );
40 // For primitive types it would be UnaryOperatorExpr, but probably no good reason to change those.
41 return true;
44 void PostfixIncrementFix::fixPostfixOperator( const CXXOperatorCallExpr* op )
46 if( !canChangePostfixToPrefix( op, op ))
47 return;
48 if( !shouldDoChange( op->getArg( 0 )))
49 return;
50 // Adding spaces around the moved ++ should not be necessary
51 // (there might a problem with e.g. a+b++ -> a+++b (i.e. a++ +b),
52 // but we don't change such expressions).
53 if( insertText( op->getLocStart(), "++" )) // insert is intentionally first, in case it fails
54 removeText( op->getCallee()->getSourceRange());
57 bool PostfixIncrementFix::canChangePostfixToPrefix( const Stmt* stmt , const CXXOperatorCallExpr* op )
59 const Stmt* parent = parentStmt( stmt );
60 if( parent == NULL )
61 return true;
62 // check if foo++ can be safely replaced by ++foo
63 switch( parent->getStmtClass())
65 case Stmt::CompoundStmtClass:
66 return true;
67 // these mean somebody is going to use it
68 case Stmt::ImplicitCastExprClass:
69 case Stmt::MaterializeTemporaryExprClass:
70 case Stmt::BinaryOperatorClass:
71 case Stmt::UnaryOperatorClass:
72 case Stmt::CallExprClass:
73 case Stmt::CXXOperatorCallExprClass:
74 return false;
75 case Stmt::CXXBindTemporaryExprClass:
76 // tricky, it may just mean the temporary will be cleaned up
77 // (by ExprWithCleanups), ignore and go up
78 return canChangePostfixToPrefix( parent, op );
79 case Stmt::ExprWithCleanupsClass:
80 // cleanup of a temporary, should be harmless (if the use
81 // of the postfix ++ operator here relies on the fact that
82 // the dtor for the object will be called, that's pretty insane
83 // code). Ignore and go up.
84 return canChangePostfixToPrefix( parent, op );
85 case Stmt::ParenExprClass: // parentheses, go up
86 return canChangePostfixToPrefix( parent, op );
87 case Stmt::IfStmtClass:
88 // cannot be changed in condition, can be changed in statements
89 return cast< IfStmt >( parent )->getCond() != stmt;
90 case Stmt::WhileStmtClass:
91 return cast< WhileStmt >( parent )->getCond() != stmt;
92 case Stmt::DoStmtClass:
93 return cast< DoStmt >( parent )->getCond() != stmt;
94 case Stmt::ForStmtClass:
95 return cast< ForStmt >( parent )->getCond() != stmt;
96 default:
97 report( DiagnosticsEngine::Fatal, "cannot analyze operator++ (plugin needs fixing)",
98 op->getLocStart()) << parent->getSourceRange();
99 parent->dump();
100 return false;
104 bool PostfixIncrementFix::shouldDoChange( const Expr* operand )
106 // TODO Changing 'a->b++' to '++a->b' is technically the same, but the latter probably looks confusing,
107 // so either avoid that, or add parentheses. Avoid for now.
108 const Expr* expr = const_cast< Expr* >( operand )->IgnoreImplicit(); // does not have const version
109 switch( expr->getStmtClass())
111 case Stmt::ParenExprClass:
112 return true; // there are already parentheses, ok to move the ++
113 case Stmt::MemberExprClass:
114 return false; // ++a->b , avoid
115 case Stmt::DeclRefExprClass:
116 return true;
117 default:
119 report( DiagnosticsEngine::Fatal, "cannot analyze operator++ (plugin needs fixing)",
120 expr->getLocStart()) << operand->getSourceRange();
121 expr->dump();
122 operand->dump();
123 return false;
128 static Plugin::Registration< PostfixIncrementFix > X( "postfixincrementfix" );
130 } // namespace
132 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */