2 * This file is part of the LibreOffice project.
6 * This file is distributed under the University of Illinois Open Source
7 * License. See LICENSE.TXT for details.
11 #include "bodynotinblock.hxx"
17 This is a compile check.
19 Check for two statements that are both indented to look like a body of if/while/for
20 but are not inside a compound statement and thus the second one is unrelated.
28 Here either both statements should be inside {} or the second statement in indented wrong.
31 BodyNotInBlock::BodyNotInBlock( CompilerInstance
& compiler
)
36 void BodyNotInBlock::run()
38 TraverseDecl( compiler
.getASTContext().getTranslationUnitDecl());
41 bool BodyNotInBlock::VisitFunctionDecl( const FunctionDecl
* declaration
)
43 if( ignoreLocation( declaration
))
45 if( !declaration
->doesThisDeclarationHaveABody())
48 traverseStatement( declaration
->getBody(), parents
);
52 void BodyNotInBlock::traverseStatement( const Stmt
* stmt
, StmtParents
& parents
)
54 parents
.push_back( stmt
);
55 for( ConstStmtIterator it
= stmt
->child_begin();
56 it
!= stmt
->child_end();
59 if( *it
!= NULL
) // some children can be apparently NULL
61 traverseStatement( *it
, parents
); // substatements first
62 parents
.push_back( *it
);
63 if( const IfStmt
* ifstmt
= dyn_cast
< IfStmt
>( *it
))
65 checkBody( ifstmt
->getThen(), ifstmt
->getIfLoc(), parents
, 0, ifstmt
->getElse() != NULL
);
66 checkBody( ifstmt
->getElse(), ifstmt
->getElseLoc(), parents
, 0 );
68 else if( const WhileStmt
* whilestmt
= dyn_cast
< WhileStmt
>( *it
))
69 checkBody( whilestmt
->getBody(), whilestmt
->getWhileLoc(), parents
, 1 );
70 else if( const ForStmt
* forstmt
= dyn_cast
< ForStmt
>( *it
))
71 checkBody( forstmt
->getBody(), forstmt
->getForLoc(), parents
, 2 );
72 else if( const CXXForRangeStmt
* forstmt
= dyn_cast
< CXXForRangeStmt
>( *it
))
73 checkBody( forstmt
->getBody(), forstmt
->getForLoc(), parents
, 2 );
77 assert( parents
.back() == stmt
);
81 void BodyNotInBlock::checkBody( const Stmt
* body
, SourceLocation stmtLocation
, const StmtParents
& parents
,
82 int stmtType
, bool dontGoUp
)
84 if( body
== NULL
|| parents
.size() < 2 )
86 // TODO: If the if/else/while/for comes from a macro expansion, ignore it completely for
87 // now. The code below could assume everything is in the same place (and thus also column)
88 // and give a false warning. Moreover some macros are rather lousily written and would
89 // result in poor formatting. To be evaluated later, maybe this could be handled
90 // including macro expansion.
91 if( stmtLocation
.isMacroID())
93 if( dyn_cast
< CompoundStmt
>( body
))
94 return; // if body is a compound statement, then it is in {}
95 // Find the next statement (in source position) after 'body'.
96 for( int parent_pos
= parents
.size() - 2; // start from grandparent
100 for( ConstStmtIterator it
= parents
[ parent_pos
]->child_begin();
101 it
!= parents
[ parent_pos
]->child_end();
104 if( *it
== parents
[ parent_pos
+ 1 ] ) // found grand(grand...)parent
106 // get next statement after our (grand...)parent
108 while( it
!= parents
[ parent_pos
]->child_end() && *it
== NULL
)
109 ++it
; // skip empty ones (missing 'else' bodies for example)
110 if( it
!= parents
[ parent_pos
]->child_end())
112 bool invalid1
, invalid2
;
113 unsigned bodyColumn
= compiler
.getSourceManager()
114 .getPresumedColumnNumber( body
->getLocStart(), &invalid1
);
115 unsigned nextStatementColumn
= compiler
.getSourceManager()
116 .getPresumedColumnNumber( (*it
)->getLocStart(), &invalid2
);
117 if( invalid1
|| invalid2
)
119 if( bodyColumn
== nextStatementColumn
)
121 report( DiagnosticsEngine::Warning
,
122 "statement aligned as second statement in %select{if|while|for}0 body but not in a statement block",
123 (*it
)->getLocStart()) << stmtType
;
124 report( DiagnosticsEngine::Note
,
125 "%select{if|while|for}0 body statement is here",
126 body
->getLocStart()) << stmtType
;
130 // else we need to go higher to find the next statement
135 // If going up would mean leaving a {} block, stop, because the } should
136 // make it visible the two statements are not in the same body.
137 if( dyn_cast
< CompoundStmt
>( parents
[ parent_pos
] ))
139 // If the body to be checked is a body of an if statement that has also
140 // an else part, don't go up, the else is after the body and should make
141 // it clear the body does not continue there.
147 static Plugin::Registration
< BodyNotInBlock
> X( "bodynotinblock" );