summaryrefslogtreecommitdiff
path: root/include/clang/AST/LexicallyOrderedRecursiveASTVisitor.h
diff options
context:
space:
mode:
Diffstat (limited to 'include/clang/AST/LexicallyOrderedRecursiveASTVisitor.h')
-rw-r--r--include/clang/AST/LexicallyOrderedRecursiveASTVisitor.h164
1 files changed, 164 insertions, 0 deletions
diff --git a/include/clang/AST/LexicallyOrderedRecursiveASTVisitor.h b/include/clang/AST/LexicallyOrderedRecursiveASTVisitor.h
new file mode 100644
index 0000000000000..264f20f19ad5b
--- /dev/null
+++ b/include/clang/AST/LexicallyOrderedRecursiveASTVisitor.h
@@ -0,0 +1,164 @@
+//===--- 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 <typename Derived>
+class LexicallyOrderedRecursiveASTVisitor
+ : public RecursiveASTVisitor<Derived> {
+ using BaseType = RecursiveASTVisitor<Derived>;
+
+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<ObjCImplementationDecl>(Child) &&
+ !isa<ObjCCategoryImplDecl>(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<Stmt *, 8> getStmtChildren(CXXOperatorCallExpr *CE) {
+ SmallVector<Stmt *, 8> 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<Decl *, 8> LexicallyNestedDeclarations;
+};
+
+} // end namespace clang
+
+#endif // LLVM_CLANG_AST_LEXICALLY_ORDERED_RECURSIVEASTVISITOR_H