bump product version to 6.3.0.0.beta1
[LibreOffice.git] / compilerplugins / clang / store / bodynotinblock.cxx
blobca4f904992c87ade4cfa6d260bc1696a932c0873
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 "bodynotinblock.hxx"
14 namespace loplugin
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.
23 For example:
25 if( a != 0 )
26 b = 2;
27 c = 3;
29 Here either both statements should be inside {} or the second statement in indented wrong.
32 BodyNotInBlock::BodyNotInBlock( const InstantiationData& data )
33 : Plugin( data )
37 void BodyNotInBlock::run()
39 TraverseDecl( compiler.getASTContext().getTranslationUnitDecl());
42 bool BodyNotInBlock::VisitIfStmt( const IfStmt* stmt )
44 if( ignoreLocation( stmt ))
45 return true;
46 checkBody( stmt->getThen(), stmt->getIfLoc(), 0, stmt->getElse() != NULL );
47 checkBody( stmt->getElse(), stmt->getElseLoc(), 0 );
48 return true;
51 bool BodyNotInBlock::VisitWhileStmt( const WhileStmt* stmt )
53 if( ignoreLocation( stmt ))
54 return true;
55 checkBody( stmt->getBody(), stmt->getWhileLoc(), 1 );
56 return true;
59 bool BodyNotInBlock::VisitForStmt( const ForStmt* stmt )
61 if( ignoreLocation( stmt ))
62 return true;
63 checkBody( stmt->getBody(), stmt->getForLoc(), 2 );
64 return true;
67 bool BodyNotInBlock::VisitCXXForRangeStmt( const CXXForRangeStmt* stmt )
69 if( ignoreLocation( stmt ))
70 return true;
71 checkBody( stmt->getBody(), stmt->getForLoc(), 2 );
72 return true;
75 void BodyNotInBlock::checkBody( const Stmt* body, SourceLocation stmtLocation, int stmtType, bool dontGoUp )
77 if( body == NULL )
78 return;
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())
85 return;
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'.
90 for(;;)
92 const Stmt* parent = parentStmt( previousParent );
93 if( parent == NULL )
94 break;
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
102 ++it;
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 )
113 return;
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;
123 return;
125 // else we need to go higher to find the next statement
127 else
128 ++it;
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 ))
133 return;
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.
137 if( dontGoUp )
138 return;
139 previousParent = parent;
143 static Plugin::Registration< BodyNotInBlock > X( "bodynotinblock" );
145 } // namespace
147 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */