//===--- LexicallyOrderedRecursiveASTVisitor.h - ----------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This file defines the LexicallyOrderedRecursiveASTVisitor interface, which // recursively traverses the entire AST in a lexical order. // //===----------------------------------------------------------------------===// #ifndef LLVM_CLANG_AST_LEXICALLY_ORDERED_RECURSIVEASTVISITOR_H #define LLVM_CLANG_AST_LEXICALLY_ORDERED_RECURSIVEASTVISITOR_H #include "clang/AST/RecursiveASTVisitor.h" #include "clang/Basic/LLVM.h" #include "clang/Basic/SourceManager.h" #include "llvm/Support/SaveAndRestore.h" namespace clang { /// A RecursiveASTVisitor subclass that guarantees that AST traversal is /// performed in a lexical order (i.e. the order in which declarations are /// written in the source). /// /// RecursiveASTVisitor doesn't guarantee lexical ordering because there are /// some declarations, like Objective-C @implementation declarations /// that might be represented in the AST differently to how they were written /// in the source. /// In particular, Objective-C @implementation declarations may contain /// non-Objective-C declarations, like functions: /// /// @implementation MyClass /// /// - (void) method { } /// void normalFunction() { } /// /// @end /// /// Clang's AST stores these declarations outside of the @implementation /// declaration, so the example above would be represented using the following /// AST: /// |-ObjCImplementationDecl ... MyClass /// | `-ObjCMethodDecl ... method /// | ... /// `-FunctionDecl ... normalFunction /// ... /// /// This class ensures that these declarations are traversed before the /// corresponding TraverseDecl for the @implementation returns. This ensures /// that the lexical parent relationship between these declarations and the /// @implementation is preserved while traversing the AST. Note that the /// current implementation doesn't mix these declarations with the declarations /// contained in the @implementation, so the traversal of all of the /// declarations in the @implementation still doesn't follow the lexical order. template class LexicallyOrderedRecursiveASTVisitor : public RecursiveASTVisitor { using BaseType = RecursiveASTVisitor; public: LexicallyOrderedRecursiveASTVisitor(const SourceManager &SM) : SM(SM) {} bool TraverseObjCImplementationDecl(ObjCImplementationDecl *D) { // Objective-C @implementation declarations should not trigger early exit // until the additional decls are traversed as their children are not // lexically ordered. bool Result = BaseType::TraverseObjCImplementationDecl(D); return TraverseAdditionalLexicallyNestedDeclarations() ? Result : false; } bool TraverseObjCCategoryImplDecl(ObjCCategoryImplDecl *D) { bool Result = BaseType::TraverseObjCCategoryImplDecl(D); return TraverseAdditionalLexicallyNestedDeclarations() ? Result : false; } bool TraverseDeclContextHelper(DeclContext *DC) { if (!DC) return true; for (auto I = DC->decls_begin(), E = DC->decls_end(); I != E;) { Decl *Child = *I; if (BaseType::canIgnoreChildDeclWhileTraversingDeclContext(Child)) { ++I; continue; } if (!isa(Child) && !isa(Child)) { if (!BaseType::getDerived().TraverseDecl(Child)) return false; ++I; continue; } // Gather declarations that follow the Objective-C implementation // declarations but are lexically contained in the implementation. LexicallyNestedDeclarations.clear(); for (++I; I != E; ++I) { Decl *Sibling = *I; if (!SM.isBeforeInTranslationUnit(Sibling->getLocStart(), Child->getLocEnd())) break; if (!BaseType::canIgnoreChildDeclWhileTraversingDeclContext(Sibling)) LexicallyNestedDeclarations.push_back(Sibling); } if (!BaseType::getDerived().TraverseDecl(Child)) return false; } return true; } Stmt::child_range getStmtChildren(Stmt *S) { return S->children(); } SmallVector getStmtChildren(CXXOperatorCallExpr *CE) { SmallVector Children(CE->children()); bool Swap; // Switch the operator and the first operand for all infix and postfix // operations. switch (CE->getOperator()) { case OO_Arrow: case OO_Call: case OO_Subscript: Swap = true; break; case OO_PlusPlus: case OO_MinusMinus: // These are postfix unless there is exactly one argument. Swap = Children.size() != 2; break; default: Swap = CE->isInfixBinaryOp(); break; } if (Swap && Children.size() > 1) std::swap(Children[0], Children[1]); return Children; } private: bool TraverseAdditionalLexicallyNestedDeclarations() { // FIXME: Ideally the gathered declarations and the declarations in the // @implementation should be mixed and sorted to get a true lexical order, // but right now we only care about getting the correct lexical parent, so // we can traverse the gathered nested declarations after the declarations // in the decl context. assert(!BaseType::getDerived().shouldTraversePostOrder() && "post-order traversal is not supported for lexically ordered " "recursive ast visitor"); for (Decl *D : LexicallyNestedDeclarations) { if (!BaseType::getDerived().TraverseDecl(D)) return false; } return true; } const SourceManager &SM; llvm::SmallVector LexicallyNestedDeclarations; }; } // end namespace clang #endif // LLVM_CLANG_AST_LEXICALLY_ORDERED_RECURSIVEASTVISITOR_H