Make recursive methods in Type work with cyclic AST

Fixes Type::canCheckEquality, Type::needsResolveReferences,
Type::isJavaCompatible, Type:containsPointer.

Adds set of visited Types to these functions to prevent
infinite recursion.

deep versions of these functions *do not* guarantee the correct
return value, but non-deep versions do:
We need to find al least one path from requested vertex
to "bad" vertex (ie. which is not java compatible).

Fixes a bug with containsPointer (containsPointer returned true
if inner type contained a pointer), so more structures get
__attribute__ aligned and static_assert generated for
struct fields.

This change is required for forward reference, as current
implementations assume that the graph is acyclic.

Potential future work: to reduce theoretical complexity of
described actions (square to linear).

Bug: 31827278

Test: mma
Test: output not changed in
  out/soong/.intermediates/hardware/interfaces

Change-Id: I3dbdd1605f9317637241057b12de6031125abf7b
diff --git a/Interface.cpp b/Interface.cpp
index 0fcd081..2e0d931 100644
--- a/Interface.cpp
+++ b/Interface.cpp
@@ -71,9 +71,7 @@
 
 Interface::Interface(const char* localName, const FQName& fullName, const Location& location,
                      Scope* parent, const Reference<Type>& superType)
-    : Scope(localName, fullName, location, parent),
-      mSuperType(superType),
-      mIsJavaCompatibleInProgress(false) {}
+    : Scope(localName, fullName, location, parent), mSuperType(superType) {}
 
 std::string Interface::typeName() const {
     return "interface " + localName();
@@ -970,38 +968,18 @@
     return false;
 }
 
-bool Interface::isJavaCompatible() const {
-    if (mIsJavaCompatibleInProgress) {
-        // We're currently trying to determine if this Interface is
-        // java-compatible and something is referencing this interface through
-        // one of its methods. Assume we'll ultimately succeed, if we were wrong
-        // the original invocation of Interface::isJavaCompatible() will then
-        // return the correct "false" result.
-        return true;
-    }
-
-    if (superType() != nullptr && !superType()->isJavaCompatible()) {
-        mIsJavaCompatibleInProgress = false;
+bool Interface::deepIsJavaCompatible(std::unordered_set<const Type*>* visited) const {
+    if (superType() != nullptr && !superType()->isJavaCompatible(visited)) {
         return false;
     }
 
-    mIsJavaCompatibleInProgress = true;
-
-    if (!Scope::isJavaCompatible()) {
-        mIsJavaCompatibleInProgress = false;
-        return false;
-    }
-
-    for (const auto &method : methods()) {
-        if (!method->isJavaCompatible()) {
-            mIsJavaCompatibleInProgress = false;
+    for (const auto* method : methods()) {
+        if (!method->deepIsJavaCompatible(visited)) {
             return false;
         }
     }
 
-    mIsJavaCompatibleInProgress = false;
-
-    return true;
+    return Scope::isJavaCompatible(visited);
 }
 
 }  // namespace android