From 37cc6846b832ac47c63e2bd65bfdf0caf8984edc Mon Sep 17 00:00:00 2001
From: Johannes Mey <johannes.mey@tu-dresden.de>
Date: Sat, 4 Jan 2020 21:24:24 +0100
Subject: [PATCH] detect interface hiding, albeit only interface->class, not
 for sub-interfaces (but this is prohibited by java anyway and extendj
 collects all implemented superinterfaces automatically)

---
 .../src/main/jastadd/ProgramToScopeTree.jrag  | 14 +++++++--
 .../test/java/org/extendj/InterfaceTest.java  | 30 +++++++++++++++++++
 .../src/test/resources/interface/ClassA.java  |  5 ++++
 .../test/resources/interface/InterfaceA.java  |  5 ++++
 .../test/resources/interface/InterfaceB.java  |  5 ++++
 5 files changed, 57 insertions(+), 2 deletions(-)
 create mode 100644 scope4j/src/test/java/org/extendj/InterfaceTest.java
 create mode 100644 scope4j/src/test/resources/interface/ClassA.java
 create mode 100644 scope4j/src/test/resources/interface/InterfaceA.java
 create mode 100644 scope4j/src/test/resources/interface/InterfaceB.java

diff --git a/scope4j/src/main/jastadd/ProgramToScopeTree.jrag b/scope4j/src/main/jastadd/ProgramToScopeTree.jrag
index 26f0fba..b1dc8e2 100644
--- a/scope4j/src/main/jastadd/ProgramToScopeTree.jrag
+++ b/scope4j/src/main/jastadd/ProgramToScopeTree.jrag
@@ -35,6 +35,12 @@ aspect ProgramToScopeTree {
           addInheritedScope(superDecl.asProtectedScope());
         }
       }
+      for (InterfaceDecl interfaceDecl : classDecl.implementedInterfaces()) {
+        System.out.println(classDecl.implementedInterfaces());
+        if (interfaceDecl.compilationUnit().fromSource()) {
+          addInheritedScope(interfaceDecl.asPackageScope());
+        }
+      }
     }
     super.updateInheritance();
   }
@@ -53,11 +59,11 @@ aspect ProgramToScopeTree {
   EnhancedForStmt contributes scope() when !(getStmt() instanceof Block) to ASTNode.scope() for containingScope();
 
   // collect all elements
-  Declarator contributes asDeclaration() when /* is NOT in interface || */ !isField() || isPrivate() to ASTNode.scope() for containingScope();
+  Declarator contributes asDeclaration() when !inInterface() && (!isField() || isPrivate()) to ASTNode.scope() for containingScope();
   // field which is neither private, protected, nor public -> package-private scope
   Declarator contributes asDeclaration() when isField() && !isPrivate() && !(isProtected() || isPublic()) to TypeDecl.packageScope() for containingScope();
   // field which is either protected or public -> protected scope
-  Declarator contributes asDeclaration() when /* is in interface && */ isField() && !isPrivate() && (isProtected() || isPublic()) to TypeDecl.protectedScope() for containingScope();
+  Declarator contributes asDeclaration() when isField() && !isPrivate() && (isProtected() || isPublic() || inInterface()) to TypeDecl.protectedScope() for containingScope();
   ParameterDeclaration contributes asDeclaration() to ASTNode.scope() for containingScope();
 }
 
@@ -156,4 +162,8 @@ aspect ScopeGenerationAttributes {
   // allow host package to be called from all AST nodes
   inh String ASTNode.hostPackage();
   eq Program.getCompilationUnit(int i).hostPackage() = getCompilationUnit(i).getPackageDecl();
+
+  inh boolean Declarator.inInterface();
+  eq TypeDecl.getChild().inInterface() = false;
+  eq InterfaceDecl.getChild().inInterface() = true;
 }
diff --git a/scope4j/src/test/java/org/extendj/InterfaceTest.java b/scope4j/src/test/java/org/extendj/InterfaceTest.java
new file mode 100644
index 0000000..070ac2e
--- /dev/null
+++ b/scope4j/src/test/java/org/extendj/InterfaceTest.java
@@ -0,0 +1,30 @@
+package org.extendj;
+
+import org.extendj.ast.AbstractFinding;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+import java.util.Set;
+
+public class InterfaceTest extends ScopeAnalysisTest {
+
+  @Test
+  void test() {
+
+
+    final String classA = "src/test/resources/interface/ClassA.java";
+    final String interfaceA = "src/test/resources/interface/InterfaceA.java";
+    final String interfaceB = "src/test/resources/interface/InterfaceB.java";
+    final String interfaceAorB = "src/test/resources/interface/Interface";
+
+    ScopeAnalysis scopeAnalysis = new ScopeAnalysis();
+    Set<AbstractFinding> findings = scopeAnalysis.analyze("src/test/resources/interface", true, true);
+
+    assertShadow(findings, "fieldA", classA,     2, interfaceA, 2);
+    assertShadow(findings, "fieldB", classA,     3, interfaceB, 3);
+    assertShadow(findings, "fieldC", classA, 4, interfaceAorB, 4);
+
+    Assertions.assertEquals(3, findings.size());
+  }
+
+}
diff --git a/scope4j/src/test/resources/interface/ClassA.java b/scope4j/src/test/resources/interface/ClassA.java
new file mode 100644
index 0000000..0a91b8a
--- /dev/null
+++ b/scope4j/src/test/resources/interface/ClassA.java
@@ -0,0 +1,5 @@
+public class ClassA implements InterfaceA {
+  int fieldA = 1;
+  int fieldB = 1;
+  int fieldC = 1;
+}
diff --git a/scope4j/src/test/resources/interface/InterfaceA.java b/scope4j/src/test/resources/interface/InterfaceA.java
new file mode 100644
index 0000000..481e0e6
--- /dev/null
+++ b/scope4j/src/test/resources/interface/InterfaceA.java
@@ -0,0 +1,5 @@
+public interface InterfaceA extends InterfaceB {
+  int fieldA = 1;
+
+  int fieldC = 1;
+}
diff --git a/scope4j/src/test/resources/interface/InterfaceB.java b/scope4j/src/test/resources/interface/InterfaceB.java
new file mode 100644
index 0000000..ca9fb45
--- /dev/null
+++ b/scope4j/src/test/resources/interface/InterfaceB.java
@@ -0,0 +1,5 @@
+public interface InterfaceB {
+
+  int fieldB = 2;
+  int fieldC = 2;
+}
-- 
GitLab