/* * * 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.flex.compiler.internal.as.codegen; import java.util.ArrayList; import java.util.Collection; import org.apache.flex.compiler.problems.BURMPatternMatchFailureProblem; import org.apache.flex.compiler.problems.CodegenInternalProblem; import org.apache.flex.compiler.problems.ICompilerProblem; import org.apache.flex.compiler.tree.as.IASNode; import static org.apache.flex.compiler.tree.ASTNodeID.*; /** * The UnknownTreeHandler-matches an annotated * AST against a set of prototype problems; the most * successful matches are recorded as problems. */ class UnknownTreeHandler { Collection<ICompilerProblem> problems; /** * Construct an Analyzer. * @param problems - the caller's collection of problems. */ public UnknownTreeHandler(Collection<ICompilerProblem> problems ) { this.problems = problems; } /** * Analyze an annotated AST against the preset collection * of prototype problems. */ public void analyze(CmcEmitter.JBurgAnnotation root) { Collection <UnknownTreeFinding> findings = exploreSubtrees(root); // If the error presents with a completely unknown pattern, // issue a last-gasp diagnosis. if ( findings.isEmpty() ) { this.problems.add(new BURMPatternMatchFailureProblem(root.getNode())); } else { for ( UnknownTreeFinding finding: findings ) { this.problems.add(finding.problem); } } } /** * Traverse the failed AST and attempt to find an * error pattern that yields a diagnostic. * @param subtree_root - the root of this subtree. * Note that this routine recursively descends through the subtree. */ Collection <UnknownTreeFinding> exploreSubtrees(CmcEmitter.JBurgAnnotation subtree_root) { Collection<UnknownTreeFinding> result = new ArrayList<UnknownTreeFinding>(); Collection <UnknownTreeFinding> provisional_findings = new ArrayList<UnknownTreeFinding>(); // Identify candidate matches. for ( UnknownTreeFinding match: findMatches(subtree_root) ) { if ( match.provisional ) provisional_findings.add(match); else result.add(match); } // Explore this node's subtrees; if there is no definite // finding at this level, then take all the subtree matches; // if there was, only take the definite matches from the subtree. boolean definite_finding_at_level = !result.isEmpty(); for ( int i = 0; i < subtree_root.getArity(); i++ ) { if ( !definite_finding_at_level ) { result.addAll(exploreSubtrees(subtree_root.getNthChild(i))); } else { for ( UnknownTreeFinding sub_finding: exploreSubtrees(subtree_root.getNthChild(i)) ) { if ( !sub_finding.provisional ) result.add(sub_finding); } } } // Use this level's provisional findings if nothing better has been found. if ( result.isEmpty() ) result = provisional_findings; return result; } /** * Find all the findings that apply to an annotated AST. * @param annotation - the annotated AST. */ ArrayList<UnknownTreeFinding> findMatches(CmcEmitter.JBurgAnnotation annotation) { IASNode node = annotation.getNode(); ArrayList<UnknownTreeFinding.Template> candidates = new ArrayList<UnknownTreeFinding.Template>(); ArrayList<UnknownTreeFinding> result = new ArrayList<UnknownTreeFinding>(); // Get the initial set of findings: all findings filed // under this node's ASTNodeID, and all findings filed // under "Unknown" which means "any" in this context. if ( UnknownTreeHandlerPatterns.allTemplates.containsKey(node.getNodeID()) ) candidates.addAll(UnknownTreeHandlerPatterns.allTemplates.get(node.getNodeID())); if ( UnknownTreeHandlerPatterns.allTemplates.containsKey(UnknownID) ) candidates.addAll(UnknownTreeHandlerPatterns.allTemplates.get(UnknownID) ); for ( UnknownTreeFinding.Template candidate: candidates ) { if ( candidate.matches(annotation) ) { try { result.add(candidate.createFinding(candidate.getInnermostMatchedNode(annotation))); } catch ( Exception ex ) { this.problems.add(new CodegenInternalProblem(node, ex)); } } } return result; } }