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 "bodynotinblock.hxx"
18 This is a compile check.
20 Check for two statements that are both indented to look like a body of if/while/for
21 but are not inside a compound statement and thus the second one is unrelated.
29 Here either both statements should be inside {} or the second statement in indented wrong.
32 BodyNotInBlock::BodyNotInBlock( const InstantiationData
& data
)
37 void BodyNotInBlock::run()
39 TraverseDecl( compiler
.getASTContext().getTranslationUnitDecl());
42 bool BodyNotInBlock::VisitIfStmt( const IfStmt
* stmt
)
44 if( ignoreLocation( stmt
))
46 checkBody( stmt
->getThen(), stmt
->getIfLoc(), 0, stmt
->getElse() != NULL
);
47 checkBody( stmt
->getElse(), stmt
->getElseLoc(), 0 );
51 bool BodyNotInBlock::VisitWhileStmt( const WhileStmt
* stmt
)
53 if( ignoreLocation( stmt
))
55 checkBody( stmt
->getBody(), stmt
->getWhileLoc(), 1 );
59 bool BodyNotInBlock::VisitForStmt( const ForStmt
* stmt
)
61 if( ignoreLocation( stmt
))
63 checkBody( stmt
->getBody(), stmt
->getForLoc(), 2 );
67 bool BodyNotInBlock::VisitCXXForRangeStmt( const CXXForRangeStmt
* stmt
)
69 if( ignoreLocation( stmt
))
71 checkBody( stmt
->getBody(), stmt
->getForLoc(), 2 );
75 void BodyNotInBlock::checkBody( const Stmt
* body
, SourceLocation stmtLocation
, int stmtType
, bool dontGoUp
)
79 // TODO: If the if/else/while/for comes from a macro expansion, ignore it completely for
80 // now. The code below could assume everything is in the same place (and thus also column)
81 // and give a false warning. Moreover some macros are rather loosely written and would
82 // result in poor formatting. To be evaluated later, maybe this could be handled
83 // including macro expansion.
84 if( stmtLocation
.isMacroID())
86 if( dyn_cast
< CompoundStmt
>( body
))
87 return; // if body is a compound statement, then it is in {}
88 const Stmt
* previousParent
= parentStmt( body
); // Here the statement itself.
89 // Find the next statement (in source position) after 'body'.
92 const Stmt
* parent
= parentStmt( previousParent
);
95 for( ConstStmtIterator it
= parent
->child_begin();
96 it
!= parent
->child_end();
99 if( *it
== previousParent
) // found grand(grand...)parent
101 // get next statement after our (grand...)parent
103 while( it
!= parent
->child_end() && *it
== NULL
)
104 ++it
; // skip empty ones (missing 'else' bodies for example)
105 if( it
!= parent
->child_end())
107 bool invalid1
, invalid2
;
108 unsigned bodyColumn
= compiler
.getSourceManager()
109 .getPresumedColumnNumber( body
->getLocStart(), &invalid1
);
110 unsigned nextStatementColumn
= compiler
.getSourceManager()
111 .getPresumedColumnNumber( (*it
)->getLocStart(), &invalid2
);
112 if( invalid1
|| invalid2
)
114 if( bodyColumn
== nextStatementColumn
)
116 report( DiagnosticsEngine::Warning
,
117 "statement aligned as second statement in %select{if|while|for}0 body but not in a statement block",
118 (*it
)->getLocStart()) << stmtType
;
119 report( DiagnosticsEngine::Note
,
120 "%select{if|while|for}0 body statement is here",
121 body
->getLocStart()) << stmtType
;
125 // else we need to go higher to find the next statement
130 // If going up would mean leaving a {} block, stop, because the } should
131 // make it visible the two statements are not in the same body.
132 if( dyn_cast
< CompoundStmt
>( parent
))
134 // If the body to be checked is a body of an if statement that has also
135 // an else part, don't go up, the else is after the body and should make
136 // it clear the body does not continue there.
139 previousParent
= parent
;
143 static Plugin::Registration
< BodyNotInBlock
> X( "bodynotinblock" );
147 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */