This is an automated email from the ASF dual-hosted git repository.

joshtynjala pushed a commit to branch develop
in repository https://gitbox.apache.org/repos/asf/royale-compiler.git


The following commit(s) were added to refs/heads/develop by this push:
     new 62d8ba6  optional private constructors (closes #82)
62d8ba6 is described below

commit 62d8ba6a093d5ec20abfa49b38c2f9aae0479376
Author: Josh Tynjala <[email protected]>
AuthorDate: Thu Apr 25 11:01:10 2019 -0700

    optional private constructors (closes #82)
    
    Enable with --allow-private-constructors compiler option. When enabled, 
constructors may be private instead of public and classes with private 
constructors cannot be instantiated outside of their parent class at compile 
time.
---
 .../royale/compiler/config/Configuration.java      |  22 +
 .../royale/compiler/projects/ICompilerProject.java |   7 +-
 .../constants/IMetaAttributeConstants.java         |   4 +
 .../as/codegen/ClassDirectiveProcessor.java        |  19 +-
 .../internal/definitions/ClassDefinition.java      |  10 +
 .../internal/definitions/FunctionDefinition.java   |  23 +
 .../internal/parsing/as/ConfigProcessor.java       |   6 +
 .../compiler/internal/projects/ASCProject.java     |   6 +
 .../compiler/internal/projects/RoyaleProject.java  |  15 +
 .../projects/RoyaleProjectConfigurator.java        |   1 +
 .../semantics/MethodBodySemanticChecker.java       |  65 ++-
 .../compiler/internal/tree/as/FunctionNode.java    |  44 +-
 .../ConstructorMustBePublicOrPrivateProblem.java   |  42 ++
 .../InaccessibleConstructorReferenceProblem.java   |  43 ++
 .../test/java/as/ASPrivateConstructorTests.java    | 631 +++++++++++++++++++++
 15 files changed, 925 insertions(+), 13 deletions(-)

diff --git 
a/compiler-common/src/main/java/org/apache/royale/compiler/config/Configuration.java
 
b/compiler-common/src/main/java/org/apache/royale/compiler/config/Configuration.java
index 9b8d0de..fba2c0a 100644
--- 
a/compiler-common/src/main/java/org/apache/royale/compiler/config/Configuration.java
+++ 
b/compiler-common/src/main/java/org/apache/royale/compiler/config/Configuration.java
@@ -1530,6 +1530,28 @@ public class Configuration
     }
 
     //
+    // 'compiler.allow-private-constructors' option
+    //
+
+    private boolean allowPrivateConstructors = false;
+
+    public boolean getCompilerAllowPrivateConstructors()
+    {
+        return allowPrivateConstructors;
+    }
+
+    /**
+     * Whether the compiler will allow constructors to be private.
+     */
+    @Config
+    @Mapping({ "compiler", "allow-private-constructors" })
+    @RoyaleOnly
+    public void setCompilerAllowPrivateConstructors(ConfigurationValue cv, 
boolean allow)
+    {
+        this.allowPrivateConstructors = allow;
+    }
+
+    //
     // 'compiler.actionscript-file-encoding' option
     //
 
diff --git 
a/compiler-common/src/main/java/org/apache/royale/compiler/projects/ICompilerProject.java
 
b/compiler-common/src/main/java/org/apache/royale/compiler/projects/ICompilerProject.java
index 61d7489..00042f9 100644
--- 
a/compiler-common/src/main/java/org/apache/royale/compiler/projects/ICompilerProject.java
+++ 
b/compiler-common/src/main/java/org/apache/royale/compiler/projects/ICompilerProject.java
@@ -275,6 +275,11 @@ public interface ICompilerProject
      /**
       * @return True if abstract classes are allowed.
       */
-      boolean getAllowAbstractClasses();
+     boolean getAllowAbstractClasses();
+     
+     /**
+      * @return True if private constructors are allowed.
+      */
+     boolean getAllowPrivateConstructors();
 
 }
diff --git 
a/compiler/src/main/java/org/apache/royale/compiler/constants/IMetaAttributeConstants.java
 
b/compiler/src/main/java/org/apache/royale/compiler/constants/IMetaAttributeConstants.java
index 189f8ea..4aba20b 100644
--- 
a/compiler/src/main/java/org/apache/royale/compiler/constants/IMetaAttributeConstants.java
+++ 
b/compiler/src/main/java/org/apache/royale/compiler/constants/IMetaAttributeConstants.java
@@ -213,6 +213,9 @@ public interface IMetaAttributeConstants
 
     // [RoyaleAbstract]
     static final String ATTRIBUTE_ABSTRACT = "RoyaleAbstract";
+
+    // [RoyalePrivateConstructor]
+    static final String ATTRIBUTE_PRIVATE_CONSTRUCTOR = 
"RoyalePrivateConstructor";
        
        /**
         * List of metadata tags that do not inherit
@@ -226,6 +229,7 @@ public interface IMetaAttributeConstants
                    ATTRIBUTE_DISCOURAGED_FOR_PROFILE,
             ATTRIBUTE_EXCLUDECLASS,
             ATTRIBUTE_ABSTRACT,
+            ATTRIBUTE_PRIVATE_CONSTRUCTOR,
         })));
 }
 
diff --git 
a/compiler/src/main/java/org/apache/royale/compiler/internal/as/codegen/ClassDirectiveProcessor.java
 
b/compiler/src/main/java/org/apache/royale/compiler/internal/as/codegen/ClassDirectiveProcessor.java
index 7be6c46..08f2704 100644
--- 
a/compiler/src/main/java/org/apache/royale/compiler/internal/as/codegen/ClassDirectiveProcessor.java
+++ 
b/compiler/src/main/java/org/apache/royale/compiler/internal/as/codegen/ClassDirectiveProcessor.java
@@ -67,6 +67,7 @@ import 
org.apache.royale.compiler.problems.CircularTypeReferenceProblem;
 import 
org.apache.royale.compiler.problems.ConstructorCannotHaveReturnTypeProblem;
 import org.apache.royale.compiler.problems.ConstructorIsGetterSetterProblem;
 import org.apache.royale.compiler.problems.ConstructorIsStaticProblem;
+import 
org.apache.royale.compiler.problems.ConstructorMustBePublicOrPrivateProblem;
 import org.apache.royale.compiler.problems.ConstructorMustBePublicProblem;
 import org.apache.royale.compiler.problems.DuplicateClassDefinitionProblem;
 import org.apache.royale.compiler.problems.DynamicNotOnClassProblem;
@@ -982,9 +983,21 @@ class ClassDirectiveProcessor extends DirectiveProcessor
             // It is ok to omit the namespace
             // We must check the AST, as CM treats all ctors as public no 
matter what the user typed in
             // so the FunctionDefinition will always be in the public namespace
-            if( node.getActualNamespaceNode() != null &&
-                    node.getActualNamespaceNode().getName() != 
IASKeywordConstants.PUBLIC)
-                problems.add(new 
ConstructorMustBePublicProblem(node.getActualNamespaceNode()));
+            if (classScope.getProject().getAllowPrivateConstructors())
+            {
+                if (node.getActualNamespaceNode().getName() != 
IASKeywordConstants.PUBLIC
+                        && !func.isPrivate())
+                {
+                    problems.add(new 
ConstructorMustBePublicOrPrivateProblem(node.getActualNamespaceNode()));
+                }
+            }
+            else if( node.getActualNamespaceNode() != null )
+            {
+                if (node.getActualNamespaceNode().getName() != 
IASKeywordConstants.PUBLIC || func.isPrivate())
+                {
+                    problems.add(new 
ConstructorMustBePublicProblem(node.getActualNamespaceNode()));
+                }
+            }
 
             // A constructor cannot be static
             if( func.isStatic() )
diff --git 
a/compiler/src/main/java/org/apache/royale/compiler/internal/definitions/ClassDefinition.java
 
b/compiler/src/main/java/org/apache/royale/compiler/internal/definitions/ClassDefinition.java
index f92749a..9e3f63f 100644
--- 
a/compiler/src/main/java/org/apache/royale/compiler/internal/definitions/ClassDefinition.java
+++ 
b/compiler/src/main/java/org/apache/royale/compiler/internal/definitions/ClassDefinition.java
@@ -313,6 +313,16 @@ public class ClassDefinition extends ClassDefinitionBase 
implements IClassDefini
     protected void setConstructor(IFunctionDefinition constructor)
     {
         this.constructor = constructor;
+
+        if(this.constructor.isPrivate()
+                && 
this.constructor.getMetaTagByName(IMetaAttributeConstants.ATTRIBUTE_PRIVATE_CONSTRUCTOR)
 == null)
+        {
+            // ensures that the constructor remains private when compiled into
+            // a library because the metadata is how private constructors are
+            // stored in the bytecode
+            MetaTag privateMetaTag = new MetaTag(this, 
IMetaAttributeConstants.ATTRIBUTE_PRIVATE_CONSTRUCTOR, new 
IMetaTagAttribute[0]);
+            addMetaTag(privateMetaTag);
+        }
     }
 
     @Override
diff --git 
a/compiler/src/main/java/org/apache/royale/compiler/internal/definitions/FunctionDefinition.java
 
b/compiler/src/main/java/org/apache/royale/compiler/internal/definitions/FunctionDefinition.java
index 5b71d87..9f0e546 100644
--- 
a/compiler/src/main/java/org/apache/royale/compiler/internal/definitions/FunctionDefinition.java
+++ 
b/compiler/src/main/java/org/apache/royale/compiler/internal/definitions/FunctionDefinition.java
@@ -296,6 +296,29 @@ public class FunctionDefinition extends 
ScopedDefinitionBase implements IFunctio
     }
 
     @Override
+    public boolean isPrivate()
+    {
+        if (super.isPrivate())
+        {
+            return true;
+        }
+        if (isConstructor())
+        {
+            IDefinition parent = getParent();
+            if (parent == null)
+            {
+                return false;
+            }
+            // if the construcutor does not have a private namespace, the 
parent
+            // class may have [RoyalePrivateConstructor] metadata instead. this
+            // is how private constructors are stored in bytecode.
+            IMetaTag[] metaTags = 
parent.getMetaTagsByName(IMetaAttributeConstants.ATTRIBUTE_PRIVATE_CONSTRUCTOR);
+            return metaTags != null && metaTags.length > 0;
+        }
+        return false;
+    }
+
+    @Override
     public boolean overridesAncestor(ICompilerProject project)
     {
         return (resolveOverriddenFunction(project) != null);
diff --git 
a/compiler/src/main/java/org/apache/royale/compiler/internal/parsing/as/ConfigProcessor.java
 
b/compiler/src/main/java/org/apache/royale/compiler/internal/parsing/as/ConfigProcessor.java
index af2dd3b..89fcd51 100644
--- 
a/compiler/src/main/java/org/apache/royale/compiler/internal/parsing/as/ConfigProcessor.java
+++ 
b/compiler/src/main/java/org/apache/royale/compiler/internal/parsing/as/ConfigProcessor.java
@@ -170,6 +170,12 @@ public class ConfigProcessor
                        // TODO Auto-generated method stub
                        return false;
                }
+
+        @Override
+        public boolean getAllowPrivateConstructors() {
+            // TODO Auto-generated method stub
+            return false;
+        }
     }
 
     /**
diff --git 
a/compiler/src/main/java/org/apache/royale/compiler/internal/projects/ASCProject.java
 
b/compiler/src/main/java/org/apache/royale/compiler/internal/projects/ASCProject.java
index de04bb2..f542cf3 100644
--- 
a/compiler/src/main/java/org/apache/royale/compiler/internal/projects/ASCProject.java
+++ 
b/compiler/src/main/java/org/apache/royale/compiler/internal/projects/ASCProject.java
@@ -92,4 +92,10 @@ public class ASCProject extends CompilerProject implements 
IASCProject
                // TODO Auto-generated method stub
                return false;
        }
+
+       @Override
+       public boolean getAllowPrivateConstructors() {
+               // TODO Auto-generated method stub
+               return false;
+       }
 }
diff --git 
a/compiler/src/main/java/org/apache/royale/compiler/internal/projects/RoyaleProject.java
 
b/compiler/src/main/java/org/apache/royale/compiler/internal/projects/RoyaleProject.java
index c99f5bb..c0a1285 100644
--- 
a/compiler/src/main/java/org/apache/royale/compiler/internal/projects/RoyaleProject.java
+++ 
b/compiler/src/main/java/org/apache/royale/compiler/internal/projects/RoyaleProject.java
@@ -2460,6 +2460,21 @@ public class RoyaleProject extends ASProject implements 
IRoyaleProject, ICompile
        allowAbstractClasses = allow;
     }
 
+    private boolean allowPrivateConstructors = false;
+    
+    /**
+     * Indicates if private constructors are allowed.
+     */
+    @Override
+    public boolean getAllowPrivateConstructors()
+    {
+       return allowPrivateConstructors;
+    }
+    public void setAllowPrivateConstructors(boolean allow)
+    {
+       allowPrivateConstructors = allow;
+    }
+
        @Override
        public boolean isPlatformRule(ICSSRule rule) {
                return true;
diff --git 
a/compiler/src/main/java/org/apache/royale/compiler/internal/projects/RoyaleProjectConfigurator.java
 
b/compiler/src/main/java/org/apache/royale/compiler/internal/projects/RoyaleProjectConfigurator.java
index cb3a35b..46ccade 100644
--- 
a/compiler/src/main/java/org/apache/royale/compiler/internal/projects/RoyaleProjectConfigurator.java
+++ 
b/compiler/src/main/java/org/apache/royale/compiler/internal/projects/RoyaleProjectConfigurator.java
@@ -265,6 +265,7 @@ public class RoyaleProjectConfigurator extends Configurator
 
             
project.setAllowImportAliases(configuration.getCompilerAllowImportAliases());
             
project.setAllowAbstractClasses(configuration.getCompilerAllowAbstractClasses());
+            
project.setAllowPrivateConstructors(configuration.getCompilerAllowPrivateConstructors());
             
             DataTranscoder.embedClassName = 
configuration.getByteArrayEmbedClass();
         }
diff --git 
a/compiler/src/main/java/org/apache/royale/compiler/internal/semantics/MethodBodySemanticChecker.java
 
b/compiler/src/main/java/org/apache/royale/compiler/internal/semantics/MethodBodySemanticChecker.java
index 52a5bd4..067c2fe 100644
--- 
a/compiler/src/main/java/org/apache/royale/compiler/internal/semantics/MethodBodySemanticChecker.java
+++ 
b/compiler/src/main/java/org/apache/royale/compiler/internal/semantics/MethodBodySemanticChecker.java
@@ -70,6 +70,7 @@ import 
org.apache.royale.compiler.internal.definitions.AmbiguousDefinition;
 import org.apache.royale.compiler.internal.definitions.VariableDefinition;
 import org.apache.royale.compiler.problems.*;
 import org.apache.royale.compiler.projects.ICompilerProject;
+import org.apache.royale.compiler.scopes.IASScope;
 import org.apache.royale.compiler.tree.ASTNodeID;
 import org.apache.royale.compiler.tree.as.IASNode;
 import org.apache.royale.compiler.tree.as.IBinaryOperatorNode;
@@ -85,6 +86,7 @@ import 
org.apache.royale.compiler.tree.as.INamespaceDecorationNode;
 import org.apache.royale.compiler.tree.as.INumericLiteralNode;
 import org.apache.royale.compiler.tree.as.IParameterNode;
 import org.apache.royale.compiler.tree.as.IReturnNode;
+import org.apache.royale.compiler.tree.as.IScopedNode;
 import org.apache.royale.compiler.tree.as.IUnaryOperatorNode;
 import org.apache.royale.compiler.tree.as.IVariableNode;
 import org.apache.royale.compiler.internal.as.codegen.ABCGeneratingReducer;
@@ -2025,7 +2027,8 @@ public class MethodBodySemanticChecker
             }
             else if ( def instanceof ClassDefinition )
             {
-                // pass
+                IClassDefinition classDef = (IClassDefinition) def;
+                checkPrivateConstructorNewExpr(call_node, null, classDef, 
classDef.getConstructor());
             }
             else if ( def instanceof GetterDefinition )
             {
@@ -2041,6 +2044,12 @@ public class MethodBodySemanticChecker
                         addProblem(new 
MethodCannotBeConstructorProblem(call_node));
                         break;
                 }
+
+                if (func_def.isConstructor())
+                {
+                    IDefinition class_def = func_def.getParent();
+                    checkPrivateConstructorNewExpr(call_node, null, class_def, 
func_def);
+                }
             }
             else if (def == null)
             {
@@ -2087,8 +2096,10 @@ public class MethodBodySemanticChecker
 
             if ( ctor instanceof FunctionDefinition )
             {
-                FunctionDefinition func = (FunctionDefinition)ctor;
-                checkFormalsVsActuals(iNode, func, args);
+                FunctionDefinition func_def = (FunctionDefinition)ctor;
+                checkFormalsVsActuals(iNode, func_def, args);
+                
+                checkPrivateConstructorNewExpr(iNode, class_binding, 
class_def, func_def);
             }
         }
         else if ( def instanceof GetterDefinition )
@@ -2100,7 +2111,12 @@ public class MethodBodySemanticChecker
 
             IFunctionDefinition.FunctionClassification func_type = 
func_def.getFunctionClassification();
 
-            if ( 
func_type.equals(IFunctionDefinition.FunctionClassification.CLASS_MEMBER) || 
func_type.equals(IFunctionDefinition.FunctionClassification.INTERFACE_MEMBER) )
+            if (func_def.isConstructor())
+            {
+                IDefinition class_def = func_def.getParent();
+                checkPrivateConstructorNewExpr(iNode, class_binding, 
class_def, func_def);
+            }
+            else if ( 
func_type.equals(IFunctionDefinition.FunctionClassification.CLASS_MEMBER) || 
func_type.equals(IFunctionDefinition.FunctionClassification.INTERFACE_MEMBER) )
             {
                 addProblem(new MethodCannotBeConstructorProblem(
                     roundUpUsualSuspects(class_binding, iNode)
@@ -2133,6 +2149,47 @@ public class MethodBodySemanticChecker
         checkReference(class_binding);
     }
 
+    private void checkPrivateConstructorNewExpr(IASNode iNode, Binding 
class_binding, IDefinition classDef, IFunctionDefinition funcDef)
+    {
+        if (!project.getAllowPrivateConstructors() || !funcDef.isPrivate())
+        {
+            return;
+        }
+
+        IScopedNode enclosingScope = iNode.getContainingScope();
+        
+        if (enclosingScope != null)
+        {
+            boolean needsProblem = true;
+            IASScope currentScope = enclosingScope.getScope();
+            while (currentScope != null)
+            {
+                IDefinition currentDef = currentScope.getDefinition();
+                if (currentDef instanceof IClassDefinition)
+                {
+                    needsProblem = 
!classDef.equals(currentScope.getDefinition());
+                    break;
+                }
+                currentScope = currentScope.getContainingScope();
+            }
+            if(needsProblem)
+            {
+                if(class_binding != null)
+                {
+                    addProblem(new InaccessibleConstructorReferenceProblem(
+                        roundUpUsualSuspects(class_binding, iNode), 
classDef.getQualifiedName()
+                    ));
+                }
+                else
+                {
+                    addProblem(new InaccessibleConstructorReferenceProblem(
+                        iNode, classDef.getQualifiedName()
+                    ));
+                }
+            }
+        }
+    }
+
     /**
      *  Check a return expression that returns a value.
      *  @param iNode - the return statement.  
diff --git 
a/compiler/src/main/java/org/apache/royale/compiler/internal/tree/as/FunctionNode.java
 
b/compiler/src/main/java/org/apache/royale/compiler/internal/tree/as/FunctionNode.java
index c07a8be..64c0b2b 100644
--- 
a/compiler/src/main/java/org/apache/royale/compiler/internal/tree/as/FunctionNode.java
+++ 
b/compiler/src/main/java/org/apache/royale/compiler/internal/tree/as/FunctionNode.java
@@ -36,8 +36,10 @@ import org.apache.royale.compiler.common.ASImportTarget;
 import org.apache.royale.compiler.common.IImportTarget;
 import org.apache.royale.compiler.config.CompilerDiagnosticsConstants;
 import org.apache.royale.compiler.constants.IASLanguageConstants;
+import org.apache.royale.compiler.constants.IMetaAttributeConstants;
 import org.apache.royale.compiler.constants.INamespaceConstants;
 import org.apache.royale.compiler.definitions.IDefinition;
+import org.apache.royale.compiler.definitions.INamespaceDefinition;
 import 
org.apache.royale.compiler.definitions.IFunctionDefinition.FunctionClassification;
 import org.apache.royale.compiler.definitions.IParameterDefinition;
 import org.apache.royale.compiler.definitions.references.IReference;
@@ -74,6 +76,7 @@ import org.apache.royale.compiler.tree.as.IParameterNode;
 import org.apache.royale.compiler.tree.as.IScopedNode;
 import org.apache.royale.compiler.tree.as.ITypeNode;
 import org.apache.royale.compiler.tree.as.IVariableNode;
+import org.apache.royale.compiler.tree.metadata.IMetaTagNode;
 import org.apache.royale.compiler.workspaces.IWorkspace;
 
 import com.google.common.base.Predicate;
@@ -364,8 +367,30 @@ public class FunctionNode extends BaseTypedDefinitionNode 
implements IFunctionNo
         
         if (isConstructor())
         {
-            if (namespaceNode != null && 
namespaceNode.getName().equals(INamespaceConstants.public_))
+            if (namespaceNode != null
+                    && 
(namespaceNode.getName().equals(INamespaceConstants.public_) || 
namespaceNode.getName().equals(INamespaceConstants.private_)))
+            {
+                // if the existing node is already public or private, return it
                 return namespaceNode;
+            }
+            IASNode parentNode = getParent();
+            if (parentNode instanceof IDefinitionNode)
+            {
+                IDefinitionNode defNode = (IDefinitionNode) parentNode;
+                IMetaTagNode[] metaTagNodes = 
defNode.getMetaTags().getTagsByName(IMetaAttributeConstants.ATTRIBUTE_PRIVATE_CONSTRUCTOR);
+                if (metaTagNodes != null && metaTagNodes.length > 0)
+                {
+                    // if the parent class has [RoyalePrivateConstructor]
+                    // metadata, the constructor should be considered private
+                    // and we should generate a fake namespace node
+                    NamespaceIdentifierNode priv = new 
NamespaceIdentifierNode(INamespaceConstants.private_);
+                    priv.span(-1, -1, -1, -1);
+                    priv.setDecorationTarget(this);
+                    return priv;
+                }
+            }
+            // if there is no namespace node, the namespace defaults to public
+            // and we'll generate a fake node
             NamespaceIdentifierNode pub = new 
NamespaceIdentifierNode(INamespaceConstants.public_);
             pub.span(-1, -1, -1, -1);
             pub.setDecorationTarget(this);
@@ -382,11 +407,12 @@ public class FunctionNode extends BaseTypedDefinitionNode 
implements IFunctionNo
         if (ns != null)
         {
             String nameString = ns.getName();
-            // If public, just return it.
-            if (nameString.equals(INamespaceConstants.public_))
+            // If public or private, just return it.
+            if (nameString.equals(INamespaceConstants.public_) || 
nameString.equals(INamespaceConstants.private_))
                 return nameString;
 
-            // Otherwise, check to see if we are a constructor.
+            // Otherwise, check to see if we are a constructor and always 
return
+            // public
             if (isConstructor())
                 return INamespaceConstants.public_;
             
@@ -649,8 +675,16 @@ public class FunctionNode extends BaseTypedDefinitionNode 
implements IFunctionNo
                         classNode.constructorNode = this;
                     }
                 }
+                // if the namespace reference is private, don't change it
+                if(!(funcDef.getNamespaceReference() instanceof 
INamespaceDefinition.IPrivateNamespaceDefinition))
+                {
+                    
funcDef.setNamespaceReference(NamespaceDefinition.getCodeModelImplicitDefinitionNamespace());
+                }
+            }
+            else
+            {
+                
funcDef.setNamespaceReference(NamespaceDefinition.getCodeModelImplicitDefinitionNamespace());
             }
-            
funcDef.setNamespaceReference(NamespaceDefinition.getCodeModelImplicitDefinitionNamespace());
         }
     }
 
diff --git 
a/compiler/src/main/java/org/apache/royale/compiler/problems/ConstructorMustBePublicOrPrivateProblem.java
 
b/compiler/src/main/java/org/apache/royale/compiler/problems/ConstructorMustBePublicOrPrivateProblem.java
new file mode 100644
index 0000000..93e8755
--- /dev/null
+++ 
b/compiler/src/main/java/org/apache/royale/compiler/problems/ConstructorMustBePublicOrPrivateProblem.java
@@ -0,0 +1,42 @@
+/*
+ *
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.royale.compiler.problems;
+
+import org.apache.royale.compiler.tree.as.IASNode;
+
+/**
+ * Diagnostic emitted when a constructor is not public or private
+ */
+public final class ConstructorMustBePublicOrPrivateProblem extends 
CodegenProblem
+{
+    public static final String DESCRIPTION =
+        "A constructor can only be declared ${PUBLIC} or ${PRIVATE}";
+
+    public static final int errorCode = 1153;
+
+    public ConstructorMustBePublicOrPrivateProblem(IASNode site)
+    {
+        super(site);
+    }
+    
+    // Prevent these from being localized.
+    public final String PUBLIC = "public";
+    public final String PRIVATE = "private";
+}
diff --git 
a/compiler/src/main/java/org/apache/royale/compiler/problems/InaccessibleConstructorReferenceProblem.java
 
b/compiler/src/main/java/org/apache/royale/compiler/problems/InaccessibleConstructorReferenceProblem.java
new file mode 100644
index 0000000..761717a
--- /dev/null
+++ 
b/compiler/src/main/java/org/apache/royale/compiler/problems/InaccessibleConstructorReferenceProblem.java
@@ -0,0 +1,43 @@
+/*
+ *
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.royale.compiler.problems;
+
+import org.apache.royale.compiler.tree.as.IASNode;
+
+/**
+ *  Diagnostic emitted when the semantic analyzer detects 
+ *  an attempt to call an inaccessible constructor (e.g., a
+ *  private constructor call outside the class).
+ */
+public final class InaccessibleConstructorReferenceProblem extends 
StrictSemanticsProblem
+{
+    public static final String DESCRIPTION =
+        "Attempted access of inaccessible constructor through a reference with 
static type ${className}.";
+
+    public static final int errorCode = 1195;
+
+    public InaccessibleConstructorReferenceProblem(IASNode site, final String 
className)
+    {
+        super(site);
+        this.className = className;
+    }
+    
+    public final String className;
+}
diff --git a/compiler/src/test/java/as/ASPrivateConstructorTests.java 
b/compiler/src/test/java/as/ASPrivateConstructorTests.java
new file mode 100644
index 0000000..7981155
--- /dev/null
+++ b/compiler/src/test/java/as/ASPrivateConstructorTests.java
@@ -0,0 +1,631 @@
+/*
+ *
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package as;
+
+import java.io.File;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+public class ASPrivateConstructorTests extends ASFeatureTestsBase
+{
+    @Test
+       public void 
testConstructorMustBePublicProblem_withPrivateConstructor_andAllowPrivateConstructorsDisabled()
+    {
+        String[] imports = new String[]
+        {
+               };
+        String[] declarations = new String[]
+        {
+        };
+        String[] testCode = new String[]
+        {
+        };
+        String[] extra = new String[]
+        {
+                       "class A {",
+            //error because private constructors have not been enabled
+                       "private function A() {",
+                       "}",
+            "}"
+        };
+        String source = getAS(imports, declarations, testCode, extra);
+        String[] options = new String[]
+        {
+            "-allow-private-constructors=false"
+        };
+        compileAndExpectErrors(source, false, false, false, options, "A 
constructor can only be declared public\n");
+       }
+
+    @Test
+       public void 
testConstructorMustBePublicProblem_withProtectedConstructor_andAllowPrivateConstructorsDisabled()
+    {
+        String[] imports = new String[]
+        {
+               };
+        String[] declarations = new String[]
+        {
+        };
+        String[] testCode = new String[]
+        {
+        };
+        String[] extra = new String[]
+        {
+                       "class A {",
+            //error because protected constructors are not allowed
+                       "protected function A() {",
+                       "}",
+            "}"
+        };
+        String source = getAS(imports, declarations, testCode, extra);
+        String[] options = new String[]
+        {
+            "-allow-private-constructors=false"
+        };
+        compileAndExpectErrors(source, false, false, false, options, "A 
constructor can only be declared public\n");
+       }
+
+    @Test
+       public void 
testConstructorMustBePublicProblem_withInternalConstructor_andAllowPrivateConstructorsDisabled()
+    {
+        String[] imports = new String[]
+        {
+               };
+        String[] declarations = new String[]
+        {
+        };
+        String[] testCode = new String[]
+        {
+        };
+        String[] extra = new String[]
+        {
+                       "class A {",
+            //error because internal constructors are not allowed
+                       "internal function A() {",
+                       "}",
+            "}"
+        };
+        String source = getAS(imports, declarations, testCode, extra);
+        String[] options = new String[]
+        {
+            "-allow-private-constructors=false"
+        };
+        compileAndExpectErrors(source, false, false, false, options, "A 
constructor can only be declared public\n");
+       }
+
+    @Test
+       public void 
testConstructorMustBePublicProblem_withMetadata_andAllowPrivateConstructorsDisabled()
+    {
+        String[] imports = new String[]
+        {
+               };
+        String[] declarations = new String[]
+        {
+        };
+        String[] testCode = new String[]
+        {
+        };
+        String[] extra = new String[]
+        {
+                       //error because private constructors have not been 
enabled
+                       "[RoyalePrivateConstructor]",
+                       "class A {",
+                       "public function A() {",
+                       "}",
+            "}"
+        };
+        String source = getAS(imports, declarations, testCode, extra);
+        String[] options = new String[]
+        {
+            "-allow-private-constructors=false"
+        };
+        compileAndExpectErrors(source, false, false, false, options, "A 
constructor can only be declared public\n");
+    }
+
+    @Test
+       public void 
testConstructorMustBePublicProblemAndInaccessibleConstructorReferenceProblem_withPrivateConstructor_andAllowPrivateConstructorsDisabled()
+    {
+        String[] imports = new String[]
+        {
+               };
+        String[] declarations = new String[]
+        {
+        };
+        String[] testCode = new String[]
+        {
+            //no error because the constructor cannot be private
+            "new A()"
+        };
+        String[] extra = new String[]
+        {
+                       "class A {",
+            //error because private constructors have not been enabled
+                       "private function A() {",
+                       "}",
+            "}"
+        };
+        String source = getAS(imports, declarations, testCode, extra);
+        String[] options = new String[]
+        {
+            "-allow-private-constructors=false"
+        };
+        compileAndExpectErrors(source, false, false, false, options, "A 
constructor can only be declared public\n");
+       }
+
+    @Test
+       public void 
testConstructorMustBePublicProblemAndInaccessibleConstructorReferenceProblem_withMetadata_andAllowPrivateConstructorsDisabled()
+    {
+        String[] imports = new String[]
+        {
+               };
+        String[] declarations = new String[]
+        {
+        };
+        String[] testCode = new String[]
+        {
+            //no error because the constructor cannot be private
+            "new A()"
+        };
+        String[] extra = new String[]
+        {
+            "[RoyalePrivateConstructor]",
+                       "class A {",
+            //error because private constructors have not been enabled
+                       "private function A() {",
+                       "}",
+            "}"
+        };
+        String source = getAS(imports, declarations, testCode, extra);
+        String[] options = new String[]
+        {
+            "-allow-private-constructors=false"
+        };
+        compileAndExpectErrors(source, false, false, false, options, "A 
constructor can only be declared public\n");
+       }
+    
+    @Test
+       public void 
testNoConstructorMustBePublicOrPrivateProblem_withPrivateConstructor_andAllowPrivateConstructorsEnabled()
+    {
+        String[] imports = new String[]
+        {
+               };
+        String[] declarations = new String[]
+        {
+        };
+        String[] testCode = new String[]
+        {
+        };
+        String[] extra = new String[]
+        {
+                       "class A {",
+                       "private function A() {",
+                       "}",
+            "}"
+        };
+        String source = getAS(imports, declarations, testCode, extra);
+        String[] options = new String[]
+        {
+            "-allow-private-constructors=true"
+        };
+        File tempASFile = generateTempFile(source);
+        String result = compile(tempASFile, source, false, false, false, 
options, true);
+        Assert.assertEquals("", result);
+       }
+
+    @Test
+       public void 
testConstructorMustBePublicOrPrivateProblem_withProtectedConstructor_andAllowPrivateConstructorsEnabled()
+    {
+        String[] imports = new String[]
+        {
+               };
+        String[] declarations = new String[]
+        {
+        };
+        String[] testCode = new String[]
+        {
+        };
+        String[] extra = new String[]
+        {
+                       "class A {",
+            //error because protected constructors are not allowed
+                       "protected function A() {",
+                       "}",
+            "}"
+        };
+        String source = getAS(imports, declarations, testCode, extra);
+        String[] options = new String[]
+        {
+            "-allow-private-constructors=true"
+        };
+        compileAndExpectErrors(source, false, false, false, options, "A 
constructor can only be declared public or private\n");
+       }
+
+    @Test
+       public void 
testConstructorMustBePublicOrPrivateProblem_withInternalConstructor_andAllowPrivateConstructorsEnabled()
+    {
+        String[] imports = new String[]
+        {
+               };
+        String[] declarations = new String[]
+        {
+        };
+        String[] testCode = new String[]
+        {
+        };
+        String[] extra = new String[]
+        {
+                       "class A {",
+            //error because internal constructors are not allowed
+                       "internal function A() {",
+                       "}",
+            "}"
+        };
+        String source = getAS(imports, declarations, testCode, extra);
+        String[] options = new String[]
+        {
+            "-allow-private-constructors=true"
+        };
+        compileAndExpectErrors(source, false, false, false, options, "A 
constructor can only be declared public or private\n");
+       }
+
+    @Test
+       public void 
testNoConstructorMustBePublicOrPrivateProblem_withMetadata_andAllowPrivateConstructorsEnabled()
+    {
+        String[] imports = new String[]
+        {
+               };
+        String[] declarations = new String[]
+        {
+        };
+        String[] testCode = new String[]
+        {
+        };
+        String[] extra = new String[]
+        {
+                       //error because private constructors have not been 
enabled
+                       "[RoyalePrivateConstructor]",
+                       "class A {",
+                       "public function A() {",
+                       "}",
+            "}"
+        };
+        String source = getAS(imports, declarations, testCode, extra);
+        String[] options = new String[]
+        {
+            "-allow-private-constructors=true"
+        };
+        File tempASFile = generateTempFile(source);
+        String result = compile(tempASFile, source, false, false, false, 
options, true);
+        Assert.assertEquals("", result);
+    }
+
+    @Test
+       public void 
testInaccessibleConstructorReferenceProblem_withPrivateConstructor_andAllowPrivateConstructorsEnabled()
+    {
+        String[] imports = new String[]
+        {
+               };
+        String[] declarations = new String[]
+        {
+        };
+        String[] testCode = new String[]
+        {
+            //error because the constructor is private
+            "new A()"
+        };
+        String[] extra = new String[]
+        {
+                       "class A {",
+                       "private function A() {",
+                       "}",
+            "}"
+        };
+        String source = getAS(imports, declarations, testCode, extra);
+        String[] options = new String[]
+        {
+            "-allow-private-constructors=true"
+        };
+        compileAndExpectErrors(source, false, false, false, options, 
"Attempted access of inaccessible constructor through a reference with static 
type A.\n");
+       }
+
+    @Test
+       public void 
testInaccessibleConstructorReferenceProblem_withMetadata_andAllowPrivateConstructorsEnabled()
+    {
+        String[] imports = new String[]
+        {
+               };
+        String[] declarations = new String[]
+        {
+        };
+        String[] testCode = new String[]
+        {
+            //error because the constructor is private
+            "new A()"
+        };
+        String[] extra = new String[]
+        {
+                       "[RoyalePrivateConstructor]",
+                       "class A {",
+                       "private function A() {",
+                       "}",
+            "}"
+        };
+        String source = getAS(imports, declarations, testCode, extra);
+        String[] options = new String[]
+        {
+            "-allow-private-constructors=true"
+        };
+        compileAndExpectErrors(source, false, false, false, options, 
"Attempted access of inaccessible constructor through a reference with static 
type A.\n");
+       }
+
+    @Test
+       public void 
testInaccessibleConstructorReferenceProblem_withPrivateConstructor_inFilePrivateArea_andAllowPrivateConstructorsEnabled()
+    {
+        String[] imports = new String[]
+        {
+               };
+        String[] declarations = new String[]
+        {
+        };
+        String[] testCode = new String[]
+        {
+        };
+        String[] extra = new String[]
+        {
+                       "class A {",
+                       "private function A() {",
+                       "}",
+            "}",
+            //error because the constructor is private
+            "new A()"
+        };
+        String source = getAS(imports, declarations, testCode, extra);
+        String[] options = new String[]
+        {
+            "-allow-private-constructors=true"
+        };
+        compileAndExpectErrors(source, false, false, false, options, 
"Attempted access of inaccessible constructor through a reference with static 
type A.\n");
+       }
+
+    @Test
+       public void 
testInaccessibleConstructorReferenceProblem_withMetadata_inFilePrivateArea_andAllowPrivateConstructorsEnabled()
+    {
+        String[] imports = new String[]
+        {
+               };
+        String[] declarations = new String[]
+        {
+        };
+        String[] testCode = new String[]
+        {
+        };
+        String[] extra = new String[]
+        {
+                       "[RoyalePrivateConstructor]",
+                       "class A {",
+                       "private function A() {",
+                       "}",
+            "}",
+            //error because the constructor is private
+            "new A()"
+        };
+        String source = getAS(imports, declarations, testCode, extra);
+        String[] options = new String[]
+        {
+            "-allow-private-constructors=true"
+        };
+        compileAndExpectErrors(source, false, false, false, options, 
"Attempted access of inaccessible constructor through a reference with static 
type A.\n");
+       }
+
+    @Test
+       public void 
testNoInaccessibleConstructorReferenceProblem_withPrivateConstructor_inMethodOfSameClass_andAllowPrivateConstructorsEnabled()
+    {
+        String[] imports = new String[]
+        {
+               };
+        String[] declarations = new String[]
+        {
+        };
+        String[] testCode = new String[]
+        {
+        };
+        String[] extra = new String[]
+        {
+            "class A {",
+                       "private function A() {",
+                       "}",
+            "public function method():Object {",
+            "return new A()",
+            "}",
+            "}"
+        };
+        String source = getAS(imports, declarations, testCode, extra);
+        String[] options = new String[]
+        {
+            "-allow-private-constructors=true"
+        };
+        File tempASFile = generateTempFile(source);
+        String result = compile(tempASFile, source, false, false, false, 
options, true);
+        Assert.assertEquals("", result);
+       }
+
+    @Test
+       public void 
testNoInaccessibleConstructorReferenceProblem_withMetadata_inMethodOfSameClass_andAllowPrivateConstructorsEnabled()
+    {
+        String[] imports = new String[]
+        {
+               };
+        String[] declarations = new String[]
+        {
+        };
+        String[] testCode = new String[]
+        {
+        };
+        String[] extra = new String[]
+        {
+            "[RoyalePrivateConstructor]",
+            "class A {",
+                       "private function A() {",
+                       "}",
+            "public function method():Object {",
+            "return new A()",
+            "}",
+            "}"
+        };
+        String source = getAS(imports, declarations, testCode, extra);
+        String[] options = new String[]
+        {
+            "-allow-private-constructors=true"
+        };
+        File tempASFile = generateTempFile(source);
+        String result = compile(tempASFile, source, false, false, false, 
options, true);
+        Assert.assertEquals("", result);
+       }
+
+    @Test
+       public void 
testNoInaccessibleConstructorReferenceProblem_withPrivateConstructor_inStaticMethodOfSameClass_andAllowPrivateConstructorsEnabled()
+    {
+        String[] imports = new String[]
+        {
+               };
+        String[] declarations = new String[]
+        {
+        };
+        String[] testCode = new String[]
+        {
+        };
+        String[] extra = new String[]
+        {
+            "class A {",
+                       "private function A() {",
+                       "}",
+            "public static function method():Object {",
+            "return new A()",
+            "}",
+            "}"
+        };
+        String source = getAS(imports, declarations, testCode, extra);
+        String[] options = new String[]
+        {
+            "-allow-private-constructors=true"
+        };
+        File tempASFile = generateTempFile(source);
+        String result = compile(tempASFile, source, false, false, false, 
options, true);
+        Assert.assertEquals("", result);
+       }
+
+    @Test
+       public void 
testNoInaccessibleConstructorReferenceProblem_withMetadata_inStaticMethodOfSameClass_andAllowPrivateConstructorsEnabled()
+    {
+        String[] imports = new String[]
+        {
+               };
+        String[] declarations = new String[]
+        {
+        };
+        String[] testCode = new String[]
+        {
+        };
+        String[] extra = new String[]
+        {
+            "[RoyalePrivateConstructor]",
+            "class A {",
+                       "private function A() {",
+                       "}",
+            "public static function method():Object {",
+            "return new A()",
+            "}",
+            "}"
+        };
+        String source = getAS(imports, declarations, testCode, extra);
+        String[] options = new String[]
+        {
+            "-allow-private-constructors=true"
+        };
+        File tempASFile = generateTempFile(source);
+        String result = compile(tempASFile, source, false, false, false, 
options, true);
+        Assert.assertEquals("", result);
+       }
+
+    @Test
+       public void 
testNoInaccessibleConstructorReferenceProblem_withPrivateConstructor_inGetterOfSameClass_andAllowPrivateConstructorsEnabled()
+    {
+        String[] imports = new String[]
+        {
+               };
+        String[] declarations = new String[]
+        {
+        };
+        String[] testCode = new String[]
+        {
+        };
+        String[] extra = new String[]
+        {
+            "class A {",
+                       "private function A() {",
+                       "}",
+            "public function get getter():Object {",
+            "return new A()",
+            "}",
+            "}"
+        };
+        String source = getAS(imports, declarations, testCode, extra);
+        String[] options = new String[]
+        {
+            "-allow-private-constructors=true"
+        };
+        File tempASFile = generateTempFile(source);
+        String result = compile(tempASFile, source, false, false, false, 
options, true);
+        Assert.assertEquals("", result);
+       }
+
+    @Test
+       public void 
testNoInaccessibleConstructorReferenceProblem_withMetadata_inGetterOfSameClass_andAllowPrivateConstructorsEnabled()
+    {
+        String[] imports = new String[]
+        {
+               };
+        String[] declarations = new String[]
+        {
+        };
+        String[] testCode = new String[]
+        {
+        };
+        String[] extra = new String[]
+        {
+            "[RoyalePrivateConstructor]",
+            "class A {",
+                       "private function A() {",
+                       "}",
+            "public function get getter():Object {",
+            "return new A()",
+            "}",
+            "}"
+        };
+        String source = getAS(imports, declarations, testCode, extra);
+        String[] options = new String[]
+        {
+            "-allow-private-constructors=true"
+        };
+        File tempASFile = generateTempFile(source);
+        String result = compile(tempASFile, source, false, false, false, 
options, true);
+        Assert.assertEquals("", result);
+       }
+}
\ No newline at end of file

Reply via email to