Package com.redhat.ceylon.compiler.typechecker.context

Source Code of com.redhat.ceylon.compiler.typechecker.context.PhasedUnit

package com.redhat.ceylon.compiler.typechecker.context;

import java.lang.ref.WeakReference;
import java.util.EnumSet;
import java.util.List;

import org.antlr.runtime.CommonToken;

import com.redhat.ceylon.compiler.typechecker.analyzer.AliasVisitor;
import com.redhat.ceylon.compiler.typechecker.analyzer.AnnotationVisitor;
import com.redhat.ceylon.compiler.typechecker.analyzer.ControlFlowVisitor;
import com.redhat.ceylon.compiler.typechecker.analyzer.DeclarationVisitor;
import com.redhat.ceylon.compiler.typechecker.analyzer.DefaultTypeArgVisitor;
import com.redhat.ceylon.compiler.typechecker.analyzer.ExpressionVisitor;
import com.redhat.ceylon.compiler.typechecker.analyzer.InheritanceVisitor;
import com.redhat.ceylon.compiler.typechecker.analyzer.LiteralVisitor;
import com.redhat.ceylon.compiler.typechecker.analyzer.LocalDeclarationVisitor;
import com.redhat.ceylon.compiler.typechecker.analyzer.ModuleManager;
import com.redhat.ceylon.compiler.typechecker.analyzer.ModuleVisitor;
import com.redhat.ceylon.compiler.typechecker.analyzer.RefinementVisitor;
import com.redhat.ceylon.compiler.typechecker.analyzer.SelfReferenceVisitor;
import com.redhat.ceylon.compiler.typechecker.analyzer.SpecificationVisitor;
import com.redhat.ceylon.compiler.typechecker.analyzer.SupertypeVisitor;
import com.redhat.ceylon.compiler.typechecker.analyzer.TypeArgumentVisitor;
import com.redhat.ceylon.compiler.typechecker.analyzer.TypeHierarchyVisitor;
import com.redhat.ceylon.compiler.typechecker.analyzer.TypeVisitor;
import com.redhat.ceylon.compiler.typechecker.analyzer.VisibilityVisitor;
import com.redhat.ceylon.compiler.typechecker.analyzer.Warning;
import com.redhat.ceylon.compiler.typechecker.io.VirtualFile;
import com.redhat.ceylon.compiler.typechecker.io.impl.Helper;
import com.redhat.ceylon.compiler.typechecker.model.Declaration;
import com.redhat.ceylon.compiler.typechecker.model.Module;
import com.redhat.ceylon.compiler.typechecker.model.Package;
import com.redhat.ceylon.compiler.typechecker.model.ProducedType;
import com.redhat.ceylon.compiler.typechecker.model.TypeDeclaration;
import com.redhat.ceylon.compiler.typechecker.model.Unit;
import com.redhat.ceylon.compiler.typechecker.tree.Tree;
import com.redhat.ceylon.compiler.typechecker.tree.Tree.ImportPath;
import com.redhat.ceylon.compiler.typechecker.tree.Tree.ModuleDescriptor;
import com.redhat.ceylon.compiler.typechecker.tree.Util;
import com.redhat.ceylon.compiler.typechecker.tree.Validator;
import com.redhat.ceylon.compiler.typechecker.tree.Visitor;
import com.redhat.ceylon.compiler.typechecker.util.AssertionVisitor;
import com.redhat.ceylon.compiler.typechecker.util.DeprecationVisitor;
import com.redhat.ceylon.compiler.typechecker.util.PrintVisitor;
import com.redhat.ceylon.compiler.typechecker.util.ReferenceCounter;
import com.redhat.ceylon.compiler.typechecker.util.StatisticsVisitor;
import com.redhat.ceylon.compiler.typechecker.util.UnitFactory;
import com.redhat.ceylon.compiler.typechecker.util.UsageVisitor;
import com.redhat.ceylon.compiler.typechecker.util.WarningSuppressionVisitor;

/**
* Represent a unit and each of the type checking phases
*
* @author Emmanuel Bernard <emmanuel@hibernate.org>
*/
public class PhasedUnit {
   
    private Tree.CompilationUnit compilationUnit;
    private Package pkg;
    private Unit unit;
    //must be the non qualified file name
    private String fileName;
    private WeakReference<ModuleManager> moduleManagerRef;
    private final String pathRelativeToSrcDir;
    private VirtualFile unitFile;
    private List<CommonToken> tokens;
    private ModuleVisitor moduleVisitor;
    private VirtualFile srcDir;
    private boolean treeValidated = false;
    private boolean declarationsScanned = false;
    private boolean scanningDeclarations = false;
    private boolean typeDeclarationsScanned = false;
    private boolean refinementValidated = false;
    private boolean flowAnalyzed = false;
    private boolean fullyTyped = false;
    private boolean usageAnalyzed = false;
    private boolean literalsProcessed = false;
    private boolean moduleVisited = false;
    private EnumSet<Warning> suppressedWarnings = EnumSet.noneOf(Warning.class);
    public VirtualFile getSrcDir() {
        return srcDir;
    }

    public PhasedUnit(VirtualFile unitFile, VirtualFile srcDir, Tree.CompilationUnit cu,
            Package p, ModuleManager moduleManager, Context context, List<CommonToken> tokenStream) {
        this.compilationUnit = cu;
        this.pkg = p;
        this.unitFile = unitFile;
        this.srcDir = srcDir;
        this.fileName = unitFile.getName();
        this.pathRelativeToSrcDir = Helper.computeRelativePath(unitFile, srcDir);
        this.moduleManagerRef = new WeakReference<>(moduleManager);
        this.tokens = tokenStream;
        unit = createUnit();
        unit.setFilename(fileName);
        unit.setFullPath(unitFile.getPath());
        unit.setRelativePath(pathRelativeToSrcDir);
        unit.setPackage(pkg);
        pkg.removeUnit(unit);
        pkg.addUnit(unit);
        cu.setUnit(unit);
    }

    public PhasedUnit(PhasedUnit other) {
        this.compilationUnit = other.compilationUnit;
        this.pkg = other.pkg;
        this.unit = other.unit;
        this.fileName = other.fileName;
        this.moduleManagerRef = new WeakReference<>(other.moduleManagerRef.get());
        this.pathRelativeToSrcDir = other.pathRelativeToSrcDir;
        this.unitFile = other.unitFile;
        this.tokens = other.tokens;
        this.moduleVisitor = other.moduleVisitor;
        this.srcDir = other.srcDir;
        this.treeValidated = other.treeValidated;
        this.declarationsScanned = other.declarationsScanned;
        this.scanningDeclarations = other.scanningDeclarations;
        this.typeDeclarationsScanned = other.typeDeclarationsScanned;
        this.fullyTyped = other.fullyTyped;
        this.refinementValidated = other.refinementValidated;
        this.fullyTyped = other.fullyTyped;
        this.flowAnalyzed = other.flowAnalyzed;
    }

    @Deprecated
    protected PhasedUnit(VirtualFile unitFile, VirtualFile srcDir, Tree.CompilationUnit cu,
            Package p, ModuleManager moduleManager, Context context) {
        this(unitFile, srcDir, cu, p, moduleManager, context, null);
    }
   
    protected boolean reuseExistingDescriptorModels() {
        return false;
    }
   
    public Module visitSrcModulePhase() {
        if ( ModuleManager.MODULE_FILE.equals(fileName) ||
                ModuleManager.PACKAGE_FILE.equals(fileName) ) {
            if (! moduleVisited) {
                moduleVisited = true;
                processLiterals();
                moduleVisitor = new ModuleVisitor(moduleManagerRef.get(), pkg);
                moduleVisitor.setCompleteOnlyAST(reuseExistingDescriptorModels());
                compilationUnit.visit(moduleVisitor);
                return moduleVisitor.getMainModule();
            }
        }
        return null;
    }

    protected Unit createUnit() {
        return new Unit();
    }
   
    public void visitRemainingModulePhase() {
        if ( moduleVisitor != null ) {
            moduleVisitor.setPhase(ModuleVisitor.Phase.REMAINING);
            compilationUnit.visit(moduleVisitor);
            moduleVisitor = null;
        }
    }
   
    public boolean isFullyTyped() {
        return fullyTyped;
    }

    public void setFullyTyped(boolean fullyTyped) {
        this.fullyTyped = fullyTyped;
    }
   
    public boolean isFlowAnalyzed() {
        return flowAnalyzed;
    }

    public void setFlowAnalyzed(boolean flowAnalyzed) {
        this.flowAnalyzed = flowAnalyzed;
    }

    public boolean isTreeValidated() {
        return treeValidated;
    }

    public void setTreeValidated(boolean treeValidated) {
        this.treeValidated = treeValidated;
    }

    public boolean isDeclarationsScanned() {
        return declarationsScanned;
    }

    public void setDeclarationsScanned(boolean declarationsScanned) {
        this.declarationsScanned = declarationsScanned;
    }

    public boolean isTypeDeclarationsScanned() {
        return typeDeclarationsScanned;
    }

    public void setTypeDeclarationsScanned(boolean typeDeclarationsScanned) {
        this.typeDeclarationsScanned = typeDeclarationsScanned;
    }

    public boolean isRefinementValidated() {
        return refinementValidated;
    }

    public void setRefinementValidated(boolean refinementValidated) {
        this.refinementValidated = refinementValidated;
    }

    public void validateTree() {
        //System.out.println("Validating tree for " + fileName);
        if (!treeValidated) {
            String fn = unit.getRelativePath();
            for (int i=0; i<fn.length(); i = fn.offsetByCodePoints(i, 1)) {
                int cp = fn.codePointAt(i);
                if (cp>127) {
                    compilationUnit.addUsageWarning(Warning.filenameNonAscii,
                            "source file name has non-ASCII characters: " + fn);
                }
            }
            for (Unit u: unit.getPackage().getUnits()) {
                if (!u.equals(unit) &&
                        u.getFilename().equalsIgnoreCase(unit.getFilename())) {
                    if (u.getFilename().equals(unit.getFilename())) {
                        String errorMessage = "identical source files: " +
                                unit.getFullPath() + " and " + u.getFullPath();
                        if (u.getFilename().equals(ModuleManager.MODULE_FILE) ||
                                u.getFilename().equals(ModuleManager.PACKAGE_FILE)) {
                            errorMessage += " (a module/package descriptor should be defined only once, even in case of multiple source directories)";
                        }
                        compilationUnit.addError(errorMessage);                       
                    } else {
                        compilationUnit.addUsageWarning(Warning.filenameCaselessCollision,
                                "source file names differ only by case: " +
                                        unit.getFullPath() + " and " + u.getFullPath());
                    }
                }
            }
            compilationUnit.visit(new Validator());
            compilationUnit.visit(new Visitor() {
                @Override
                public void visit(ModuleDescriptor that) {
                    super.visit(that);
                    ImportPath importPath = that.getImportPath();
                    if (importPath != null) {
                        String moduleName = Util.formatPath(importPath.getIdentifiers());
                        ModuleManager moduleManager = moduleManagerRef.get();
                        if (moduleManager != null) {
                            for (Module otherModule : moduleManager.getCompiledModules()) {
                                String otherModuleName = otherModule.getNameAsString();
                                if (moduleName.startsWith(otherModuleName + ".") ||
                                        otherModuleName.startsWith(moduleName + ".")) {
                                    StringBuilder error = new StringBuilder("Found two modules within the same hierarchy: '");
                                    error.append( otherModule.getNameAsString() )
                                    .append( "' and '" )
                                    .append( moduleName )
                                    .append("'");
                                    that.addError(error.toString());
                                }
                            }
                        }
                    }
                }
            });
            treeValidated = true;
        }
    }

    public void scanDeclarations() {
        Boolean enabled = ProducedTypeCache.setEnabled(false);
        try {
            if (!declarationsScanned) {
                processLiterals();
                scanningDeclarations = true;
                //System.out.println("Scan declarations for " + fileName);
                UnitFactory unitFactory = new UnitFactory() {
                    @Override
                    public Unit createUnit() {
                        return PhasedUnit.this.createUnit();
                    }
                };
                DeclarationVisitor dv = new DeclarationVisitor(pkg, fileName,
                        unitFile.getPath(), pathRelativeToSrcDir, unitFactory);
                compilationUnit.visit(dv);
                unit = dv.getCompilationUnit();

                LocalDeclarationVisitor ldv = new LocalDeclarationVisitor();
                compilationUnit.visit(ldv);

                declarationsScanned = true;
                scanningDeclarations = false;
            }
        }
        finally {
            ProducedTypeCache.setEnabled(enabled);
        }
    }

  private void processLiterals() {
    if (!literalsProcessed) {
      compilationUnit.visit(new LiteralVisitor());
      literalsProcessed = true;
    }
  }

    public void scanTypeDeclarations() {
        Boolean enabled = ProducedTypeCache.setEnabled(false);
        try {
            if (!typeDeclarationsScanned) {
                //System.out.println("Scan type declarations for " + fileName);
                compilationUnit.visit(new DefaultTypeArgVisitor());
                compilationUnit.visit(new SupertypeVisitor(false)); //TODO: move to a new phase!
                compilationUnit.visit(new TypeVisitor());
                typeDeclarationsScanned = true;
            }
        }
        finally {
            ProducedTypeCache.setEnabled(enabled);
        }
    }

    public synchronized void validateRefinement() {
        Boolean enabled = ProducedTypeCache.setEnabled(false);
        try {
            if (!refinementValidated) {
                ProducedType.depth.set(0);
                //System.out.println("Validate member refinement for " + fileName);
                compilationUnit.visit(new AliasVisitor());
                compilationUnit.visit(new SupertypeVisitor(true)); //TODO: move to a new phase!
                compilationUnit.visit(new InheritanceVisitor());
                compilationUnit.visit(new RefinementVisitor());
                refinementValidated = true;
            }
        }
        finally {
            ProducedTypeCache.setEnabled(enabled);
        }
    }

    public synchronized void analyseTypes() {
        if (!fullyTyped) {
            ProducedType.depth.set(-100);
            //System.out.println("Run analysis phase for " + fileName);
            compilationUnit.visit(new ExpressionVisitor());
            compilationUnit.visit(new VisibilityVisitor());
            compilationUnit.visit(new AnnotationVisitor());
            compilationUnit.visit(new TypeArgumentVisitor());
            fullyTyped = true;
        }
    }
   
    public synchronized void analyseFlow() {
        if (!flowAnalyzed) {
            compilationUnit.visit(new TypeHierarchyVisitor());
            //System.out.println("Validate control flow for " + fileName);
            compilationUnit.visit(new ControlFlowVisitor());
            //System.out.println("Validate self references for " + fileName);
            //System.out.println("Validate specification for " + fileName);
            for (Declaration d: unit.getDeclarations()) {
                compilationUnit.visit(new SpecificationVisitor(d));
                if (d instanceof TypeDeclaration) {
                    compilationUnit.visit(new SelfReferenceVisitor((TypeDeclaration) d));
                }
            }
            flowAnalyzed = true;
        }
    }

    public synchronized void analyseUsage() {
        if (! usageAnalyzed) {
            ReferenceCounter rc = new ReferenceCounter();
            compilationUnit.visit(rc);
            compilationUnit.visit(new UsageVisitor(rc));
            compilationUnit.visit(new DeprecationVisitor());
            compilationUnit.visit(new WarningSuppressionVisitor<Warning>(Warning.class, suppressedWarnings));
            usageAnalyzed = true;
        }
    }

    public void generateStatistics(StatisticsVisitor statsVisitor) {
        compilationUnit.visit(statsVisitor);
    }
   
    public void runAssertions(AssertionVisitor av) {
        //System.out.println("Running assertions for " + fileName);
        compilationUnit.visit(av);
    }

    public void display() {
        System.out.println("Displaying " + fileName);
        compilationUnit.visit(new PrintVisitor());
    }
   
    public Package getPackage() {
        return pkg;
    }
   
    public Unit getUnit() {
        return unit;
    }

    public List<Declaration> getDeclarations() {
        if (!declarationsScanned) {
            scanDeclarations();
        }
        return unit.getDeclarations();
    }

    public String getPathRelativeToSrcDir() {
        return pathRelativeToSrcDir;
    }

    public VirtualFile getUnitFile() {
        return unitFile;
    }

    @Override
    public String toString() {
        final StringBuilder sb = new StringBuilder();
        sb.append("PhasedUnit");
        sb.append("{filename=").append(fileName);
        sb.append(", compilationUnit=").append(unit);
        sb.append(", pkg=").append(pkg);
        sb.append('}');
        return sb.toString();
    }

    public Tree.CompilationUnit getCompilationUnit() {
        return compilationUnit;
    }

    public List<CommonToken> getTokens() {
        return tokens;
    }

    public boolean isScanningDeclarations() {
        return scanningDeclarations;
    }

    public void setSuppressedWarnings(EnumSet<Warning> suppressedWarnings) {
        this.suppressedWarnings = suppressedWarnings;
    }
}
TOP

Related Classes of com.redhat.ceylon.compiler.typechecker.context.PhasedUnit

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.