1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
7 * This file is distributed under the University of Illinois Open Source
8 * License. See LICENSE.TXT for details.
12 #include "postfixincrementfix.hxx"
17 Change all postfix ++ operators of non-trivial types to prefix if possible.
23 PostfixIncrementFix::PostfixIncrementFix( const InstantiationData
& data
)
24 : FilteringRewritePlugin( data
)
28 void PostfixIncrementFix::run()
30 TraverseDecl( compiler
.getASTContext().getTranslationUnitDecl());
33 bool PostfixIncrementFix::VisitCXXOperatorCallExpr( const CXXOperatorCallExpr
* op
)
35 if( ignoreLocation( op
))
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.
44 void PostfixIncrementFix::fixPostfixOperator( const CXXOperatorCallExpr
* op
)
46 if( !canChangePostfixToPrefix( op
, op
))
48 if( !shouldDoChange( op
->getArg( 0 )))
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
);
62 // check if foo++ can be safely replaced by ++foo
63 switch( parent
->getStmtClass())
65 case Stmt::CompoundStmtClass
:
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
:
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
;
97 report( DiagnosticsEngine::Fatal
, "cannot analyze operator++ (plugin needs fixing)",
98 op
->getLocStart()) << parent
->getSourceRange();
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
:
119 report( DiagnosticsEngine::Fatal
, "cannot analyze operator++ (plugin needs fixing)",
120 expr
->getLocStart()) << operand
->getSourceRange();
128 static Plugin::Registration
< PostfixIncrementFix
> X( "postfixincrementfix" );
132 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */