check accessiblity of parameter and return types, fixes bug 433290
authorJuerg Billeter <j@bitron.ch>
Sat, 22 Mar 2008 20:17:22 +0000 (20:17 +0000)
committerJürg Billeter <juergbi@src.gnome.org>
Sat, 22 Mar 2008 20:17:22 +0000 (20:17 +0000)
2008-03-22  Juerg Billeter  <j@bitron.ch>

* vala/valascope.vala, vala/valasemanticanalyzer.vala,
  vala/valasymbol.vala: check accessiblity of parameter and return
  types, fixes bug 433290

svn path=/trunk/; revision=1148

ChangeLog
vala/valascope.vala
vala/valasemanticanalyzer.vala
vala/valasymbol.vala

index f92435f..c33dcb0 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,9 @@
+2008-03-22  Jürg Billeter  <j@bitron.ch>
+
+       * vala/valascope.vala, vala/valasemanticanalyzer.vala,
+         vala/valasymbol.vala: check accessiblity of parameter and return
+         types, fixes bug 433290
+
 2008-03-21  Jürg Billeter  <j@bitron.ch>
 
        * vapi/Makefile.am, vapi/sdl-gfx.vapi, vapi/sdl-image.vapi,
index 8bd9a30..a223ba4 100644 (file)
@@ -1,6 +1,6 @@
 /* valascope.vala
  *
- * Copyright (C) 2006-2007  Jürg Billeter
+ * Copyright (C) 2006-2008  Jürg Billeter
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -86,5 +86,29 @@ public class Vala.Scope : Object {
                }
                return sym;
        }
+
+       /**
+        * Returns whether the specified scope is an ancestor of this scope.
+        *
+        * @param scope a scope or null for the root scope
+        * @return      true if this scope is a subscope of the specified
+        *              scope, false otherwise
+        */
+       public bool is_subscope_of (Scope? scope) {
+               if (scope == this) {
+                       return true;
+               }
+
+               // null scope is the root scope
+               if (scope == null) {
+                       return true;
+               }
+
+               if (parent_scope != null) {
+                       return parent_scope.is_subscope_of (scope);
+               }
+
+               return false;
+       }
 }
 
index 257ea83..45257a0 100644 (file)
@@ -411,6 +411,13 @@ public class Vala.SemanticAnalyzer : CodeVisitor {
                        }
                }
 
+               // check whether return type is at least as accessible as the method
+               if (!is_type_accessible (m, m.return_type)) {
+                       m.error = true;
+                       Report.error (m.source_reference, "return type `%s` is less accessible than method `%s`".printf (m.return_type.to_string (), m.get_full_name ()));
+                       return;
+               }
+
                foreach (Expression precondition in m.get_preconditions ()) {
                        if (precondition.error) {
                                // if there was an error in the precondition, skip this check
@@ -519,6 +526,13 @@ public class Vala.SemanticAnalyzer : CodeVisitor {
                                current_source_file.add_type_dependency (p.type_reference, SourceFileDependencyType.HEADER_SHALLOW);
                        }
                        current_source_file.add_type_dependency (p.type_reference, SourceFileDependencyType.SOURCE);
+
+                       // check whether parameter type is at least as accessible as the method
+                       if (!is_type_accessible (p, p.type_reference)) {
+                               p.error = true;
+                               Report.error (p.source_reference, "parameter type `%s` is less accessible than method `%s`".printf (p.type_reference.to_string (), p.parent_symbol.get_full_name ()));
+                               return;
+                       }
                }
 
                /* special treatment for construct formal parameters used in creation methods */
@@ -537,6 +551,20 @@ public class Vala.SemanticAnalyzer : CodeVisitor {
                }
        }
 
+       // check whether type is at least as accessible as the specified symbol
+       private bool is_type_accessible (Symbol sym, DataType type) {
+               foreach (Symbol type_symbol in type.get_symbols ()) {
+                       Scope method_scope = sym.get_top_accessible_scope ();
+                       Scope type_scope = type_symbol.get_top_accessible_scope ();
+                       if ((method_scope == null && type_scope != null)
+                           || (method_scope != null && !method_scope.is_subscope_of (type_scope))) {
+                               return false;
+                       }
+               }
+
+               return true;
+       }
+
        private void find_base_class_property (Property! prop, Class! cl) {
                var sym = cl.scope.lookup (prop.name);
                if (sym is Property) {
index 3883ceb..a63b96d 100644 (file)
@@ -218,6 +218,28 @@ public abstract class Vala.Symbol : CodeNode {
                
                return result.str;
        }
+
+       // get the top scope from where this symbol is still accessible
+       public Scope? get_top_accessible_scope () {
+               if (access != SymbolAccessibility.PUBLIC) {
+                       // private symbols are accessible within the scope where the symbol has been declared
+                       Scope scope = owner;
+
+                       // skip scopes of normal namespaces, they don't influence accessibility
+                       while (scope != null && scope.owner is Namespace && scope.owner.name != null) {
+                               scope = scope.parent_scope;
+                       }
+
+                       return scope;
+               }
+
+               if (parent_symbol == null) {
+                       return null;
+               }
+
+               // if this is a public symbol, it's equally accessible as the parent symbol
+               return parent_symbol.get_top_accessible_scope ();
+       }
 }
 
 public enum Vala.SymbolAccessibility {